/* ==========================================================================
   WIKAIR shared tokens and components for the pages built on Sacha's side
   of the design (Join us, Donate, Contact, and the hands hero on Home).

   The blend, deliberately:
     · Space Grotesk carries every title on the site, and his dark
       nav and footer frame every page unchanged.
     · Bodoni carries the WIKAIR wordmark only. It is the face used on the hands
       hero. Bodoni 72 Oldstyle ships with macOS and cannot be served as a
       webfont, so it leads the stack for Apple devices and Bodoni Moda
       covers everyone else.
     · The page surface stays in our clay-and-cobalt palette rather than his
       near-black. A light page inside his dark chrome shows both identities
       at once, which is the point while this is still being decided.

   One file on purpose, so there are no new folders.
   ========================================================================== */

:root {
  /* Surface. Sampled from the sky gradient the rest of the site sits on
     (#E8EDF4 to #E2E8F0), so a card here reads as the same material as a card
     on About rather than a slightly different grey. */
  --clay: #e4eaf2;
  --clay-raised: #eef2f7;
  --clay-sunken: #dde4ee;
  --paper: #ffffff;
  --sky: linear-gradient(160deg, #E8EDF4 0%, #D0DCE8 30%, #C8D8E8 50%, #D4DFEA 70%, #E2E8F0 100%);

  /* Ink. His headings are #101A36 and his body copy #232323; matching them
     means a heading does not change colour when you move between pages. */
  --ink: #101A36;
  --navy-900: #101A36;
  --navy-700: #213E89;
  --body: #3e4550;

  /* Accent. His --accent-bright / --accent, rather than a third blue. */
  --cobalt: #335DCD;
  --cobalt-700: #284AA3;
  --cobalt-100: #dbe4f7;

  /* Vincent's chrome, for the seams where our pages meet his nav/footer */
  --chrome: #141414;

  /* Card-scale curve, matching the radius already used site-wide for actual
     content cards and inputs (.tl-card, .highlight-card-img, .field input,
     .status): 4px, matched to About's thin photo trim, read as barely
     rounded at card size. Photo frames keep 4px as a literal value where
     they need it (contact.html), decoupled from this token. */
  --radius: 14px;
  --shadow-soft: 0 1px 2px rgba(10, 20, 38, 0.04), 0 12px 32px -16px rgba(10, 20, 38, 0.18);
  --shadow-lift: 0 1px 2px rgba(10, 20, 38, 0.05), 0 22px 48px -20px rgba(35, 71, 230, 0.25);
}

/* Pages that opt into the light surface. Applied on <body> so Vincent's
   dark nav and footer keep their own colours untouched above and below. */
/* The same fixed sky the rest of the site sits on, rather than a radial of
   our own. This is the rule that decides whether these pages feel like part
   of the site or like a different site wearing the same nav. */
body.wikair-light {
  background: var(--sky);
  background-attachment: fixed;
  color: var(--body);
}

.wk-wrap { max-width: 1120px; margin: 0 auto; padding: 0 2.5rem; }

/* ---------- Type ---------------------------------------------------------- */
.wk-eyebrow {
  /* Matches .mission-label / .team-label on About exactly: same size, same
     colour (already the same token), regular weight rather than bold, and
     wider tracking. */
  font-size: 0.75rem; font-weight: 400; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--cobalt-700);
}
.wk-display {
  font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', sans-serif;
  font-weight: 300;
  font-size: clamp(2.25rem, 4.6vw, 3.5rem);
  line-height: 1.08;
  letter-spacing: -0.01em;
  color: var(--navy-900);
  font-optical-sizing: auto;
}
.wk-h2 {
  font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', sans-serif;
  font-weight: 300;
  font-size: clamp(1.6rem, 2.6vw, 2.1rem);
  line-height: 1.15;
  color: var(--navy-900);
}
.wk-lead { font-size: 1.0625rem; line-height: 1.7; color: var(--body); max-width: 62ch; }
.wk-body { font-size: 0.95rem; line-height: 1.65; color: var(--body); }
.wk-small { font-size: 0.8125rem; line-height: 1.6; color: rgba(61, 74, 99, 0.72); }

