/* ========================================================================
   components.css — the page component kit
   Loaded AFTER css/style.css, so everything here may rely on (and override)
   what the main sheet already set.

   Rules this file keeps to:
   - Only the existing tokens: --ink, --ink-soft, --ice, --lift, --line,
     --blue, --ease, --nav-h, --pad. No new colour, no new font, no new
     radius or shadow language. Dark mode rides the same tokens through
     html.mode-dark, exactly as the main sheet does.
   - Every selector carries its own block prefix (.subhero__, .pcard__,
     .erow__, .erows-more__, .tags__, .tail__, .legal__, .day__, .rotator__,
     .benefit__, .numbers__), so nothing here can collide with style.css.
   - Hover states live only inside @media (hover: hover) and (pointer: fine),
     so a finger tap never leaves a component stuck in its hover look.
   - Everything works down to 360px with no horizontal page scroll.
   - Reuse first. .section, .section__head, .section__index, .section__title,
     .split / .split-lines, .btn (+ --primary/--small/--outline/--ghost),
     .btn__arrow, .offer__grid + .offer__card, .offer__numbers, .process*,
     .promises, .footer* and .apply__* come from style.css unchanged.
   ======================================================================== */


/* ------------------------------------------------------------------------
   00 · Shared surface and helpers
   The frosted recipe is the main sheet's card rule, so a programme card is
   visibly the same material as an .offer__card.
   ------------------------------------------------------------------------ */
