/* ==========================================================================
   VAMLAS — design system base
   Derived from: assets/vamlas-graafinen-ohjeistus/ohjeisto/VAMLAS-ohjeisto-202606.pdf (06.2026)
   Finnish brand terms are kept as-is in token names so they map 1:1 to the
   guideline. Translations are noted in comments.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Typeface — Atkinson Hyperlegible Next
   Chosen by the brand for readability for people with low vision; it is the
   primary face "aina kun teknisesti onnistuu" (whenever technically possible).
   Fallbacks per guideline: Aptos, then Arial.
   TTF is what the brand kit ships. Convert to .woff2 for production
   (~70% smaller) and add it as the first src entry.
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  src: url('../fonts/AtkinsonHyperlegibleNext-VariableFont_wght.ttf') format('truetype-variations');
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Atkinson Hyperlegible Next';
  src: url('../fonts/AtkinsonHyperlegibleNext-Italic-VariableFont_wght.ttf') format('truetype-variations');
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
}

/* --------------------------------------------------------------------------
   2. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* --- Pääväripaletti (primary palette) -----------------------------------
     The four logo colours plus tummansininen. Tint steps are the guideline's
     own 75/50/25/15% screens — not computed opacity, so they stay accurate
     against any background. */

  /* Sinivioletti (blue-violet) — PMS 7455. The primary brand colour. */
  --vamlas-sinivioletti: #48559d;
  --vamlas-sinivioletti-75: #7680b6;
  --vamlas-sinivioletti-50: #a3aace;
  --vamlas-sinivioletti-25: #d1d5e7;
  --vamlas-sinivioletti-15: #e4e6f0;

  /* Vaaleansininen (light blue) — PMS 291. Background only. */
  --vamlas-vaaleansininen: #aecaeb;
  --vamlas-vaaleansininen-75: #c2d7f0;
  --vamlas-vaaleansininen-50: #d7e4f5;
  --vamlas-vaaleansininen-25: #ebf2fa;
  --vamlas-vaaleansininen-15: #f3f7fc;

  /* Vaaleanpunainen (pink) — PMS 204. Background only. */
  --vamlas-vaaleanpunainen: #ff86c9;
  --vamlas-vaaleanpunainen-75: #ffa4d7;
  --vamlas-vaaleanpunainen-50: #ffc3e4;
  --vamlas-vaaleanpunainen-25: #ffe1f2;
  --vamlas-vaaleanpunainen-15: #ffedf7;

  /* Keltaoranssi (amber) — PMS 130. Background only. */
  --vamlas-keltaoranssi: #ffb500;
  --vamlas-keltaoranssi-75: #ffc840;
  --vamlas-keltaoranssi-50: #ffda80;
  --vamlas-keltaoranssi-25: #ffedbf;
  --vamlas-keltaoranssi-15: #fff4d9;

  /* Tummansininen (dark blue). Added to the palette for depth and for text
     on coloured surfaces — it is the highest-contrast brand colour. */
  --vamlas-tummansininen: #313a6b;

  /* --- Lisävärit (extra colours) -----------------------------------------
     Designed for infographics. All meet at least WCAG AA on white
     (measured: 4.63–8.66:1). Use for data series, not for chrome. */
  --vamlas-rubiininpunainen: #99225f; /* ruby      7.64:1 on white */
  --vamlas-keltaruskea: #91701e;      /* ochre     4.63:1 on white */
  --vamlas-turkoosi: #127b7e;         /* teal      5.05:1 on white */
  --vamlas-violetti: #6e02bf;         /* violet    8.66:1 on white */
  --vamlas-vihrea: #075c23;           /* green     8.19:1 on white */

  /* --- Liukuväri (gradient) ----------------------------------------------
     The identity's signature blend, taken from the taimi element: light blue
     and blue-violet through amber into pink, running on a diagonal.
     Use large and cropped — only part of it should ever be visible. */
  --vamlas-liukuvari: linear-gradient(
    135deg,
    var(--vamlas-vaaleansininen) 0%,
    var(--vamlas-sinivioletti) 30%,
    var(--vamlas-keltaoranssi) 55%,
    var(--vamlas-vaaleanpunainen) 80%,
    var(--vamlas-sinivioletti) 100%
  );

  /* --- Semantic colour ----------------------------------------------------
     Prefer these in components. Contrast ratios verified against the surface
     each one is paired with. */
  --color-bg: #ffffff;
  --color-bg-subtle: var(--vamlas-vaaleansininen-25);   /* #ebf2fa */
  --color-bg-dark: var(--vamlas-tummansininen);

  --color-text: var(--vamlas-tummansininen);            /* 10.78:1 on white */
  --color-text-muted: var(--vamlas-sinivioletti);       /*  6.86:1 on white */
  --color-text-on-dark: #ffffff;                        /* 10.78:1 on dark blue */

  /* On any saturated brand background (light blue, pink, amber), sinivioletti
     drops below 4.5:1 — light blue is only 4.07:1. Tummansininen clears AA on
     all three (6.39 / 4.88 / 6.09:1), so it is the text colour on colour. */
  --color-text-on-brand: var(--vamlas-tummansininen);

  --color-accent: var(--vamlas-sinivioletti);
  --color-accent-strong: var(--vamlas-tummansininen);
  --color-highlight: var(--vamlas-keltaoranssi);
  --color-border: var(--vamlas-sinivioletti-25);
  --color-border-strong: var(--vamlas-sinivioletti-50);
  --color-focus: var(--vamlas-tummansininen);

  /* --- Typography ---------------------------------------------------------
     Fluid scale. Every step interpolates over the same viewport range,
     320px → 1344px, so the whole scale moves together.

     To recompute a step from a target min/max (in rem):
       vw coefficient = (max - min) / 0.64
       rem offset     = min - 0.2 × coefficient

     The heading steps (lg and up) run ~1.15 apart on mobile opening to ~1.25
     on desktop. Body and below (md, base, sm, xs) are set for readability
     rather than by ratio and are deliberately left out of that progression. */
  --font-sans: 'Atkinson Hyperlegible Next', 'Aptos', Arial, system-ui, sans-serif;

  --text-xs: clamp(0.78rem, 0.76rem + 0.10vw, 0.83rem);
  --text-sm: clamp(0.88rem, 0.86rem + 0.09vw, 0.94rem);
  --text-base: clamp(1rem, 0.96rem + 0.20vw, 1.13rem);
  --text-md: clamp(1.19rem, 1.11rem + 0.38vw, 1.44rem);
  --text-lg: clamp(1.34rem, 1.23rem + 0.56vw, 1.70rem);
  --text-xl: clamp(1.52rem, 1.35rem + 0.83vw, 2.05rem);
  --text-2xl: clamp(1.72rem, 1.48rem + 1.22vw, 2.50rem);
  --text-3xl: clamp(2.12rem, 1.69rem + 2.16vw, 3.50rem);

  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800;

  --leading-tight: 1.15;
  --leading-snug: 1.3;
  --leading-normal: 1.6;   /* body — generous for readability */
  --leading-loose: 1.75;

  --tracking-tight: -0.01em;
  --tracking-normal: 0;
  --tracking-wide: 0.06em;

  /* Cap line length for readability — a core accessibility concern here. */
  --measure: 68ch;
  --measure-narrow: 46ch;

  /* --- Space --------------------------------------------------------------
     Scale rooted in the logo's X unit (the height of the wordmark's text
     line), which the guideline uses for clear space: 1X around the logo,
     2X around the bare symbol. */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-sm: 1rem;
  --space-md: 1.5rem;
  --space-lg: 2.5rem;
  --space-xl: 4rem;
  --space-2xl: 6rem;
  --space-3xl: 9rem;

  /* --- Layout ------------------------------------------------------------- */
  --width-full: 88rem;
  --width-large: 77rem;
  --width-medium: 64rem;
  --width-content: 54rem;
  --width-narrow: 42rem;
  --gutter: clamp(var(--space-sm), 4vw, var(--space-xl));

  /* --- Radii ---------------------------------------------------------------
     The identity is built from organic leaf shapes, so corners are soft. The
     leaf silhouette itself is not approximated here — see .leaf-overlay, which
     uses the brand kit's real SVG. */
  --radius-sm: 0.25rem;
  --radius-md: 0.5rem;
  --radius-lg: 1rem;
  --radius-pill: 100vmax;

  /* --- Elevation -----------------------------------------------------------
     Tinted with the brand blue rather than neutral black so shadows sit in
     the same colour world as everything else. */
  --shadow-sm: 0 1px 2px rgb(49 58 107 / 0.08);
  --shadow-md: 0 4px 12px rgb(49 58 107 / 0.10);
  --shadow-lg: 0 12px 32px rgb(49 58 107 / 0.14);

  /* --- Motion -------------------------------------------------------------- */
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
  --duration-fast: 120ms;
  --duration: 200ms;
}