/* The wordmark face. Local Bodoni first for Apple devices, Bodoni Moda
   (loaded from Google Fonts in the page head) for everyone else. */
.wk-wordmark {
  font-family: 'Bodoni 72 Oldstyle', 'Bodoni 72', 'Bodoni Moda', Didot, Georgia, serif;
  font-weight: 400;
  letter-spacing: 0.06em;
  font-optical-sizing: auto;
}

/* ---------- Surfaces ------------------------------------------------------ */
.wk-card {
  background: var(--clay-raised);
  border: 1px solid rgba(10, 20, 38, 0.06);
  border-radius: var(--radius);
  box-shadow: var(--shadow-soft);
}
.wk-card-inset {
  background: var(--clay-sunken);
  border-radius: 4px;
  box-shadow: inset 0 1px 3px rgba(10, 20, 38, 0.07);
}

/* ---------- Buttons ------------------------------------------------------- */
/* Home's "Wikair Highlights" button (.highlight-btn in index.html), so a
   button looks the same on every page: a full pill, the accent-to-bright
   cobalt gradient at 135deg, Space Grotesk at weight 400 with open tracking,
   and a soft cobalt glow that deepens as it lifts. */
.wk-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem;
  padding: 0.8rem 2rem; border-radius: 999px;
  font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Helvetica Neue', sans-serif;
  font-size: clamp(0.9rem, 1.4vw, 1.1rem); font-weight: 400; letter-spacing: 0.04em;
  text-decoration: none; border: 0; cursor: pointer;
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.wk-btn-primary {
  background: linear-gradient(135deg, #284AA3, #335DCD);
  color: #F2F6FF;
  box-shadow: 0 4px 24px rgba(51, 93, 205, 0.3);
}
.wk-btn-primary:hover { transform: translateY(-2px); box-shadow: 0 8px 32px rgba(51, 93, 205, 0.45); }
/* The secondary partner: same pill and type, a white fill and navy ink. */
.wk-btn-soft {
  background: #fff;
  color: var(--navy-900);
  box-shadow: 0 4px 24px rgba(16, 26, 54, 0.1);
}
.wk-btn-soft:hover { transform: translateY(-2px); box-shadow: 0 8px 32px rgba(16, 26, 54, 0.16); }
.wk-btn:active { transform: translateY(0); }
.wk-btn:disabled { opacity: 0.5; pointer-events: none; }

/* ---------- Section rhythm ------------------------------------------------ */
/* The hairline the homepage uses between its vision quadrants:
   ink at 12% opacity, not a heavy rule. Skipped on the first section of a
   page (.wk-section-first carries no border), so nothing sits above the header. */
/* padding-block, not the shorthand: several sections are .wk-wrap and
   .wk-section on one element, and "padding: 4.5rem 0" zeroed the wrap's side
   padding, so on a phone their text ran to the screen edge. */
.wk-section { padding-block: 4.5rem; border-top: 1px solid rgba(16, 26, 54, 0.12); }
.wk-section-first { padding-block: 10.5rem 3rem; }  /* clears the fixed 69px nav */

/* Home's .light-band (the "Our Journey" field): a full-bleed flat band in a
   lighter blue that meets the sky backdrop on a crisp edge. The colour change
   is the divider, so the hairline is dropped. Headings inside run at the
   Journey size and weight. */
.wk-band { background: #E4EBF7; border-top: 0; }
.wk-band + .wk-section { border-top: 0; }
/* The footer's 80px top margin would leave a strip of sky between a closing
   band and the footer; the band's own padding already gives the room. */
.wk-band + .footer { margin-top: 0; }
.wk-band .wk-h2,
.wk-h2.wk-h2-lg { font-size: clamp(2rem, 3.6vw, 3rem); letter-spacing: -0.01em; }
.wk-band .wk-lead { font-weight: 300; color: rgba(16, 26, 54, 0.78); max-width: 48rem; }

/* ---------- Partner school marquee --------------------------------------- */
.wk-marquee {
  position: relative; margin-top: 2.5rem; overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
}
/* Two constraints keep the loop seamless and both are easy to break: the
   spacing lives on the cards rather than as a flex gap (a gap sits between
   items only, leaving -50% half a gap short), and the track carries no
   padding, since translateX(-50%) resolves against the border box. */
.wk-marquee-track {
  display: flex; width: max-content;
  animation: wk-marquee 42s linear infinite;
}
.wk-marquee:hover .wk-marquee-track { animation-play-state: paused; }
@keyframes wk-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }

.wk-school {
  display: flex; align-items: center; gap: 1rem;
  min-width: 19rem; flex-shrink: 0;
  margin-right: 1rem; padding: 1.25rem 1.5rem;
  background: var(--clay-raised);
  border: 1px solid rgba(10,20,38,0.06);
  border-radius: 6px;
  box-shadow: var(--shadow-soft);
}
/* A white tile rather than a tinted circle: these are seven schools' own
   marks, drawn for white, and most arrive with their background baked in
   El Plantío's is navy. A neutral tile lets each sit as intended. */
/* Echoes the same white-frame language as About's photos: a real drop shadow
   rather than an inset one, so a school mark reads as a small print sitting
   on the card instead of a sunken icon well. */
.wk-school-logo {
  width: 56px; height: 56px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  background: #fff; border-radius: var(--radius); overflow: hidden;
  box-shadow: 0 4px 10px rgba(16, 26, 54, 0.12);
}
.wk-school-logo img { width: 100%; height: 100%; object-fit: contain; padding: 6px; }
.wk-school-name { font-weight: 600; font-size: 1.0625rem; color: var(--navy-900); line-height: 1.3; }
.wk-school-place { font-size: 0.8125rem; color: rgba(61,74,99,0.7); margin-top: 2px; min-height: 1.1rem; }

/* ---------- Motion preferences ------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .wk-marquee { overflow-x: auto; }
}

/* ---------- Ask WIKAIR (homepage FAQ conversation) ----------------------- */
.ask { background: linear-gradient(180deg, #eef1f8 0%, #e6ebf3 100%); }
.ask-grid { display: grid; gap: 2.5rem; grid-template-columns: 1fr; align-items: start; }
@media (min-width: 960px) { .ask-grid { grid-template-columns: 5fr 7fr; gap: 4rem; } }

.ask-panel { padding: 0; overflow: hidden; }
.thread {
  /* A definite height, not max-height: the scroll container needs something
     to resolve against, or it silently stops scrolling and the thread spills
     over the chips below. */
  height: 26rem; overflow-y: auto;   /* was 22rem; the answers now run to three paragraphs */
  padding: 1.5rem 1.5rem 0.5rem;
  scroll-behavior: smooth;
}
.turn { margin-bottom: 1.5rem; }
.q {
  margin-left: auto; max-width: 85%; width: fit-content;
  padding: 0.65rem 1rem; border-radius: 8px;
  background: linear-gradient(180deg, #3a5cf0 0%, var(--cobalt) 55%, var(--cobalt-700) 100%);
  color: #fff; font-size: 0.9375rem; line-height: 1.5;
  box-shadow: 0 10px 22px -12px rgba(35,71,230,0.6);
}
.a-row { display: flex; gap: 0.75rem; margin-top: 0.75rem; }
.a-mark {
  flex-shrink: 0; width: 30px; height: 30px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #8ea4ff, var(--cobalt) 60%, #1b37c4);
  box-shadow: 0 0 0 3px rgba(35,71,230,0.10);
}
.a {
  max-width: 88%; padding: 0.75rem 1rem; border-radius: 8px;
  background: var(--paper); color: var(--body);
  font-size: 0.9375rem; line-height: 1.6;
  box-shadow: 0 1px 2px rgba(10,20,38,0.05), 0 8px 20px -14px rgba(10,20,38,0.35);
  white-space: pre-line;   /* answers separate their paragraphs with a blank line */
}
.a .caret {
  display: inline-block; width: 2px; height: 1em; margin-left: 1px;
  background: var(--cobalt); vertical-align: -0.15em;
  animation: wk-caret 1.05s steps(1) infinite;
}
@keyframes wk-caret { 0%,49% { opacity: 1; } 50%,100% { opacity: 0; } }

.dots { display: inline-flex; gap: 5px; align-items: center; padding: 0.9rem 1rem; }
.dots span {
  width: 7px; height: 1px; border-radius: 0; background: rgba(61,74,99,0.55);
  animation: wk-dot 1.1s ease-in-out infinite;
}
.dots span:nth-child(2) { animation-delay: 0.15s; }
.dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes wk-dot { 0%,100% { opacity: 0.25; } 50% { opacity: 1; } }

.chips { border-top: 1px solid rgba(10,20,38,0.08); padding: 1.1rem 1.5rem; }
.chips-label {
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.16em;
  text-transform: uppercase; color: rgba(61,74,99,0.6);
}
.chips-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.75rem; }
/* The FAQ's four audiences, as small headings over their rows. */
.chips-group {
  margin-top: 1rem; font-size: 0.8125rem; font-weight: 600; color: var(--navy-900);
}
.chips-group + .chips-row { margin-top: 0.5rem; }
.chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  padding: 0.5rem 0.95rem; border-radius: 4px;
  border: 1px solid rgba(10,20,38,0.1);
  background: linear-gradient(180deg, #fff 0%, #eef1f8 100%);
  font: inherit; font-size: 0.875rem; font-weight: 500; color: var(--navy-900);
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  box-shadow: 0 1px 2px rgba(10,20,38,0.05);
}
.chip:hover { transform: translateY(-1px); box-shadow: 0 6px 14px -8px rgba(10,20,38,0.4); }
.chip:disabled { opacity: 0.45; pointer-events: none; }
.chip .plus { color: var(--cobalt); font-weight: 700; }
.chips-done { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; justify-content: space-between; }
.chips-done p { font-size: 0.9375rem; color: var(--body); }
.chips-done a { font-size: 0.9375rem; font-weight: 600; color: var(--cobalt-700); text-decoration: none; border-bottom: 1px solid rgba(35,71,230,0.3); }

/* ---------- Tilt cards ---------------------------------------------------
   The unlumen TiltCard rebuilt without it, because its primitives ship in a package
   this project does not have, and it is written against shadcn tokens that do
   not exist here. Faithful to the original's anatomy:
     · rotationFactor 11 tilt toward the cursor
     · a static 800px circle clipped by the card (NOT a pointer spotlight,
       that was my first pass and it was the wrong effect)
     · scale(1.05) and a deeper shadow on hover
     · a header row: title and summary left, a split pill right
   Only transform and opacity animate, so it stays on the compositor.
   ------------------------------------------------------------------------ */
.tilt-field { perspective: 1000px; }

.tilt {
  position: relative;
  overflow: hidden;                 /* this is what clips the circle */
  transform-style: preserve-3d;
  /* The script sets transition:none while it owns the transform, so this
     governs only the states it is not driving. Shorter than the old 400ms,
     which was long enough to visibly lag the pointer. */
  /* Governs only the box-shadow and the leave/settle glide (the script sets
     transition:none while the pointer-follow owns the transform). Slowed
     alongside the flood so leaving a card is not abrupt next to entering it. */
  transition: transform 420ms cubic-bezier(0.22, 1, 0.36, 1),
              box-shadow 420ms cubic-bezier(0.22, 1, 0.36, 1);
  will-change: transform;
}
.tilt:hover { box-shadow: var(--shadow-lift); }

/* The clipped circle, in navy rather than the original's white. It sits below
   the card at rest and rises to flood it on hover: the dark sweep, in the
   brand colour instead of black. */
.tilt::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 78%;
  width: 800px; height: 800px;
  margin-left: -400px;
  border-radius: 50%;
  /* All three stops stay in the navy family. The depth comes from the lit
     centre, not from crushing the edges toward black. */
  background: radial-gradient(circle at 50% 40%, #1b3f74 0%, #12294f 55%, var(--navy-900) 100%);
  pointer-events: none;
  transform: translateY(0) scale(0.55);
  /* Was 620ms, then 900ms: still read as quick. This is a deliberate wash of
     colour across a card, not a button responding to a click, so it can
     afford to take its time. */
  transition: transform 1400ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* --flood is set per card by the page script (sizeFlood in join.html) so a
   taller card, like "Or propose your own", is covered to its corners too. */
.tilt:hover::before { transform: translateY(-48%) scale(var(--flood, 1.15)); }

/* Hover intent. Every hover-in effect waits HOVER_DELAY before it starts, and
   the delay applies to entering only (the base rules carry none), so leaving
   is still immediate. Sweeping the cursor across the grid no longer sets off
   every card it crosses: a transition cancelled inside its delay never shows.
   Keep in step with DELAY in join.html's tilt script. */
.tilt:hover { transition-delay: 280ms; }
.tilt:hover::before { transition-delay: 280ms; }
.tilt:hover h3,
.tilt:hover li,
.tilt:hover li::before,
.tilt:hover .needs,
.tilt:hover .needs strong { transition-delay: 430ms; }

/* Text has to survive the flood, so it inverts with it. Transitioned on the
   same curve as the circle, a touch faster, so the copy is already light by
   the time the navy reaches it. */
.tilt h3,
.tilt .summary,
.tilt li,
.tilt .needs,
.tilt .needs strong { transition: color 380ms ease; }
/* Given transitions of their own so the hover delay below holds them too;
   without one a delay does nothing and they would snap before the flood. */
.tilt li::before { transition: background-color 380ms ease; }
.tilt .needs { transition: color 380ms ease, background-color 380ms ease, box-shadow 380ms ease; }
.tilt:hover h3 { color: #fff; }
.tilt:hover li { color: rgba(255,255,255,0.82); }
.tilt:hover li::before { background: var(--spark, #2FA8CF); }
.tilt:hover .needs { background: rgba(255,255,255,0.08); box-shadow: none; }
.tilt:hover .needs, .tilt:hover .needs strong { color: rgba(255,255,255,0.9); }

/* Content sits above the circle, on its own layer so the 3D transform does
   not flatten it. */
.tilt > * { position: relative; z-index: 1; }

/* The split pill, from the original's price + badgeLabel. */
.tilt-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1rem; }
/* The original is `flex-1 mr-2` on the text column. Without it the pill
   squeezes the summary and it wraps after three words. min-width:0 is what
   actually lets a flex child shrink below its content width. */
.tilt-head > div { flex: 1; min-width: 0; }
.pill { display: inline-flex; align-items: center; font-size: 0.75rem; font-weight: 600; white-space: nowrap; flex-shrink: 0; }
.pill-a {
  border-radius: 3px 0 0 3px; padding: 0.28rem 0.6rem;
  background: rgba(10, 20, 38, 0.07); color: var(--navy-900);
}
.pill-b {
  border-radius: 0 3px 3px 0; padding: 0.28rem 0.6rem;
  background: rgba(47, 168, 207, 0.18); color: #10627d;
}

/* Touch and reduced motion get the card, not the choreography. */
@media (hover: none), (pointer: coarse), (prefers-reduced-motion: reduce) {
  .tilt, .tilt:hover { transform: none !important; }
  .tilt:hover::before { transform: none; }
}

/* ---------- SiriOrb --------------------------------------------------------
   The smoothui SiriOrb, ported rather than approximated. Its visual is pure
   CSS in the original too: a mesh of conic gradients spun by an @property
   --angle, blurred, with a drifting specular sheen and a lit rim. None of that
   needed React; only the audio-amplitude and state props did, and this use has
   neither. Recoloured from the stock pink/violet into WIKAIR blues.
   -------------------------------------------------------------------------- */
@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.orb {
  --c1: oklch(52% 0.20 264);
  --c2: oklch(70% 0.12 255);
  --c3: oklch(38% 0.14 265);
  --c4: oklch(80% 0.07 262);
  --orb-bg: oklch(93% 0.012 262);
  /* The component derives these from its size; at 30px it lands on blur 1px,
     contrast 1.1, shadow-spread 0.5px, rim 1.8px. A 6px blur on a 30px orb
     averages the whole mesh into one pale disc, which is the failure mode
     these small-size branches exist to avoid. */
  --blur-amount: 1px;
  --contrast-amount: 1.1;
  --shadow-spread: 0.5px;
  --rim: 1.8px;

  display: grid;
  grid-template-areas: "stack";
  place-items: center;
  width: 30px; height: 30px;
  border-radius: 50%;
  overflow: hidden;
  position: relative;
  isolation: isolate;
  flex-shrink: 0;
}
.orb::before,
.orb::after,
.orb > .orb-layer { content: ""; display: block; grid-area: stack; width: 100%; height: 100%; border-radius: 50%; }

/* The mesh. Six conic gradients at different origins, each spun at its own
   multiple of --angle, so the colours never repeat on a fixed cycle. */
.orb::before {
  background:
    conic-gradient(from calc(var(--angle) *  2) at 25% 70%, var(--c3), transparent 20% 80%, var(--c3)),
    conic-gradient(from calc(var(--angle) *  2) at 45% 75%, var(--c2), transparent 30% 60%, var(--c2)),
    conic-gradient(from calc(var(--angle) * -3) at 80% 20%, var(--c1), transparent 40% 60%, var(--c1)),
    conic-gradient(from calc(var(--angle) * 1.5) at 60% 35%, var(--c4), transparent 25% 75%, var(--c4)),
    conic-gradient(from calc(var(--angle) *  1) at 20% 80%, var(--c1), transparent 10% 90%, var(--c1)),
    conic-gradient(from calc(var(--angle) * -2) at 85% 10%, var(--c3), transparent 20% 80%, var(--c3));
  box-shadow: inset var(--orb-bg) 0 0 var(--shadow-spread) calc(var(--shadow-spread) * 0.2);
  /* saturate() is what keeps the colour alive after the blur eats into it. */
  filter: blur(var(--blur-amount)) contrast(var(--contrast-amount)) saturate(1.4);
  animation: orb-rotate 20s linear infinite;
}

/* Drifting highlight, so the sheen never sits still enough to read as a
   printed-on gradient. */
.orb-sheen {
  background:
    radial-gradient(circle at 30% 24%, hsl(0 0% 100% / 0.32), transparent 34%),
    radial-gradient(circle at 72% 80%, hsl(0 0% 100% / 0.07), transparent 48%);
  mix-blend-mode: screen;
  animation: orb-drift 9s ease-in-out infinite alternate;
}

/* Lit top edge, shaded bottom, thin inner ring. This is what makes the mesh
   read as a sphere rather than a flat blurred disc. */
.orb-rim {
  box-shadow:
    inset 0 0 0 1px hsl(0 0% 100% / 0.16),
    inset 0 calc(var(--rim) * 1) calc(var(--rim) * 2) hsl(0 0% 100% / 0.22),
    inset 0 calc(var(--rim) * -1.2) calc(var(--rim) * 2.4) hsl(0 0% 0% / 0.4);
  pointer-events: none;
}

@keyframes orb-rotate { to { --angle: 360deg; } }
@keyframes orb-drift {
  0%   { transform: translate(-6%, -4%) scale(1.05); }
  100% { transform: translate(7%, 6%) scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
  .orb::before, .orb-sheen { animation: none; }
}

/* ---------- touch targets -------------------------------------------------
   Buttons landed at 41px and the file input at 34px, both under the 44px a
   finger needs. Applied only at phone widths so the desktop proportions of
   the buttons are untouched.
   -------------------------------------------------------------------------- */
@media (max-width: 768px) {
  .wk-btn { min-height: 44px; }
  .f-file { min-height: 44px; display: flex; align-items: center; }
  .f-file::file-selector-button { min-height: 34px; }
  .chip { min-height: 44px; }
  /* Inline mail and text links inside body copy, given room to be hit.
     inline-flex rather than padding alone, so the 44px is real height and not
     just visual space that the hit box ignores. */
  .mail, a.addr, .f-status a, .fineprint a, .addr + p a, .routes a {
    display: inline-flex; align-items: center; min-height: 44px;
  }
}

/* Phone layout for Join us, Contact and Donate (the body.wikair-light pages).
   40px gutters took a fifth of a 375px screen from every line of text; 20px
   matches the nav's own side padding on a phone. */
@media (max-width: 600px) {
  body.wikair-light .wk-wrap { padding-inline: 1.25rem; }
  body.wikair-light .wk-section { padding-block: 3.5rem; }
  body.wikair-light .wk-section-first { padding-block: 7.5rem 2.5rem; }
}

/* Home FAQ on a phone. The orb, the gap and an 88% cap left the answer
   text a ~150px column, so a three-paragraph answer ran twenty lines deep.
   The orb shrinks, the bubble takes the rest of the row, and the thread is
   capped by the screen rather than a fixed 26rem so the chips stay in reach. */
@media (max-width: 600px) {
  .ask .wk-wrap { padding-inline: 1.25rem; }
  .ask .thread { padding: 1rem 1rem 0.25rem; height: min(26rem, 62svh); }
  .ask .a-row { gap: 0.5rem; }
  .ask .a-row .orb { width: 22px; height: 22px; }
  .ask .a { max-width: none; flex: 1; min-width: 0; padding: 0.7rem 0.85rem; }
  .ask .q { max-width: 92%; }
  .ask .chips { padding: 1rem; }
  .ask .chip { text-align: left; }
}

/* Role cards on touch. A tap sets :hover and leaves it set, and the old
   reset (transform: none) put the full-size navy circle over the bottom of
   the card with the text still dark. On touch the cards simply stay in
   their resting state. */
@media (hover: none) {
  .tilt:hover { box-shadow: var(--shadow-soft); }
  .tilt:hover::before { transform: translateY(0) scale(0.55); }
  .tilt:hover h3 { color: var(--navy-900); }
  .tilt:hover li, .tilt:hover .own-note { color: var(--body); }
  .tilt:hover li::before { background: var(--cobalt); }
  .tilt:hover .needs { background: var(--clay-sunken); box-shadow: inset 0 1px 3px rgba(10, 20, 38, 0.07); color: var(--body); }
  .tilt:hover .needs strong { color: var(--navy-900); }
}

/* ---------- Opening animation (Join us, Contact, Donate, 404) -------------
   About's fade-up (20-30px rise, 0.8-1s, staggered 0.15s), but played on
   load in CSS rather than waiting on a scroll observer, so the top of the
   page is never an empty sky waiting for an animation. fill-mode both keeps
   each piece hidden only for its own delay; if animations do not run at all,
   everything is simply there. Sections further down reveal as they scroll
   in (.wk-reveal, driven by nav.js). */
@keyframes wk-rise {
  from { opacity: 0; transform: translateY(24px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: no-preference) {
  body.wikair-light .wk-section-first .wk-eyebrow { animation: wk-rise 0.8s ease both; }
  body.wikair-light .wk-section-first .wk-display { animation: wk-rise 1s ease 0.15s both; }
  body.wikair-light .wk-section-first .wk-lead    { animation: wk-rise 1s ease 0.3s both; }
  /* the first block under the header: route cards, form, check card */
  body.wikair-light .routes > :nth-child(1),
  body.wikair-light .contact-grid > :nth-child(1),
  body.wikair-light .give-grid > :nth-child(2) { animation: wk-rise 1s ease 0.45s both; }
  body.wikair-light .routes > :nth-child(2),
  body.wikair-light .contact-grid > :nth-child(2) { animation: wk-rise 1s ease 0.6s both; }
  /* 404 */
  body.wikair-light .lost > * { animation: wk-rise 0.9s ease both; }
  body.wikair-light .lost > :nth-child(2) { animation-delay: 0.1s; }
  body.wikair-light .lost > :nth-child(3) { animation-delay: 0.2s; }
  body.wikair-light .lost > :nth-child(4) { animation-delay: 0.3s; }
  body.wikair-light .lost > :nth-child(5) { animation-delay: 0.4s; }
  body.wikair-light .lost > :nth-child(6) { animation-delay: 0.5s; }
  /* keeps Wika's float running after the rise */
  body.wikair-light .lost > .lost-mascot { animation: wk-rise 0.9s ease both, wk-float 7s ease-in-out 0.9s infinite; }

  .wk-reveal { opacity: 0; transform: translateY(28px); transition: opacity 0.9s ease, transform 0.9s ease; }
  .wk-reveal.is-in { opacity: 1; transform: none; }
}