.pcard {
  background: color-mix(in srgb, #ffffff 45%, transparent);
  -webkit-backdrop-filter: blur(22px) saturate(180%);
  backdrop-filter: blur(22px) saturate(180%);
  border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  box-shadow: 0 1px 0 color-mix(in srgb, #fff 80%, transparent) inset,
              0 20px 50px -34px color-mix(in srgb, var(--ink) 34%, transparent);
}
html.mode-dark .pcard {
  background: color-mix(in srgb, #fff 5%, transparent);
  border-color: color-mix(in srgb, #fff 11%, transparent);
  box-shadow: 0 1px 0 color-mix(in srgb, #fff 8%, transparent) inset;
}

/* One focus ring for every interactive part of this kit. The main sheet uses
   an ink ring in the header and a blue ring in the form; blue is the one that
   reads on both the aurora and a frosted card. */
.pcard__link:focus-visible,
.erow__link:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 3px;
  border-radius: 6px;
}

/* Every box in this kit that takes its height from an aspect-ratio is also a
   grid or flex child somewhere. Such a box keeps an automatic minimum size, and
   in a grid row that mixes ratios it can resolve its width from the row's
   height and blow the whole track past the viewport. Opting out of the
   automatic minimum fixes it with no side effect, because every one of these
   boxes is sized by its container. */
.subhero__media,
.pcard__media,
.erow__thumb {
  min-width: 0;
  min-height: 0;
}

/* Anchor landing, once for the whole site.
   The header is fixed and `--nav-h` tall, so a section reached by a hash — from
   another page, from the footer, or with JS off — would otherwise open with its
   label hidden under the bar. Every linkable section on every page is a
   `.section` carrying an id, so one rule covers them all. */
.section[id] {
  scroll-margin-top: calc(var(--nav-h) + 24px);
}

/* The skip link is NOT defined here. style.css owns `.skip-link`, and
   partials/header-sub.html uses that name.

   One thing is corrected: style.css parks the focused pill at top: 8px, which
   is inside the fixed bar, so while it had focus it sat on top of the wordmark.
   The bar is exactly --nav-h tall, so dropping the pill just below it clears
   the brand and changes nothing else. */
.skip-link:focus { top: calc(var(--nav-h) + 8px); }

/* For labels that must exist for a screen reader and nowhere else. */
.vishidden {
  position: absolute !important; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden; white-space: nowrap;
  clip: rect(0 0 0 0); clip-path: inset(50%); border: 0;
}


/* ------------------------------------------------------------------------
   01a · Subpage header
   Wordmark left; the language link and the brief pill right. Below 600px the
   wordmark steps down a size so the three fit one row at 360px.
   ------------------------------------------------------------------------ */
@media (max-width: 600px) {
  .nav__logo { font-size: 0.8rem; }
}


/* ------------------------------------------------------------------------
   01b · Subpage hero
   Eyebrow, H1 with one italic word, lead, then one wide photo. The H1 reuses
   the .apply__title step of the ramp rather than the hero's display size: a
   subpage opens under a fixed bar, not on a full-viewport stage.
   ------------------------------------------------------------------------ */
.subhero {
  max-width: 1500px; margin: 0 auto;
  padding: calc(var(--nav-h) + clamp(44px, 8vh, 104px)) var(--pad) clamp(40px, 7vh, 80px);
}
.subhero__title {
  font-family: 'Clash Display', sans-serif; font-weight: 600;
  font-size: clamp(2.6rem, 7vw, 5.2rem); line-height: 1; letter-spacing: -0.02em;
  margin: 0 0 22px; max-width: 18ch;
}
/* style.css only paints em blue inside .section__title, .hero__title and
   .cta__title, so the subpage H1 has to claim it for itself. */
.subhero__title em { color: var(--blue); }
.subhero__lead {
  max-width: 760px;
  font-size: clamp(1.05rem, 1.6vw, 1.35rem); line-height: 1.55; opacity: 0.85;
}
.subhero__lead + .subhero__lead { margin-top: 18px; }
/* 16:9 on desktop, 4:3 on a phone: a letterbox loses the room at 360px. */
.subhero__media {
  margin: clamp(34px, 6vh, 72px) 0 0;
  aspect-ratio: 16 / 9; border-radius: 16px; overflow: hidden;
}
.subhero__caption {
  margin-top: 12px; font-size: 0.82rem; line-height: 1.5; color: var(--ink-soft);
}
@media (max-width: 700px) {
  .subhero__media { aspect-ratio: 4 / 3; }
  .subhero__title { max-width: none; }
}


/* ------------------------------------------------------------------------
   02 · Programme card grid
   Photo 4:3, eyebrow, H3, one sentence, a short ✦ tape and an arrow link. The
   link is stretched over the whole card, so the card is one click target while
   the accessible name stays on the real anchor. The --soon variant has a
   badge, no photo and no link. The five- and six-card grids are in sections
   07 and 12.
   ------------------------------------------------------------------------ */
.pcards {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px;
  margin-top: clamp(40px, 7vh, 80px);
}
.pcard {
  position: relative; isolation: isolate;
  display: flex; flex-direction: column;
  border-radius: 16px; overflow: hidden;
  transition: border-color 0.4s var(--ease), transform 0.4s var(--ease);
}
.pcard__media { aspect-ratio: 4 / 3; overflow: hidden; margin: 0; }
.pcard__media img { transition: transform 0.8s var(--ease); }
.pcard__body {
  display: flex; flex-direction: column; flex: 1 1 auto;
  gap: 10px; padding: clamp(20px, 2.5vw, 32px);
}
/* Same micro-label as .offer__card h3, one step quieter than the title. */
.pcard__eyebrow {
  font-size: 0.78rem; font-weight: 500; text-transform: uppercase;
  letter-spacing: 0.14em; opacity: 0.55;
}
.pcard__title {
  font-family: 'Clash Display', sans-serif; font-weight: 600;
  font-size: clamp(1.1rem, 1.6vw, 1.4rem); line-height: 1.2;
}
.pcard__text { font-size: 0.95rem; line-height: 1.6; color: var(--ink-soft); }
/* Side by side, a one-line title would start its text higher than a
   two-line neighbour, so every title keeps room for two lines. Stacked on a
   phone there is no neighbour to line up with. */
@media (min-width: 561px) { .pcards .pcard__title { min-height: 2.4em; } }
/* The ✦ tape, card sized. */
.pcard__tape {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px;
  margin-top: 4px;
  font-family: 'Clash Display', sans-serif; font-weight: 500; font-size: 0.85rem;
  color: var(--ink-soft);
}
.pcard__tape i { font-style: normal; font-size: 0.7rem; color: var(--blue); }
.pcard__link {
  margin-top: auto; padding-top: 14px;
  display: inline-flex; align-items: center; gap: 10px;
  font-family: 'Clash Display', sans-serif; font-weight: 600; font-size: 0.95rem;
  color: var(--blue);
}
/* The whole card is the hit area. */
.pcard__link::after { content: ''; position: absolute; inset: 0; border-radius: inherit; }
.pcard__link .btn__arrow { transition: transform 0.35s var(--ease); }
/* Coming soon: no photo, no link, a badge where the eyebrow sits. */
.pcard__badge {
  align-self: flex-start;
  padding: 7px 14px; border-radius: 100px;
  border: 1px solid color-mix(in srgb, var(--blue) 45%, transparent);
  color: var(--blue);
  font-size: 0.72rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.14em;
}
.pcard--soon .pcard__body {
  padding-top: clamp(26px, 3vw, 40px);
  /* A card without a photo, tape or link is shorter than its neighbours.
     Centring its lines turns the height the stretched row gives it into
     margin instead of a hole. */
  justify-content: center;
}
/* Focus lands on the stretched anchor, so ring the card, not the text. */
.pcard:has(.pcard__link:focus-visible) { outline: 2px solid var(--blue); outline-offset: 3px; }
.pcard__link:focus-visible { outline: none; }
/* …but only where :has() exists to draw that ring. Without it the line above
   would suppress the link's own outline and put nothing in its place, leaving
   the three programme links with no visible focus at all. */
@supports not (selector(:has(*))) {
  .pcard__link:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
}

/* The cursor spotlight, the same one style.css gives .offer__card. js/site.js
   feeds --mx/--my on pointermove. Painted above the stretched
   .pcard__link::after, which is why it must not take pointer events. */
@media (hover: hover) {
  .pcard { position: relative; }
  .pcard::after {
    content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none;
    opacity: 0; transition: opacity 0.4s;
    background: radial-gradient(240px circle at var(--mx, 50%) var(--my, 50%), rgba(0, 65, 255, 0.13), transparent 65%);
  }
  .pcard:hover::after { opacity: 1; }
  /* The card that leads nowhere does not light up either. */
  .pcard--soon:hover::after { opacity: 0; }
}

@media (hover: hover) and (pointer: fine) {
  .pcard:hover { border-color: var(--blue); transform: translateY(-4px); }
  .pcard:hover .pcard__media img { transform: scale(1.04); }
  .pcard:hover .pcard__link .btn__arrow { transform: translateX(5px); }
  /* No hover lift on the card that leads nowhere. */
  .pcard--soon:hover { transform: none; border-color: color-mix(in srgb, var(--ink) 10%, transparent); }
  html.mode-dark .pcard--soon:hover { border-color: color-mix(in srgb, #fff 11%, transparent); }

  /* The ✦ tape steps in from the centre outwards on hover and on focus. It is
     declared ONLY inside this query: a touch device or a keyboard-only visitor
     never sees the dimmed resting state, it simply reads the tape finished.
     Three phrases, so centre-out is 2nd, then 1st, then 3rd. Pure CSS — no JS,
     so it cannot get stuck half-played. */
  .pcard__tape span {
    opacity: 0.55; transform: translateY(4px);
    transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
  }
  .pcard:hover .pcard__tape span,
  .pcard:focus-within .pcard__tape span { opacity: 1; transform: none; }
  .pcard:hover .pcard__tape span:nth-of-type(2),
  .pcard:focus-within .pcard__tape span:nth-of-type(2) { transition-delay: 0s; }
  .pcard:hover .pcard__tape span:nth-of-type(1),
  .pcard:focus-within .pcard__tape span:nth-of-type(1) { transition-delay: 0.05s; }
  .pcard:hover .pcard__tape span:nth-of-type(3),
  .pcard:focus-within .pcard__tape span:nth-of-type(3) { transition-delay: 0.1s; }
}
@media (max-width: 1024px) { .pcards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px)  { .pcards { grid-template-columns: 1fr; } }


/* ------------------------------------------------------------------------
   03 · Event row list
   Hairline rows in the language of .promise: date, title, one line, place. On
   desktop, hovering or focusing a row fades its photo into a fixed slot in the
   right column; the list reserves that column so nothing ever sits under the
   photo. On phones the same <img> becomes a 64px thumb inside the row, so the
   picture is never keyboard-only content.
   ------------------------------------------------------------------------ */
.erows {
  list-style: none; margin: clamp(36px, 6vh, 72px) 0 0;
  border-top: 1px solid var(--line);
}
.erow {
  position: relative;
  display: grid;
  grid-template-columns: minmax(92px, 11%) minmax(0, 1fr) minmax(110px, 16%);
  grid-template-areas:
    "date  title place"
    "date  note  place";
  column-gap: clamp(14px, 2.4vw, 40px); row-gap: 6px;
  padding: clamp(20px, 2.6vw, 34px) 0;
  border-bottom: 1px solid var(--line);
  transition: background 0.4s var(--ease);
}
.erow__date {
  grid-area: date;
  font-family: 'Clash Display', sans-serif; font-weight: 600;
  font-size: 0.82rem; letter-spacing: 0.06em; color: var(--blue);
  font-variant-numeric: tabular-nums;
}
.erow__title {
  grid-area: title;
  font-family: 'Clash Display', sans-serif; font-weight: 600;
  font-size: clamp(1.1rem, 1.6vw, 1.4rem); line-height: 1.2;
}
.erow__note { grid-area: note; font-size: 0.95rem; line-height: 1.55; color: var(--ink-soft); max-width: 62ch; }
.erow__place { grid-area: place; font-size: 0.85rem; line-height: 1.5; color: var(--ink-soft); opacity: 0.85; }
.erow__link { color: inherit; }
.erow__link::after { content: ''; position: absolute; inset: 0; }
/* Off by default: a plain row on a plain page shows no photo at all. */
.erow__thumb { display: none; margin: 0; }

/* Desktop: the fixed preview slot, aligned to the 1500px container's right
   gutter so it lines up with the section edge instead of the window edge. */
@media (min-width: 901px) {
  .erows--preview { padding-right: calc(min(32vw, 420px) + clamp(24px, 4vw, 64px)); }
  /* The reserved photo column takes roughly a third of the width, so the date
     track gets a fixed FLOOR rather than a percentage, and the floor is the
     part that does the work: the middle track is 1fr, an fr track absorbs all
     the leftover space in the row, so a minmax(x, max-content) track never
     actually grows past x. 165px clears the longest date on one line. */
  .erows--preview .erow {
    grid-template-columns: minmax(165px, max-content) minmax(0, 1fr) minmax(110px, 16%);
  }
  .erows--preview .erow__thumb {
    display: block; position: fixed; z-index: 1; pointer-events: none;
    top: calc(var(--nav-h) + clamp(28px, 12vh, 110px));
    right: max(var(--pad), calc(50vw - 750px + var(--pad)));
    width: min(32vw, 420px); aspect-ratio: 4 / 3;
    border-radius: 16px; overflow: hidden;
    opacity: 0; transform: translateY(10px);
    transition: opacity 0.4s var(--ease), transform 0.4s var(--ease);
  }
  /* Keyboard parity: focus anywhere in the row raises the same photo. */
  .erows--preview .erow:focus-within .erow__thumb,
  .erows--preview .erow:focus-visible .erow__thumb { opacity: 1; transform: none; }
  /* The same state, set by js/site.js from pointerenter and focusin, so the
     script has one class to drive instead of re-implementing the CSS. The
     CSS rules above stay the no-JS path and keep working on their own. */
  .erows--preview .erow.is-preview .erow__thumb { opacity: 1; transform: none; }

  /* Event posters are 4:5, not 4:3. Cropping one to the photo slot would cut
     its title off, so a poster row gets a slot of its own and is shown whole,
     narrower so a 4:5 preview does not outgrow a short window. */
  .erows--preview .erow__thumb--poster {
    width: min(24vw, 320px);
    aspect-ratio: 4 / 5;
  }
}
@media (min-width: 901px) and (hover: hover) and (pointer: fine) {
  .erows--preview .erow:hover .erow__thumb { opacity: 1; transform: none; }
  .erow:hover .erow__title { color: var(--blue); }
}

/* Phone: one column, a 64px thumb beside the date and title. */
@media (max-width: 700px) {
  .erow {
    grid-template-columns: 64px minmax(0, 1fr);
    grid-template-areas:
      "thumb date"
      "thumb title"
      "note  note"
      "place place";
    column-gap: 14px;
  }
  .erow__thumb {
    display: block; grid-area: thumb; align-self: start;
    width: 64px; height: 64px; border-radius: 12px; overflow: hidden;
  }
  /* A row with no photo must not leave a 64px hole. */
  .erow:not(:has(.erow__thumb)) { grid-template-columns: minmax(0, 1fr); grid-template-areas: "date" "title" "note" "place"; }
  .erow__note { max-width: none; }
  /* The 64px thumb becomes 64x80 for a poster, so it is uncropped here too.
     The grid column stays 64px wide, so nothing else in the row moves. */
  .erow__thumb--poster { width: 64px; height: 80px; }
}


/* ------------------------------------------------------------------------
   04 · Tag row
   A row of chips for a list of topics or tracks.
   ------------------------------------------------------------------------ */
.tags { list-style: none; display: flex; flex-wrap: wrap; gap: 9px; margin-top: clamp(28px, 4vh, 48px); }
.tags__item {
  font-size: 0.9rem; font-weight: 500; line-height: 1;
  padding: 10px 16px; border-radius: 100px;
  color: var(--ink-soft);
  border: 1px solid var(--line);
  background: color-mix(in srgb, #fff 40%, transparent);
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease),
    background 0.3s var(--ease), transform 0.3s var(--ease);
}
html.mode-dark .tags__item {
  background: color-mix(in srgb, #fff 5%, transparent);
  border-color: color-mix(in srgb, #fff 12%, transparent);
}
@media (hover: hover) and (pointer: fine) {
  .tags__item:hover {
    border-color: var(--blue); color: var(--blue);
    background: color-mix(in srgb, var(--blue) 7%, transparent);
    transform: translateY(-2px);
  }
}
@media (max-width: 420px) { .tags__item { font-size: 0.85rem; padding: 9px 14px; } }


/* ------------------------------------------------------------------------
   05a · Page tail
   A subpage ends the same way: H2 with one italic word, one line, one arrow
   button. Sits between the last section and the footer.
   ------------------------------------------------------------------------ */
.tail { max-width: 1500px; margin: 0 auto; padding: clamp(80px, 12vh, 150px) var(--pad); }
.tail__line { margin-top: 20px; max-width: 60ch; font-size: clamp(1.05rem, 1.6vw, 1.35rem); line-height: 1.55; opacity: 0.85; }
.tail .btn { margin-top: clamp(28px, 4vh, 44px); }
.tail__note { margin-top: 22px; max-width: 60ch; font-size: 0.92rem; line-height: 1.6; color: var(--ink-soft); }
.tail__note a { color: var(--blue); text-decoration: underline; text-underline-offset: 3px; }

/* 05b · Legal block (about.html, under the last section, above the footer) */
.legal {
  max-width: 1500px; margin: 0 auto;
  padding: clamp(28px, 4vh, 44px) var(--pad) 0;
}
.legal__inner { border-top: 1px solid var(--line); padding-top: clamp(20px, 3vh, 30px); }
.legal__name { font-family: 'Clash Display', sans-serif; font-weight: 600; font-size: 0.95rem; margin-bottom: 8px; }
.legal__lines { font-size: 0.85rem; line-height: 1.7; color: var(--ink-soft); }
.legal__lines span { display: block; }
.legal__link { color: var(--ink-soft); border-bottom: 1px solid color-mix(in srgb, currentColor 40%, transparent); transition: color 0.3s var(--ease); }
@media (hover: hover) and (pointer: fine) {
  .legal__link:hover { color: var(--blue); }
}


/* ------------------------------------------------------------------------
   06 · Footer: link list, legal line, bottom-row links and mark
   The list drops the browser bullets the global reset leaves behind; the legal
   line sits under the copyright, smaller and quieter.
   ------------------------------------------------------------------------ */
.footer__list { list-style: none; display: flex; flex-direction: column; gap: 10px; }
/* .footer__cols p has a bottom margin, so the list needs no top margin of its
   own. */
.footer__list a { align-self: flex-start; }
.footer__legal {
  margin-top: 20px;
  font-size: 0.72rem; line-height: 1.6;
  color: var(--ink-soft); opacity: 0.75;
  max-width: 90ch;
}
/* The bottom row's links, spaced apart like every other item in that row. */
.footer__links { display: flex; flex-wrap: wrap; gap: clamp(14px, 2vw, 28px); }
/* assets/logo-mark.png is a white-on-transparent mark: flattened to ink in
   light mode, left as it is in dark mode. The file is RGBA, so only the
   glyphs are painted, not a plate. */
.footer__mark { filter: brightness(0); opacity: 0.55; }
html.mode-dark .footer__mark { filter: none; opacity: 0.95; }


/* ------------------------------------------------------------------------
   07 · Page-shaped exceptions
   Rules that belong to one page or one section each. Each says where.
   ------------------------------------------------------------------------ */

/* Two or more lead paragraphs in a row. style.css resets every margin to 0
   and gives .offer__lead no rhythm of its own. Same 18px step .subhero__lead
   uses above, so the two stacks read alike. */
.offer__lead + .offer__lead { margin-top: 18px; }

/* --- index.html -------------------------------------------------------------
   The home page is built from the kit plus the patterns in style.css; the
   rules below are the modifiers it needs on top. Same contract as the rest of
   the file: only the existing tokens, every hover inside the hover query,
   every movement cancelled under reduced motion (section 10), and nothing
   that moves on x. */

/* Hero. style.css caps .hero__sub at 30ch, which is too narrow for a lead of
   several sentences: 52ch keeps it to four or five lines beside the buttons at
   1440 and lets .hero__bottom keep its two-column, bottom-aligned
   composition. */
.hero__sub--lead { max-width: 52ch; }

/* Two buttons side by side. style.css stacks .hero__cta as a column; two
   buttons read as a row. On a phone they go full width, so the stack lines up
   with the lead above it. */
.hero__cta--row { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px; }
@media (max-width: 760px) {
  .hero__cta--row { width: 100%; }
  .hero__cta--row .btn { width: 100%; justify-content: center; }
}

/* The numbers band. Tabular figures so the numerals do not jitter while
   site.js counts them up; a bold noun at the head of a label (css/fonts.css
   loads Satoshi at 400, 500 and 700, so 700 is the weight that exists; 600 would be
   synthesised). */
.offer__numbers--facts .offer__num-val { font-variant-numeric: tabular-nums; }
.offer__numbers--facts .offer__num-label strong { font-weight: 700; color: var(--ink); }

/* Five cards, the first featured. The four-card grid of section 02 re-cut as
   three columns with the first card spanning two. At 761px and up the
   featured card lays its photo on the left and its copy on the right, so its
   height follows the 4:3 card beside it instead of stretching the row. Below
   that it stacks like every other card. */
.pcards--five { grid-template-columns: repeat(3, 1fr); }
.pcard--feature { grid-column: span 2; }
@media (min-width: 761px) {
  .pcard--feature { flex-direction: row; }
  .pcard--feature .pcard__media { flex: 0 0 50%; aspect-ratio: auto; }
  .pcard--feature .pcard__media img { height: 100%; object-fit: cover; }
  /* The copy centres in the taller card; the link therefore joins the stack
     instead of being pushed to the bottom edge by its auto margin. */
  .pcard--feature .pcard__body { justify-content: center; }
  .pcard--feature .pcard__link { margin-top: 6px; }
}
/* A badge with the live dot. The keyframes (livepulse) are in style.css;
   section 10 stops the dot under reduced motion. */
.pcard__badge--live { display: inline-flex; align-items: center; gap: 8px; }
.pcard__badge--live::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0;
  background: var(--blue);
  animation: livepulse 2.2s var(--ease) infinite;
}
@media (max-width: 1024px) { .pcards--five { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) {
  .pcards--five { grid-template-columns: 1fr; }
  .pcard--feature { grid-column: auto; }
}

/* A one-row tail: the kit's .tail without its H2. Eyebrow and one sentence on
   the left, one button on the right, between two hairlines that stay inside
   the content width. The section's own vertical padding is dropped; the
   neighbours' section padding is the air around it. */
.tail--row { padding-top: 0; padding-bottom: 0; }
.tail__row {
  display: flex; justify-content: space-between; align-items: center;
  gap: 24px 40px; flex-wrap: wrap;
  padding: clamp(36px, 6vh, 64px) 0;
  border-top: 1px solid var(--line); border-bottom: 1px solid var(--line);
}
.tail__copy { min-width: 0; }
.tail--row .section__index { margin-bottom: 10px; }
.tail--row .tail__line { margin-top: 0; }
.tail--row .btn { margin-top: 0; flex: 0 0 auto; }
@media (max-width: 560px) {
  .tail--row .btn { width: 100%; justify-content: center; }
}


/* ------------------------------------------------------------------------
   08 · Forced colours
   Windows High Contrast (and any forced-colors mode) throws box-shadow away.
   The brief form's text fields, its select and its choice pills suppress the
   native outline and show focus as a blue box-shadow halo instead, which is a
   real ring in normal rendering and nothing at all there. This adds a
   fallback ring only in a mode where the authored one cannot be drawn: the
   normal look is untouched.
   ------------------------------------------------------------------------ */
@media (forced-colors: active) {
  .field input:focus-visible,
  .field select:focus-visible,
  .field textarea:focus-visible,
  .choice:has(input:focus-visible) {
    outline: 2px solid Highlight;
    outline-offset: 2px;
  }
}


/* ------------------------------------------------------------------------
   09 · Between pages
   Every page is a real HTML file, so navigation gets the browser's own
   cross-document View Transitions rather than a router: old content fades in
   0.22s, new content rises 24px in 0.5s on the house curve, and the fixed
   header is its own named group so the bar never flashes. Chrome/Edge 126+ and
   Safari 18.2+; Firefox simply navigates, which is the same page either way.

   THE COLLISION, and how it is kept apart. style.css already owns bare
   `::view-transition-old(root)` / `::view-transition-new(root)` for the
   dark-mode star wipe — a SAME-document transition. Those selectors cannot
   tell a theme flip from a page navigation, so without a guard every click
   would circle-wipe out of the last star's coordinates. js/main.js therefore
   puts `mode-wipe` on <html> for exactly as long as the theme transition runs,
   and every rule below is scoped `html:not(.mode-wipe)`. During a wipe these
   rules do not match and style.css's modewipe keyframes are untouched; during
   a navigation the class is absent (a fresh document never has it) and these
   win on specificity. Neither ever sees the other's animation.

   Everything sits inside `prefers-reduced-motion: no-preference`, so a visitor
   who asked for less motion gets a plain, instant navigation.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }

  html:not(.mode-wipe)::view-transition-old(root) {
    animation: vt-out 0.22s var(--ease) both;
  }
  html:not(.mode-wipe)::view-transition-new(root) {
    animation: vt-in 0.5s var(--ease) 0.12s both;
  }

  /* The frosted bar is on every page in the same place, so it is carried
     across instead of being faded out and back in with the page under it. */
  html:not(.mode-wipe) .nav { view-transition-name: site-nav; }
  html:not(.mode-wipe)::view-transition-group(site-nav) { animation-duration: 0.35s; }
}
/* Named outside the query so a skipped or unsupported transition still has
   them defined; unused keyframes cost nothing. 24px is the same rise the stat
   band and the process steps already use. */
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(24px); } }


/* ------------------------------------------------------------------------
   10 · Reduced motion
   style.css already clamps every duration to 0.01ms, which handles fades.
   What it cannot do is cancel a transform that a hover state applies, so every
   movement in this kit is switched off here, and anything that was revealed by
   a transform is put in its resting position instead.
   ------------------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  .pcard:hover,
  .tags__item:hover { transform: none; }
  .pcard:hover .pcard__media img,
  .pcard:hover .pcard__link .btn__arrow { transform: none; }
  .erows--preview .erow__thumb { transform: none; transition: none; }
  .erows--preview .erow:hover .erow__thumb,
  .erows--preview .erow.is-preview .erow__thumb,
  .erows--preview .erow:focus-within .erow__thumb { transform: none; }
  /* The live badge carries the pulsing dot. */
  .pcard__badge--live::before { animation: none; }
  /* The tape settles instantly instead of stepping in from the centre. */
  .pcard__tape span { opacity: 1; transform: none; transition: none; }
}

/* A visitor who asked for less transparency gets flat surfaces, the same
   bargain the buttons already make in style.css. */
@media (prefers-reduced-transparency: reduce) {
  .pcard {
    background: var(--lift);
    -webkit-backdrop-filter: none; backdrop-filter: none;
  }
}

/* ==========================================================================
   11 · Touch targets and dark-mode contrast
   On coarse pointers every control gets at least 44 px of hit area. Padding
   grows, negative margins keep the visual position, so the desktop look is
   untouched. In dark mode the FAQ answers get a higher opacity so they keep
   their contrast on the dark ground.
   ========================================================================== */
@media (hover: none) and (pointer: coarse) {
  .nav__logo { padding-block: 14px; margin-block: -14px; }
  .btn--small { min-height: 44px; }
  .footer__list a, .footer__links a, .footer__bottom a, .footer__brandline a { display: inline-block; padding-block: 8px; margin-block: -8px; }
  .pcard__link { padding-block: 6px; margin-block: -6px; }
}
html.mode-dark .faq__a p { opacity: 0.88; }

/* ==========================================================================
   12 · Six project cards: the sixth card closes the grid full width.
   ========================================================================== */
.pcards--six .pcard--soon { grid-column: 1 / -1; }
@media (min-width: 1025px) {
  .pcards--six .pcard--soon .pcard__body {
    flex-direction: row; flex-wrap: wrap;
    align-items: center; justify-content: flex-start;
    gap: 12px clamp(20px, 2.4vw, 40px);
    padding-top: clamp(20px, 2.5vw, 32px);
  }
  .pcards--six .pcard--soon .pcard__badge { align-self: center; }
  .pcards--six .pcard--soon .pcard__text { flex: 1 1 32ch; }
}
@media (max-width: 560px) {
  .pcards--six .pcard--soon { grid-column: auto; }
}

/* ==========================================================================
   13 · Language switch: the SLO/ENG text link beside the header pill.
   ========================================================================== */
.nav__lang {
  display: inline-flex; align-items: center;
  font-family: 'Clash Display', sans-serif; font-weight: 600; font-size: 0.95rem;
  letter-spacing: 0.01em; line-height: 1;
  color: var(--ink);
  transition: color 0.25s var(--ease);
}
.nav__lang:hover { color: var(--blue); }
.nav__lang:focus-visible { outline: 2px solid var(--ink); outline-offset: 4px; }
/* The hairline sits between the label and the pill; ink, not currentColor,
   so it stays quiet while the label turns blue on hover. .nav__actions adds
   its own 12px gap on the pill's side, so the line is centred in the gap. */
.nav__lang::after {
  content: ''; display: inline-block; width: 1px; height: 1.1em;
  margin-left: 12px;
  background: var(--ink); opacity: 0.25;
}
/* Phone: the subpage bar carries the wordmark, the switch and the pill in
   one row, so the switch gives back a few pixels on each side of its line. */
@media (max-width: 600px) {
  .nav__lang::after { margin-left: 8px; }
  .nav__actions { gap: 8px; }
}
/* Touch targets, the same treatment section 11 gives the wordmark and the
   pill: 44px of hit area, no change to the look. */
@media (hover: none) and (pointer: coarse) {
  .nav__lang { padding-block: 15px; margin-block: -15px; }
}

/* ==========================================================================
   14 · A button after a lead, four footer columns
   ========================================================================== */

/* A button, or a row of buttons, that follows a lead paragraph. style.css
   resets every margin to 0 and .offer__lead / .subhero__lead carry none of
   their own, so a button placed straight after one would sit flush against
   the last line of text. */
.offer__lead + .btn, .subhero__lead + .btn,
.subhero__lead + .hero__cta { margin-top: clamp(24px, 3.6vh, 36px); }

/* Four footer columns. style.css lays the footer out in three, so a fourth
   column wrapped onto a row of its own at desktop widths. The modifier keeps
   the three-column footer intact anywhere it is still used. */
@media (min-width: 1025px) {
}

/* ==========================================================================
   15 · Links inside running text
   ========================================================================== */

/* style.css gives every link the colour of the text around it and no
   underline, which suits navigation and buttons but hides a link that sits
   in the middle of a paragraph. Links inside lead paragraphs, FAQ answers,
   form hints and the confirmation panel are marked in the brand blue with a
   thin underline; buttons are excluded so they keep their own look. */
.offer__lead a:not(.btn), .subhero__lead a:not(.btn), .tail__line a:not(.btn),
.faq__a a:not(.btn), .apply__lead a:not(.btn), .field__hint a:not(.btn) {
  color: var(--blue);
  text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 0.18em;
}
@media (hover: hover) and (pointer: fine) {
  .offer__lead a:not(.btn):hover, .subhero__lead a:not(.btn):hover, .tail__line a:not(.btn):hover,
  .faq__a a:not(.btn):hover, .apply__lead a:not(.btn):hover, .field__hint a:not(.btn):hover {
    text-decoration-thickness: 2px;
  }
}

/* The skip link and in-page anchors move focus to <main> (tabindex="-1"),
   so screen readers announce the jump. A focused container is not a control,
   so it shows no focus ring. */
main[tabindex="-1"]:focus { outline: none; }

/* ==========================================================================
   16 · Three-card row (home page, recognition)
   ========================================================================== */

/* .pcards lays out four cards; a row of three uses this modifier so the
   cards fill the row instead of leaving a fourth slot empty. */

/* ==========================================================================
   17 · Benefits (home page, "What we bring")
   ========================================================================== */

/* Three equal points with no numbering, because they are not a sequence.
   Each opens with the kit's four-point star in the brand blue, the same mark
   the last step of the process uses, then a display-face title. */
.benefits {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(24px, 3vw, 48px);
  margin-top: clamp(40px, 6vh, 72px);
}
.benefit {
  display: flex; flex-direction: column; gap: 14px;
  border-top: 1px solid var(--line);
  padding-top: clamp(20px, 2.6vh, 28px);
}
.benefit__mark { display: block; width: 22px; height: 22px; color: var(--blue); }
.benefit__mark svg { display: block; width: 100%; height: 100%; }
.benefit__title {
  font-family: 'Clash Display', sans-serif; font-weight: 600;
  font-size: clamp(1.3rem, 2vw, 1.75rem); line-height: 1.15; letter-spacing: -0.01em;
}
.benefit p { font-size: clamp(0.98rem, 1.2vw, 1.08rem); line-height: 1.6; color: var(--ink-soft); max-width: 42ch; }
@media (max-width: 900px) { .benefits { grid-template-columns: 1fr; } }

/* ==========================================================================
   18 · Photo strip (talks page)
   ========================================================================== */

/* A row of photographs from the events themselves. Each tile is a plain
   <figure>: the photos are shown at a fixed 4:3 crop and are not opened in
   a lightbox, so they carry no pointer cursor. */
.gallery {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 1.6vw, 20px);
  margin-top: clamp(36px, 6vh, 72px);
}
.gallery--four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.gallery__item { aspect-ratio: 4 / 3; max-width: 100%; border-radius: 16px; overflow: hidden; }
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .gallery__item img { transition: transform 0.8s var(--ease); }
  .gallery__item:hover img { transform: scale(1.04); }
}
/* One line under the strip saying where and when the photos were taken. */
.gallery__note {
  margin-top: 18px;
  max-width: 78ch;
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--ink-soft);
}
@media (max-width: 900px) { .gallery, .gallery--four { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 420px) { .gallery, .gallery--four { gap: 10px; } }

/* ==========================================================================
   19 · Home headline with a turning word
   ========================================================================== */

/* "Gen-Z talent." stays still and the word under it turns over. All the words
   share one grid cell, so the box is as wide as the longest word (and no
   wider, so only the word itself pauses it on hover) and nothing below it
   moves when the word changes. Without the script, or with reduced
   motion, the first word simply stays. Screen readers get the whole line once
   from .sr-only; the turning words are hidden from them. */
.hero__static { display: block; }
.rotator { display: inline-grid; justify-items: start; vertical-align: top; }
.rotator__word {
  grid-area: 1 / 1;
  transition: opacity 0.5s var(--ease), transform 0.7s var(--ease);
}
.rotator__word:not(.is-on) { opacity: 0; transform: translateY(0.3em); }
.rotator__word.is-off { transform: translateY(-0.3em); }

/* Text for screen readers only. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}


/* A row of buttons closing a section. */
.section__cta { display: flex; flex-wrap: wrap; gap: 14px; margin-top: clamp(40px, 6vh, 64px); }

/* ==========================================================================
   21 · Earlier events behind one toggle (talks page)
   ========================================================================== */

/* The newest event is shown; the rest sit in a native <details>, so the
   toggle works from the keyboard and without the script. The summary is one
   more hairline row with the count and a round arrow that turns to point
   down when the list is open. */
.erows-more__toggle {
  display: flex; align-items: center; gap: 14px;
  padding: clamp(18px, 2.2vw, 26px) 0;
  border-bottom: 1px solid var(--line);
  font-family: 'Clash Display', sans-serif; font-weight: 600;
  font-size: clamp(1rem, 1.4vw, 1.2rem);
  cursor: pointer; list-style: none;
}
.erows-more__toggle::-webkit-details-marker { display: none; }
.erows-more__count {
  display: inline-grid; place-items: center; min-width: 28px; height: 28px; padding: 0 8px;
  border-radius: 999px; font-size: 0.8rem; font-variant-numeric: tabular-nums;
  color: var(--blue); background: color-mix(in srgb, var(--blue) 12%, transparent);
}
.erows-more__arrow {
  margin-left: auto; display: inline-grid; place-items: center; flex-shrink: 0;
  width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--line); color: var(--blue);
  transition: transform 0.4s var(--ease), background-color 0.3s var(--ease), color 0.3s var(--ease);
}
.erows-more[open] .erows-more__arrow { transform: rotate(90deg); }
@media (hover: hover) and (pointer: fine) {
  .erows-more__toggle:hover .erows-more__arrow { background: var(--blue); border-color: var(--blue); color: #fff; }
}
.erows-more__toggle:focus-visible { outline: 2px solid var(--blue); outline-offset: 4px; border-radius: 8px; }
.erows--more { margin-top: 0; border-top: 0; }

/* ==========================================================================
   22 · Facts in the home hero
   ========================================================================== */

/* The three facts sit at the bottom of the first screen, under the buttons,
   so they are read with the headline rather than after a scroll. Smaller
   figures than the stat band further down, and the cells keep one row down
   to tablet width. */
.hero .offer__numbers--hero { margin: clamp(24px, 4.5vh, 52px) 0 0; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.hero .offer__numbers--hero .offer__num { padding: clamp(14px, 2.2vh, 26px) clamp(12px, 1.8vw, 28px); }
.hero .offer__numbers--hero .offer__num-val { font-size: clamp(2rem, 4.2vw, 3.6rem); }
.hero .offer__numbers--hero .offer__num-label { max-width: 26ch; }
@media (max-width: 1024px) {
  .hero .offer__numbers--hero .offer__num:last-child { grid-column: auto; }
  .hero .offer__numbers--hero .offer__num:nth-child(n + 3) { border-top: 0; }
  .hero .offer__numbers--hero .offer__num + .offer__num { border-left: 1px solid var(--line); }
}
@media (max-width: 600px) {
  .hero .offer__numbers--hero { grid-template-columns: 1fr; }
  .hero .offer__numbers--hero .offer__num + .offer__num { border-left: 0; border-top: 1px solid var(--line); }
  .hero .offer__numbers--hero .offer__num-val { font-size: 1.9rem; }
  .hero .offer__numbers--hero .offer__num-label { max-width: none; font-size: 0.875rem; }
}

/* A link under a stat label, on a line of its own. */
.offer__num-link { display: block; margin-top: 8px; color: var(--blue); font-weight: 500; }
@media (hover: hover) and (pointer: fine) {
  .offer__num-link:hover { text-decoration: underline; text-underline-offset: 3px; }
}

/* The facts strip sits over the globe: a light ground of its own keeps the
   labels readable whatever the globe draws behind them. */
.hero .offer__numbers--hero {
  position: relative; z-index: 1;
  background: color-mix(in srgb, var(--ice) 90%, transparent);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}

/* On the request form page the header button would reload the form and lose
   the answers, so it is hidden there, together with the divider that would
   otherwise stand after the language switch with nothing beside it. */
.apply-body .nav .btn--small { display: none; }
.apply-body .nav__lang::after { display: none; }

/* A stat label that is also the link to the figure's source: the label keeps
   its colour and gets a quiet underline. */
.offer__num-label a {
  color: inherit; text-decoration: underline; text-underline-offset: 3px;
  text-decoration-color: color-mix(in srgb, currentColor 35%, transparent);
}
@media (hover: hover) and (pointer: fine) {
  .offer__num-label a:hover { color: var(--blue); }
}

/* The end of the page content: the footer opens on a hairline, so the last
   section always has a visible edge under it instead of running into blank
   space. It spans the footer's own width, like the legal block's rule. */
.footer { border-top: 1px solid var(--line); }

/* The partner strip under the home page hero: a dark band across the full
   width. The track holds the logo set twice and main.js slides it left by half
   its own width on a loop, so the second set lands exactly where the first
   began; the right padding matches the gap so that join is seamless too. */
.marquee-section {
  position: relative;
  padding: clamp(34px, 5.4vh, 56px) 0;
  background: var(--ink); color: var(--ice);
}
.marquee-label {
  position: absolute; top: clamp(12px, 1.9vh, 20px); left: 0; right: 0;
  text-align: center; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.18em;
  opacity: 0.42; margin: 0; padding: 0 var(--pad);
}
.marquee { overflow: hidden; }
.marquee__track {
  display: flex; align-items: center; width: max-content;
  gap: clamp(44px, 6vw, 96px); padding-right: clamp(44px, 6vw, 96px);
  will-change: transform;
}
.marquee__logo {
  flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  height: clamp(36px, 3.5vw, 50px);
}
.marquee__logo img {
  width: auto; height: 100%; max-width: none; object-fit: contain;
  filter: brightness(0) invert(1);
  opacity: 0.72; transition: opacity 0.4s var(--ease);
}
.marquee__logo:hover img { opacity: 1; }
/* A wordmark reads larger than a compact mark at the same pixel height, so
   each shape gets its own height and the row holds one optical line. */
.marquee__logo--wide { height: clamp(20px, 1.9vw, 25px); }
.marquee__logo--tall { height: clamp(26px, 2.5vw, 33px); }
/* Impact Hub's artwork is already white and has its own badge outline. */
.marquee__logo--hub { height: clamp(24px, 2.3vw, 31px); }
.marquee__logo--hub img { filter: none; opacity: 0.8; }
/* --ink turns light in dark mode, so the band keeps its own dark fill there. */
html.mode-dark .marquee-section { background: #17171d; color: var(--ink); }
html.mode-dark .marquee-label { opacity: 0.66; }