/* --------------------------------------------------------------------------
   3. Base
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background-color: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  font-weight: var(--weight-regular);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* --------------------------------------------------------------------------
   4. Typography
   Headings are semibold blue-violet in the guideline's own applications.
   Sentence case is the default; uppercase is reserved for the .eyebrow label.
   -------------------------------------------------------------------------- */
h1, h2, h3, h4, h5, h6 {
  margin: 0 0 var(--space-sm);
  color: var(--color-accent);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  /*text-wrap: balance;*/
}

h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-2xl); }
h3 { font-size: var(--text-xl); }
h4 { font-size: var(--text-lg); }
h5 { font-size: var(--text-md); }
h6 {
  font-size: var(--text-base);
  font-weight: var(--weight-bold);
}

p, ul, ol, dl, blockquote, figure, table, pre {
  margin: 0 0 var(--space-sm);
}

p, li {
  /*max-width: var(--measure);*/
  text-wrap: auto;
}

.lead {
  font-size: var(--text-md);
  line-height: var(--leading-normal);
  margin-bottom: var(--space-md);
}

.eyebrow {
  display: block;
  margin-bottom: var(--space-2xs);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

small { font-size: var(--text-sm); }

strong, b { font-weight: var(--weight-bold); }

blockquote {
  border-left: 4px solid var(--color-highlight);
  padding-left: var(--space-md);
  font-size: var(--text-md);
  line-height: var(--leading-normal);
}

.quote {
  margin: var(--space-lg) 0;
  .quote-author {
    padding-left: var(--space-md);
    margin: 0;
  }
}

hr {
  height: 1px;
  margin: var(--space-lg) 0;
  border: 0;
  background-color: var(--color-border);
}

/* Links stay underlined — removing the underline would leave colour as the
   only signal, which fails WCAG 1.4.1.

   Do not set `display: inline-block` here. An inline-block takes its baseline
   from its LAST line box, so a link that wraps onto two lines inside an <li>
   drags the whole box up and the list marker ends up level with the second
   line. Links must stay inline so they flow and wrap like the text around
   them. Anything needing a box of its own sets display on itself — .button
   (inline-flex), .logo (block), .skip-link (absolute, so blockified). */
a {
  color: var(--color-accent);
  text-decoration: underline;
  text-decoration-thickness: 0.08em;
  text-underline-offset: 0.18em;
  transition: color var(--duration-fast) var(--ease);
}

a:hover {
  color: var(--color-accent-strong);
  text-decoration-thickness: 0.14em;
}

/* External-link icon.

   Masked rather than used as a background-image, with background-color set to
   currentColor, so the icon is always exactly the colour of the link text it
   follows — on dark surfaces, on brand surfaces, inside any button variant,
   and on hover — from a single asset.

   The SVG carries fill="currentColor", but that has no effect when the file is
   loaded as a background-image: an externally referenced SVG cannot inherit
   CSS from the host document. That is why a separate white copy was needed
   before; masking removes the need for it. */
a.external::after,
a[target="_blank"]::after {
  content: '';
  display: inline-block;
  /* em, not px, so the icon tracks the fluid type scale and stays in
     proportion wherever it sits — body copy, a heading, or a button. */
  width: 1em;
  height: 1em;
  margin-left: 0.3rem;
  background-color: currentColor;
  -webkit-mask-image: url('../images/box-arrow-up-right.svg');
  mask-image: url('../images/box-arrow-up-right.svg');
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
}

a.external.button::after {
  margin-left: 0.1rem;
}

img, picture, svg, video {
  display: block;
  max-width: 100%;
  height: auto;
}

.text-center {
  text-align: center;
}
.slogan {
  font-size: var(--text-lg);
  margin-bottom: var(--space-lg);
}
.item-heading {
  font-size: var(--text-md);
}
.no-margin {
  margin-bottom: 0;
}
.item .item-heading + time {
  display: block;
  margin: var(--space-xs) 0 0 0;
  font-size: var(--text-sm);
}
.list-item-heading {
  font-size: var(--text-base);
}
.page-title {
  text-wrap: auto;
  margin-bottom: 0;
}
.page-title + time {
  display: block;
  margin-bottom: var(--space-xl);
}
time + img {
  margin-bottom: var(--space-xl);
  border-radius: var(--radius-md);
}

/* --------------------------------------------------------------------------
   5. Focus
   Two-tone ring so it stays visible on both light and dark surfaces.
   -------------------------------------------------------------------------- */
:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
  box-shadow: 0 0 0 6px var(--vamlas-keltaoranssi-50);
}

.surface--dark :focus-visible {
  outline-color: #ffffff;
}

.skip-link {
  position: absolute;
  top: var(--space-2xs);
  left: var(--space-2xs);
  z-index: 100;
  padding: var(--space-2xs) var(--space-sm);
  border-radius: var(--radius-md);
  background-color: var(--vamlas-rubiininpunainen);
  color: var(--color-text-on-dark);
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* --------------------------------------------------------------------------
   6. Forms
   -------------------------------------------------------------------------- */
label {
  display: block;
  margin-bottom: var(--space-3xs);
  font-weight: var(--weight-semibold);
}

input, textarea, select {
  width: 100%;
  padding: var(--space-2xs) var(--space-xs);
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background-color: var(--color-bg);
  color: var(--color-text);
  font: inherit;
  font-size: var(--text-base);
}

input:hover, textarea:hover, select:hover {
  border-color: var(--color-accent);
}

::placeholder {
  color: var(--vamlas-sinivioletti-75);
  opacity: 1;
}

/* --------------------------------------------------------------------------
   7. Components
   -------------------------------------------------------------------------- */

/* Buttons — 44px minimum target per WCAG 2.5.8. */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2xs);
  min-height: 2.75rem;
  padding: var(--space-2xs) var(--space-md);
  border: 2px solid transparent;
  border-radius: var(--radius-pill);
  background-color: var(--color-accent);
  color: var(--color-text-on-dark);
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color var(--duration) var(--ease),
    border-color var(--duration) var(--ease),
    color var(--duration) var(--ease);
}

.button:hover {
  background-color: var(--color-accent-strong);
  color: var(--color-text-on-dark);
}

.button--secondary {
  border-color: var(--color-accent);
  background-color: transparent;
  color: var(--color-accent);
}

.button--secondary:hover {
  border-color: var(--color-accent-strong);
  background-color: var(--vamlas-sinivioletti-15);
  color: var(--color-accent-strong);
}

.surface--dark .button--secondary {
  border-color: var(--color-wh);
}
.surface--dark .button--secondary:hover {
  color: var(--vamlas-tummansininen);
}

/* Amber needs dark text — it is only 1.77:1 against white. */
.button--highlight {
  background-color: var(--color-highlight);
  color: var(--color-text-on-brand);
}

.button--highlight:hover {
  background-color: var(--vamlas-keltaoranssi-75);
  color: var(--color-text-on-brand);
}

.button:disabled,
.button[aria-disabled='true'] {
  opacity: 0.5;
  cursor: not-allowed;
}

.container--content .card {
  figure {
    img {
      border-radius: var(--radius-md);
      margin: 0;
    }
  }
}

.badge {
  display: inline-block;
  padding: var(--space-3xs) var(--space-xs);
  border-radius: var(--radius-pill);
  background-color: var(--vamlas-vaaleansininen-50);
  color: var(--color-text-on-brand);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

/* Lehtikehys — the leaf as a colour panel laid over a photo.
   Guideline p. 13, lower two examples: "käyttää lehteä tekstin alla
   väripintana ja sijoittaa se sitten kuvan päälle" — the leaf is a flat brand
   colour sitting on top of the image, and the caption sits inside it.

   The shape is the brand kit's own SVG used as a mask over a solid colour, so
   the colour stays tokenised and recolourable rather than baked into the file.

   Per the guideline the leaf is scaled large and always cropped by the frame —
   never shown whole — so --leaf-size defaults well past 100% and the container
   clips it.

   The text deliberately does NOT live inside the masked element. Masking a
   text container silently clips any text that outgrows the shape, which would
   break the moment someone raises their font size — unacceptable on a site
   built around legibility. The shape is a decorative pseudo-element and the
   caption is a normal, unclipped box stacked above it. */
.leaf-overlay {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  display: grid;
}

.leaf-overlay > img,
.leaf-overlay > picture {
  grid-area: 1 / 1;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* The leaf itself: a brand-coloured shape punched out by the SVG mask. */
.leaf-overlay::after {
  content: '';
  position: absolute;
  z-index: 1;
  pointer-events: none;
  inline-size: var(--leaf-size, 100%);
  aspect-ratio: 328.4 / 558.8;
  inset-block-end: var(--leaf-bottom, -5%);
  inset-inline-start: var(--leaf-start, 5%);
  background-color: var(--leaf-color, var(--vamlas-vaaleansininen));
  -webkit-mask-image: var(--leaf-shape, url('../images/lehtikehys-01.svg'));
  mask-image: var(--leaf-shape, url('../images/lehtikehys-01.svg'));
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
  -webkit-mask-size: contain;
  mask-size: contain;
  transform: rotate(var(--leaf-rotate, 0deg));
}

/* The mirrored half of the pair — the kit ships both. */
.leaf-overlay--mirrored {
  --leaf-shape: url('../images/lehtikehys-02.svg');
}

/* Caption, sitting above the leaf and never clipped by it. */
.leaf-overlay__content {
  /* Same grid cell as the image, so it stacks over it. Without this it lands
     in row 2 and the text sits below the picture instead of on the panel. */
  grid-area: 1 / 1;
  position: relative;
  z-index: 2;
  align-self: end;
  padding: var(--space-md);
  color: var(--color-text-on-brand);
}

.leaf-overlay__content :is(h1, h2, h3, h4, h5, h6, p) {
  color: inherit;
}

/* Taimi — the sprout element used as a large decorative background.
   Guideline pp. 8–12: it is always scaled large, always cropped by the edge of
   the layout, rotated only in 45° steps, and never shown whole. The open
   variant (taimi avoin) has one leaf replaced by empty space, which is what
   makes it usable behind text.

   This has to be a pseudo-element rather than `background-image`, because a
   background cannot be rotated — `transform` does not apply to it — and
   `background-size` cannot push the artwork past the element's own box.

   Purely decorative, so a pseudo-element is also the correct semantics: there
   is nothing for a screen reader to announce and no alt text to invent.

   Tune per section with the custom properties below. Negative offsets are what
   push the artwork off the edge; --taimi-rotate must stay on a 45° step. */
.taimi {
  position: relative;
  overflow: hidden;    /* the crop the guideline requires */
  isolation: isolate;  /* keeps the negative z-index inside this section */
}

.taimi::after {
  content: '';
  position: absolute;
  z-index: -1;
  pointer-events: none;
  inline-size: var(--taimi-size, min(60rem, 110vw));
  aspect-ratio: 1800 / 1609;
  inset-block-start: var(--taimi-top, -8rem);
  inset-inline-end: var(--taimi-end, -30rem);
  background: var(--taimi-image, url('../images/taimi-avoin.webp'))
    no-repeat center / contain;
  transform: rotate(var(--taimi-rotate, 315deg));
}

/* Surfaces — the full-bleed horizontal bands a page is made of.
   Vertical rhythm lives here and nowhere else: .container handles width only,
   .stack handles the gaps between elements inside. Keeping those three jobs
   separate is what keeps section spacing predictable. Every top-level band
   (header, main sections, footer) should carry .surface. */
.surface {
  padding-block: var(--section-space, var(--space-xl));
}

/* Size modifiers, so a band can deviate without leaving the scale. */
.surface--tight { --section-space: var(--space-md); }
.surface--loose { --section-space: var(--space-2xl); }
.surface--flush { --section-space: 0; }

/* Two neighbouring bands that share a background have an invisible boundary,
   so their two sets of padding read as one doubled gap. Collapse the second
   one's top padding.

   Neighbours with *different* backgrounds deliberately keep both: the colour
   change is visible, and each band needs its own breathing room against it.

   Matching is on background modifiers only, so the size modifiers above can
   be combined freely without breaking the collapse.

   The second selector of each pair reaches through <main>. <main> is a plain
   wrapper that adds no spacing of its own, so a band inside it is visually
   adjacent to the header — but a sibling combinator can't see across the
   element boundary, and that header/hero seam is the most common place for
   the doubled gap to show up. */
.surface--subtle + .surface--subtle,
.surface--subtle + main > .surface--subtle:first-child,
.surface--dark + .surface--dark,
.surface--dark + main > .surface--dark:first-child,
.surface--brand + .surface--brand,
.surface--brand + main > .surface--brand:first-child,
.surface:not(.surface--subtle, .surface--dark, .surface--brand, .surface--gradient)
  + .surface:not(.surface--subtle, .surface--dark, .surface--brand, .surface--gradient),
.surface:not(.surface--subtle, .surface--dark, .surface--brand, .surface--gradient)
  + main > .surface:not(.surface--subtle, .surface--dark, .surface--brand, .surface--gradient):first-child {
  padding-block-start: 0;
}

.surface--subtle {
  background-color: var(--color-bg-subtle);
}

.surface--dark {
  background-color: var(--color-bg-dark);
  color: var(--color-text-on-dark);
}

.surface--dark :is(h1, h2, h3, h4, h5, h6, a, .lead, .eyebrow) {
  color: var(--color-text-on-dark);
}

.surface--brand {
  background-color: var(--vamlas-vaaleansininen);
  color: var(--color-text-on-brand);
}

.surface--brand :is(h1, h2, h3, h4, h5, h6, a, .lead, .eyebrow) {
  color: var(--color-text-on-brand);
}

/* The gradient as a large surface — for use with a one-colour logo on top,
   per the "liukuväri isona pintana" page. Scaled well past the container so
   only part of the blend shows, as the guideline requires. */
.surface--gradient {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: var(--color-text-on-brand);
}

.surface--gradient::before {
  content: '';
  position: absolute;
  inset: -50%;
  z-index: -1;
  background: var(--vamlas-liukuvari);
}

/* --------------------------------------------------------------------------
   8. Layout utilities
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  max-width: var(--width-full);
  margin-inline: auto;
  padding-inline: var(--gutter);
  ul, ol {
    padding: 0 0 0 var(--space-sm);
  }
}
.container--content {
  figure img {
    margin: 0 auto var(--space-xl);
  }
}
.container--large {
  max-width: var(--width-large);
}
.container--medium { max-width: var(--width-medium); }
.container--content {
  max-width: var(--width-content);
}
.container--narrow { max-width: var(--width-narrow); }
.container--title {
  h1 {
    margin-bottom: var(--space-md);
  }
}
.text-left {
  margin-inline: initial;
}

/* Owl stack — consistent vertical rhythm without margin bookkeeping. */
.stack > * + * {
  margin-block-start: var(--flow, var(--space-sm));
}

.stack--lg { --flow: var(--space-lg); }
.stack--xl { --flow: var(--space-xl); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs);
  align-items: center;
}

.visually-hidden:not(:focus):not(:active) {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.grid {
  display: grid;
  grid-gap: var(--space-xl);
  @media screen and (min-width: 768px) {
    grid-template-columns: repeat(12, 1fr);
  }
}
.grid-2 {
  @media screen and (min-width: 768px) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.grid-3 {
  @media screen and (min-width: 768px) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
.grid-4 {
  @media screen and (min-width: 768px) {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}
.grid-twothird {
  @media screen and (min-width: 768px) {
    grid-template-columns: 1fr 2fr;
  }
  &.reverse {
    @media screen and (min-width: 768px) {
      grid-template-columns: 2fr 1fr;
    }
  }
}
.column {
  grid-column: span var(--span);
}
section {
  padding-block: var(--space-xl);
}
footer {
  padding-block: var(--space-xl);
}
.list-item {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid var(--vamlas-vaaleansininen);
  padding: var(--space-md) 0;
  .list-item-heading {
    margin: 0;
  }
}
.item {
  position: relative;
  img {
    border-radius: var(--radius-md);
  }
  time {
    display: block;
    font-size: var(--text-base);
    font-style: italic;
  }
}
.grid-more-cta {
  margin: var(--space-md) 0 0 0;
}

/* Card variants, set per collection by the Kokoelma listatyyli field.
   All three keep the cover image; only the text below it differs. */

/* The "when / where / how much" card. A definition list because these are
   label/value pairs, not prose. */
.item.item--details .item-details {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-3xs) var(--space-xs);
  font-size: var(--text-base);

  dt {
    font-weight: var(--weight-semibold);
  }

  dd {
    margin: 0;
  }

  /* .item time is italic to set the publish date apart from the body. Inside
     the details list it sits alongside plain values, so it reads as one of
     them rather than as an aside. */
  time {
    display: inline;
    font-size: inherit;
    font-style: normal;
    margin-bottom: 0;
  }
}
.item-heading a {
  display: block;
  &:after {
    content: '';
    position: absolute;
    inset: 0;
  }
}
.page-img {
  margin: 0;
  img {
    mask-image: url('../images/lehtikehys-03.svg');
    mask-repeat: no-repeat;
    mask-size: contain;
  }
}

/* --------------------------------------------------------------------------
   Prose — a blocks column whose figures break out of the text column and sit
   in the side margin, magazine style.

   The column is --width-content (54rem) centred in the viewport, so the free
   margin either side is (viewport - 54rem) / 2. Below about 76rem there isn't
   enough of it to hold a figure, so figures stay full width in the flow and
   only break out above that.

   Float rather than grid: the blocks arrive as a flat sequence from Kirby, so
   there are no rows to place a figure into. A float is the one mechanism that
   lets text run alongside an element that came before it in source order.

   Tune per page with --figure-width and --figure-outset. --figure-outset is
   how far past the column edge the image reaches; keep it smaller than the
   available margin at your breakpoint or the image will touch the viewport.
   -------------------------------------------------------------------------- */
.prose {
  display: flow-root;   /* contains the floats so they can't escape the band */

  /* Defined unconditionally, not inside the media query below. A custom
     property that only exists at some widths makes any rule using it collapse
     to `unset` everywhere else, which is silent and hard to spot. */
  --figure-width: 20rem;
  --figure-outset: 8rem;
}

.prose > figure {
  margin-block: var(--space-md);
}

.prose > figure img {
  inline-size: 100%;
  border-radius: var(--radius-md);
}

.prose figcaption {
  margin-block-start: var(--space-2xs);
  color: var(--color-text-muted);
  font-size: var(--text-base);
  line-height: var(--leading-snug);
  font-style: italic;
}

/* 70rem (1120px) is where the margin becomes wide enough to hold the outset:
   (70rem - 54rem) / 2 = 8rem of free space each side, plus the container's own
   gutter. Raise --figure-outset and this breakpoint has to rise with it. */
@media (min-width: 70rem) {
  /* Physical left/right rather than inline-start/end: `float` only accepts the
     logical keywords in fairly recent browsers, and this layout is LTR-only.
     The margins stay logical — those are universally supported. */
  /* Side is chosen per block in the Panel (the image block's Asettelu field),
     which the snippet emits as data-align. Anything else — including
     data-align="full" — stays in the flow at column width. */
  .prose > figure:is([data-align='right'], [data-align='left']) {
    inline-size: var(--figure-width);
    margin-block-start: var(--space-3xs);
  }

  .prose > figure[data-align='right'] {
    float: right;
    margin-inline-start: var(--space-lg);
    margin-inline-end: calc(-1 * var(--figure-outset));
  }

  .prose > figure[data-align='left'] {
    float: left;
    margin-inline-start: calc(-1 * var(--figure-outset));
    margin-inline-end: var(--space-lg);
  }

  /* A heading starts a fresh band instead of sitting beside a figure. */
  .prose > :is(h2, h3) {
    clear: both;
  }
}

/* --------------------------------------------------------------------------
   Video embeds

   The facade shown before a third-party video is loaded. Text sits over a
   thumbnail, so a scrim carries the contrast rather than trusting the image —
   brand colours alone cannot guarantee a ratio over arbitrary photography.
   -------------------------------------------------------------------------- */
.video-embed {
  margin-block: var(--space-md);

  iframe {
    display: block;
    inline-size: 100%;
    aspect-ratio: 16 / 9;
    border: 0;
    border-radius: var(--radius-md);
  }

  figcaption {
    margin-block-start: var(--space-2xs);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
  }
}

.video-embed__facade {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-sm);
  aspect-ratio: 16 / 9;
  padding: var(--space-md);
  border-radius: var(--radius-md);
  text-align: center;

  /* The gradient is the fallback when no local thumbnail exists; the scrim
     above it keeps the text readable once a thumbnail is layered in by the
     inline background-image. */
  background-color: var(--vamlas-tummansininen);
  background-image: var(--vamlas-liukuvari);
  background-size: cover;
  background-position: center;
  position: relative;
  isolation: isolate;

  &::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    border-radius: inherit;
    background: rgb(49 58 107 / 0.72);
  }

  a {
    color: var(--color-text-on-dark);
  }
}

.video-embed__notice {
  max-inline-size: 34ch;
  margin: 0;
  color: var(--color-text-on-dark);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
}

/* --------------------------------------------------------------------------
   9. Motion & print
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

@media print {
  body { background: #fff; color: #000; }
  .surface--dark, .surface--gradient { background: none; color: #000; }
}

/* --------------------------------------------------------------------------
  Header
-------------------------------------------------------------------------- */

header.surface {
  padding-block: var(--space-lg);
}
/* Header row: logo, nav, call to action.

   Wide enough and all three sit on one line. Below that the nav takes a row of
   its own — flex-basis: 100% forces the break rather than leaving it to
   whatever happens to fit — and order swaps the CTA up beside the logo instead
   of letting it drop away with the nav. */
.top {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
  align-items: center;
  row-gap: var(--space-sm);
}

.logo    { order: 1; }
.top .menu { order: 2; }
.top-cta { order: 3; }

/* 83rem ≈ 1328px, where the three stop fitting side by side. */
@media (max-width: 83rem) {
  .top .menu {
    order: 3;
    flex-basis: 100%;
  }

  .top-cta {
    order: 2;
  }
}
.logo {
  display: block;
  flex-shrink: 0;
  width: 200px;
  max-width: 100%;
}
.logo img {
  width: 100%;
}
.menu {
  ul#top-menu {
    margin: 0;
    padding: 0;
    list-style-type: none;
    display: flex;
    flex-flow: column wrap;
    justify-content: center;
    align-items: center;
    @media screen and (min-width: 768px) {
      flex-flow: row wrap;
      justify-content: flex-start;
    }
    > li {
      margin: 0 var(--space-xs) 0;
      &:last-child {
        margin-right: 0;
      }
      &:first-child {
        margin-left: 0;
      }
    }
    a.open, a.active {
      color: var(--color-accent-strong);
      text-decoration-thickness: 0.14em;
    }
  }
  .sub-menu {
    background: var(--vamlas-sinivioletti);
    padding: var(--space-md);
    margin: 0;
    list-style-type: none;
    li + li {
      margin: var(--space-xs) 0 0;
    }
    a {
      color: #fff;
      display: block;
    }
  }
}
.breadcrumb,
.pagination {
  &.surface {
    padding-block: var(--space-md);
  }
}
.pagination {
  nav {
    display: flex;
    justify-content: space-between;
    span.pages {
      flex: 1 1 auto;
    }
    span.sep {
      display: inline-block;
      margin: 0 var(--space-3xs);
    }
  }
}
.breadcrumb {
  nav {
    ol {
      list-style-type: none;
      margin: 0;
      padding: 0;
      display: flex;
      flex-flow: row wrap;
      li:not(:last-child):after {
        display: inline-block;
        margin: 0 0.25rem;
        content: "/";
      }
    }
  }
}

/* --------------------------------------------------------------------------
  Home
-------------------------------------------------------------------------- */

/* The hero carries the taimi off the right edge. These four values are the
   whole composition — adjust them, not the .taimi rule itself. */
.home {
  --taimi-size: min(64rem, 115vw);
  --taimi-top: -12rem;
  --taimi-end: -32rem;
  --taimi-rotate: 135deg;
}

/* Below roughly 60rem the artwork starts crowding the text, so pull it
   further off the edge and shrink it. */
@media (max-width: 60rem) {
  .home {
    --taimi-size: min(34rem, 125vw);
    --taimi-top: -8rem;
    --taimi-end: -14rem;
  }
}
/* Featured box — guideline p. 13, the two lower examples ("teksti kehyksen
   sisällä"): a photo with a colour panel over it carrying the text.

   The panel is a rectangle with ONE curved edge, which is what the guideline
   actually shows — not a leaf silhouette. The lehtikehys mask was tried first
   and is the wrong tool here: a leaf is convex on both sides, so filling the
   left of the box solidly needs its whole left half pushed off-canvas, and at
   the scale that requires the visible arc flattens out. An elliptical
   border-radius gives the same single sweeping edge and stays controllable.

   Blue-violet text on the white panel measures 6.86:1. The panel is white
   rather than --color-bg-subtle because the hero section is itself
   surface--subtle, and a subtle panel there is invisible against it. */
.featured {
  --panel-color: var(--vamlas-vaaleansininen-25);
  position: relative;
  isolation: isolate;
  display: grid;
  min-height: 24rem;
  max-height: 35rem;
  border-radius: var(--radius-md);
  overflow: hidden;
}

.featured > img {
  grid-area: 1 / 1;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

.featured::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: var(--panel-color);

  /* Masked, not a background image: masking is alpha-based, so the artwork's
     own fill is ignored and the panel keeps --panel-color from the tokens.

     Default size is a stretch, NOT contain. The shapes are portrait (0.78) and
     near-square (1.19) while the box is ~2.25 wide, so contain scales them
     down to fit and leaves the panel floating clear of the edges — and because
     mask-position defaults to center, floating in the middle. A panel has to
     reach its edges, so it stretches.

     Both are overridable per instance if a given box needs different framing. */
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.featured__content {
  /* Absolutely positioned, NOT a grid item.

     As a grid item this inflated the single row: content taller than the
     container made the row taller than max-height, the container clipped to
     35rem, but centring still happened inside the oversized row — so the text
     sat below the visible area. max-height clips a grid container; it does not
     shrink its tracks. An absolutely positioned child is ignored for track
     sizing, so the row is driven by the image and the text centres inside the
     clamped box.

     Centring moves to justify-content on a column flexbox; `safe` keeps the
     start edge reachable if the text ever outgrows the box. */
  position: absolute;
  inset-block: 0;
  z-index: 2;

  display: flex;
  flex-direction: column;
  justify-content: center;
  justify-content: safe center;

  padding: var(--space-md);
  max-inline-size: 25ch;
  color: var(--color-accent);
  @media screen and (min-width: 768px) {
    padding: var(--space-lg);
    max-inline-size: 30ch;
  }
}

.featured__content :is(h2, h3, p) {
  color: inherit;
  margin: 0;
}

/* The whole box is the link target. */
.featured a {
  color: inherit;
  &:after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 3;
  }
}

/* Variant 1 — panel down the left, photo right, convex arc between them.
   The two radii differ (100% of width / 50% of height), which is what bows
   the edge outward instead of rounding a corner. */
.featured--side::after {
  -webkit-mask-image: url('../images/curve.svg');
  mask-image: url('../images/curve.svg');
  -webkit-mask-position: var(--panel-mask-position, left);
  mask-position: var(--panel-mask-position, left);
}

.featured--side .featured__content {
  inset-inline-start: 0;
}

/* Variant 2 — panel in the bottom-right, photo filling the rest. */
.featured--corner::after {
  -webkit-mask-image: url('../images/curve-right.svg');
  mask-image: url('../images/curve-right.svg');
  -webkit-mask-position: var(--panel-mask-position, right);
  mask-position: var(--panel-mask-position, right);
}

.featured--corner .featured__content {
  inset-inline-end: 0;
}

.featured__content h1 {
  margin-bottom: var(--space-md);
  font-size: var(--text-2xl);
}

/* --------------------------------------------------------------------------
  Footer
-------------------------------------------------------------------------- */

footer .menu {
  justify-content: flex-start;
  margin-bottom: var(--space-md);
  ul {
    flex-flow: column wrap;
    align-items: flex-start;
    list-style-type: none;
    padding: 0;
    li {
      margin: 0;
    }
    li + li {
      margin-top: var(--space-2xs);
    }
  }
}
footer nav {
  margin: 0;
}
.footer-grid {
  margin: 0 0 var(--space-lg) 0;
}
footer .social {
  list-style-type: none;
  padding: 0;
  margin: 0;
  li + li {
    margin-top: var(--space-2xs);
  }
}
footer h3 {
  font-size: var(--text-md);
}
footer .copyright {
  p {
    margin: 0;
  }
}
.footer-logo img {
  max-width: 80px;
  height: auto;
}

/* Align the footer's second column with the .container--content column used
   for page bodies above it.

   Both containers are centred and share the same padding-inline, so the
   padding cancels and the offset between their content edges is purely
   (full - content) / 2 — no viewport term:

     .container          left edge = (W - 88rem) / 2 + gutter
     .container--content left edge = (W - 54rem) / 2 + gutter
     difference                    = (88rem - 54rem) / 2 = 17rem

   Column 1 therefore has to be that offset minus one grid gap. This holds
   exactly only once .container is actually capped at --width-full, which is
   why it lives in a min-width query: below that the container is narrower
   than 88rem, the real offset shrinks with the viewport, and tracking it
   would need 100vw — which is off by the scrollbar width. Below the cap the
   columns stay equal, which is the better layout at that size anyway. */
@media (min-width: 88rem) {
  footer .grid-4 {
    grid-template-columns:
      calc((var(--width-full) - var(--width-content)) / 2 - var(--space-xl))
      repeat(3, minmax(0, 1fr));
  }
}

/* --------------------------------------------------------------------------
  General / reuseable
-------------------------------------------------------------------------- */

.top-border {
  border-top: 1px solid var(--vamlas-vaaleansininen);
  padding-top: var(--space-xl);
  margin-top: var(--space-xl);
}
.line {
  background: var(--vamlas-liukuvari);
  width: 100%;
  height: 5px;
  display: block;
}
.related {
  .item {
    time {
      margin-bottom: 0;
    }
  }
}
/* Category filter: a plain GET form — label, select, submit button. */
.categories {
  margin: var(--space-md) 0 var(--space-lg);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-xs);
  align-items: center;

  label {
    margin: 0;
    font-weight: var(--weight-semibold);
  }

  /* The global form rule sets width:100% so fields fill a column. Here the
     select sits inline beside its label, so it sizes to its content instead —
     with a floor that keeps the longest category name readable. */
  select {
    width: auto;
    min-width: min(18rem, 100%);
  }
}
.details-container {
  background: var(--vamlas-sinivioletti);
  border-radius: var(--radius-md);
  align-items: center;
  margin: var(--space-xl) 0;
  color: var(--color-text-on-dark);
  h2 {
    color: var(--color-text-on-dark);
    font-size: var(--text-md);
    margin-bottom: var(--space-2xs);
  }
}
.details-image {
  img {
    border-top-left-radius: var(--radius-md);
    border-bottom-left-radius: var(--radius-md);
  }
}
.details-content {
  p, time {
    margin: 0;
  }
  a.training-link {
    color: #fff;
  }
}
.items-title {
  margin-bottom: var(--space-md);
}
figure.center {
  img {
    border-radius: var(--radius-md);
    display: block;
    margin: 0 auto var(--space-xl);
  }
}
.disclaimer {
  background: var(--color-bg-subtle);
  border-radius: var(--radius-sm);
  padding: var(--space-md);
  margin: 0 0 var(--space-md) 0;
  font-style: italic;
  border-left: 6px solid var(--vamlas-keltaoranssi);
}
.title-divider {
  font-weight: 400;
}
/* Slogan and button side by side.

   The previous `flex: 0 1 auto` kept them stacked: flex-basis: auto means an
   item's base size is its max-content width, and the slogan is a 131-character
   sentence — far wider than the container. With wrapping on, an item that does
   not fit moves to the next line BEFORE any shrinking happens, so the slogan
   claimed the whole line and the button dropped below it.

   Giving the text a basis it can actually meet lets both share a line, while
   still stacking naturally once the container gets narrow. */
.about {
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-md) var(--space-lg);

  > p {
    margin: 0;   /* the gap handles spacing, including once wrapped */
  }

  > p:first-child {
    flex: 1 1 22rem;
    font-size: var(--text-md);
    color: var(--color-accent);
  }

  /* The button sizes to its label rather than being stretched. */
  > p:last-child {
    flex: 0 0 auto;
  }
}
.category-intro {
  align-items: center;
}

/* --------------------------------------------------------------------------
  Newsletter / subscribe
-------------------------------------------------------------------------- */

.newsletter {
  p:last-of-type {
    margin-bottom: 0;
  }
}