/* Wolka — store-facing website.
   Every colour, size, radius and weight below is transcribed from the native app.
   tools/check.mjs rejects anything not present in tools/tokens.mjs.
   Do not add a value here that does not already exist in wolka_mobile/lib/. */

/* Figtree (SIL OFL) is the family bundled with the app, self-hosted here rather than pulled from a
   CDN because netlify.toml pins `font-src 'self'`. Subset to Latin. The four faces are declared
   over the same weight ranges the app's `_face()` maps — 400/500 Regular, 600/700 SemiBold,
   800 ExtraBold, 900 Black — so a 700 or 900 rule resolves to a real face instead of a synthesised
   bold. The shape glyphs the copy uses (○ ♡ ⚔ ✓) are not in the font and fall back to a system
   face, exactly as they do in the app; → is in the font and now renders with the brand face. */
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("assets/fonts/figtree-400.woff2") format("woff2");
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 600 700;
  font-display: swap;
  src: url("assets/fonts/figtree-600.woff2") format("woff2");
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url("assets/fonts/figtree-800.woff2") format("woff2");
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("assets/fonts/figtree-900.woff2") format("woff2");
}

:root {
  --ink: #173c2b;
  --cream: #f7f5eb;
  --lime: #dcef85;
  --orange: #f46f42;
  --muted: #667568;

  --sage: #e9ecdd;
  --sage-alt: #e8ebde;
  --hairline: #dce1d2;
  --outline: #cfd6c7;
  --track: #d3dcc5;
  --track-bar: #dbdfd0;
  --unlock-track: #bcd15b;
  --you-row: #e5edce;
  --you-race: #e5eccc;
  --leader: #edd8a2;
  --locked: #f0eee4;
  --unread: #f1f0e4;
  --avatar-off: #d8decc;
  --filter-on: #d8e5c4;
  --lane-you: #c0d96c;
  --lane-them: #cddf79;
  --lane-tick: #a8be60;
  --lane-line: #8fae53;
  --partial: #ece5d7;
  --err-fill: #ffe8d9;
  --err: #a43b2d;
  --err-off: #d9b7ae;
  --off-bg: #adbdb1;
  --off-fg: #475e50;
  --del: #c62828;
  --del-off: #e3b6b3;
  --del-fg: #5f2421;
  --focus: #d57d49;
  --ink-28: #173c2b47;
  --ink-12: #173c2b1f;

  --font: "Figtree", system-ui, -apple-system, "Segoe UI", sans-serif;
  --gutter: 24px;
  --page: 800px;
  /* Height of the sticky header, kept in step with the two header layouts below. The tab bar sets
     this height, not the wordmark, because its 44px touch target is the taller of the two. */
  --head-h: 69px;
}

*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The header is sticky, so an in-page link used to park its target's first line directly
     underneath it — tapping "See the race" scrolled to a heading you could not see, which reads as
     a tap that did half of its job. Reserve the header's height above every scroll target. */
  scroll-padding-top: calc(var(--head-h) + 16px);
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  margin: 0;
  background: var(--cream);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  font-weight: 400;
  line-height: 1.5;
  overflow-x: hidden;
}

body > main { flex: 1 0 auto; }
body > .site-head, body > .site-foot { flex-shrink: 0; }

img { max-width: 100%; height: auto; display: block; }

a { color: inherit; }

a:not([class]) {
  display: inline-block;
  min-height: 44px;
  padding-block: 12px;
  margin-block: -12px;
}

/* Every unclassed link is given a 44px touch target, and the padding it gains is taken back with a
   negative block margin so it adds no space to the line. That trade is only safe for a link sitting
   in normal flow. As a flex or grid item the same negative margin is real layout, so a wrapping row
   of these links gets its gap cancelled twice over and the rows sit on top of each other. The `.toc`
   chips below are exactly that: a wrapped grid of bubbles. They keep the 44px target and drop the
   refund, so their row gap is a gap again. */
.toc a { padding-block: 12px; min-height: 44px; margin-block: 0; }

:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 4px;
  border-radius: 4px;
}

/* ---------- layout ----------
   Page gutters are the app's 24px. Content width matches the RaceTrack clamp,
   min(screenWidth - 48, 800). Galleries widen to the values the existing
   docs/*.html previews already use. */

.wrap {
  width: 100%;
  max-width: calc(var(--page) + var(--gutter) * 2);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.wrap--wide { --page: 1040px; }
.wrap--gallery { --page: 1160px; }

.section { padding-block: 64px; }
.section--tight { padding-block: 40px; }
.section--airy { padding-block: 96px; }

.rule { height: 1px; background: var(--hairline); border: 0; margin: 0; }

.grid { display: grid; gap: 24px; }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--6 { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 14px; }
.grid--top { align-items: start; }

.stack { display: grid; gap: var(--gap, 16px); }

/* Horizontal overflow strip, the web equivalent of the app's fixed tab bar. */
.rail-x {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 8px;
  margin-inline: calc(var(--gutter) * -1);
  padding-inline: var(--gutter);
}
.rail-x > * { scroll-snap-align: start; flex: 0 0 auto; }

/* ---------- type ---------- */

.wordmark {
  font-size: 32px;
  font-weight: 900;
  letter-spacing: -1.5px;
  margin: 0;
  line-height: 1;
  text-decoration: none;
  padding-block: 6px;
  margin-block: -6px;
}

.display {
  font-size: 82px;
  font-weight: 900;
  letter-spacing: -2px;
  line-height: 1.02;
  margin: 0;
  text-wrap: balance;
}

.display--sm { font-size: 40px; letter-spacing: -1.5px; }
.display--xs { font-size: 34px; letter-spacing: -1px; }
.headline { font-size: 39px; font-weight: 900; letter-spacing: -1.5px; line-height: 1.05; margin: 0; }

.section-h { font-size: 26px; font-weight: 800; line-height: 1.15; margin: 0; }
.sub-h { font-size: 23px; font-weight: 900; line-height: 1.2; margin: 0; }
.sub-h--reg { font-size: 24px; font-weight: 800; }

.lead { font-size: 20px; line-height: 1.45; color: var(--muted); margin: 0; }
.body { font-size: 16px; line-height: 1.6; margin: 0; }
.body--sm { font-size: 15px; font-weight: 600; line-height: 1.55; margin: 0; }
.body--tight { font-size: 14px; line-height: 1.6; margin: 0; }
.caption { font-size: 13px; color: var(--muted); line-height: 1.5; margin: 0; }
.footnote { font-size: 12px; color: var(--muted); line-height: 1.5; margin: 0; max-width: 62ch; }

.eyebrow {
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

/* An eyebrow labels the heading directly beneath it, and it was sitting flush against it — measured
   at 0px in all seven sections, most visibly under "The things people ask first." One adjacent-sibling
   rule rather than a margin on .eyebrow itself, because an eyebrow inside a card or a device frame
   should stay tight to the number or title it belongs to. */
.eyebrow + .section-h { margin-top: 8px; }

.stat-xl { font-size: 82px; font-weight: 900; letter-spacing: -2px; line-height: 1; margin: 0; }
.stat-l { font-size: 46px; font-weight: 900; letter-spacing: -2px; line-height: 1; margin: 0; }
.stat-m { font-size: 30px; font-weight: 900; line-height: 1.05; margin: 0; }
.stat-s { font-size: 20px; font-weight: 900; line-height: 1.1; margin: 0; }

.tnum { font-variant-numeric: tabular-nums; }

.measure { max-width: 62ch; }
.muted { color: var(--muted); }
.ink { color: var(--ink); }
.lime { color: var(--lime); }
.caps { text-transform: lowercase; }

/* ---------- hero and step composition ---------- */

.hero { display: grid; gap: 32px; }
.hero__sub { display: grid; gap: 16px; }
.hero__mark { display: flex; justify-content: flex-start; }
.hero__mark img { width: 108px; height: 108px; }

.steps { display: grid; gap: 24px; align-items: start; }
.step { display: grid; gap: 12px; align-content: start; }

/* ---------- crop frame ----------
   The only element on this site with no app counterpart. It is a viewport crop
   showing real app atoms at real app dimensions. No bezel, notch, status bar,
   home indicator, shadow or reflection, because the app renders none of those. */

.frame {
  border: 1px solid var(--hairline);
  border-radius: 24px;
  background: var(--cream);
  padding: 18px;
  overflow: hidden;
}

/* ---------- navigation ----------
   The header uses the app's own tab bar: same pill, same radius, same weights. */

.site-head {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--cream);
  border-bottom: 1px solid var(--hairline);
}

.site-head__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-block: 12px;
}
.site-head .wordmark { display: inline-flex; align-items: center; min-height: 44px; }

.tabbar {
  display: flex;
  gap: 4px;
  padding: 8px;
  border-top: 1px solid var(--hairline);
}

.tab {
  appearance: none;
  border: 0;
  background: var(--cream);
  color: var(--muted);
  font: inherit;
  font-size: 12px;
  font-weight: 700;
  padding: 12px 14px;
  border-radius: 20px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  /* Taps must not wait on the 300ms click delay. */
  touch-action: manipulation;
  transition: background-color 120ms cubic-bezier(0.33, 1, 0.68, 1),
              color 120ms cubic-bezier(0.33, 1, 0.68, 1);
}
.tab:active {
  /* The press itself must not animate. A transition on the way down is 120ms of the tap feeling
     like it did not register, which is the difference between a page that answers a tap and one
     that appears to hesitate. The release keeps the transition, which is where it reads as spring. */
  transition: none;
  background: var(--track-bar);
  color: var(--ink);
}
.tab--on { background: var(--ink); color: var(--cream); }
.tab--on:active { background: var(--ink); color: var(--cream); }

/* Site nav in the header.
   Above 850px the four tabs sit beside the wordmark and never overflow. Below it they move to
   their own full-width row, because squeezing them next to a 32px wordmark leaves them clipped
   inside a sideways scroller — and a clipped tab behind an `overflow-x` scroller is the jank:
   the touch is held while the browser decides tap-or-swipe, so the click arrives late, a swipe
   meant for the nav drags the page, and the last tab is half off-screen with no scrollbar to
   say so. Owning the row costs ~44px of header height and removes all of it. */
.site-head .tabbar {
  border-top: 0;
  padding: 0;
  flex-wrap: nowrap;
  /* Still a scroller, for viewports too narrow to hold the row even at full width. Touch handling
     is declared here so that fallback scrolls like a tab bar instead of a text selection. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-user-select: none;
  user-select: none;
}
.site-head .tabbar::-webkit-scrollbar { display: none; }

@media (max-width: 850px) {
  :root { --head-h: 117px; }
  .site-head__inner { flex-wrap: wrap; gap: 8px 0; padding-block: 10px; }
  /* The footer wordmark pins its own size inline, so this only affects the header. The refund for
     its padding, margin-block: -6px, is free in the footer but is real layout here: as a flex item
     it ate 12px of the row gap, so an 8px gap rendered as 2px between the title and the tabs. In
     the header the refund is dropped so the gap means what it says. */
  .site-head .wordmark { font-size: 24px; margin-block: 0; }
  .site-head .tabbar { flex: 1 0 100%; }
}

.frame__chrome {
  display: flex;
  gap: 8px;
  align-items: center;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 16px;
}
.frame__chrome .pill { margin-left: auto; }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  padding: 17px 18px;
  border: 0;
  border-radius: 18px;
  background: var(--ink);
  color: var(--cream);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  min-height: 44px;
  transition: background-color 180ms cubic-bezier(0.33, 1, 0.68, 1);
}
.btn--secondary { background: var(--sage); color: var(--ink); }
.btn--orange { background: var(--orange); color: var(--ink); }
.btn--danger { background: var(--err); color: var(--cream); }
.btn--del { background: var(--del); color: var(--white); }
/* The app's null-action button: wolkah_widgets.dart gives a disabled fill of #ADBDB1 and #475E50.
   Reused here so "coming soon" is stated in the app's own language rather than a new treatment. */
.btn--disabled {
  background: var(--off-bg);
  color: var(--off-fg);
  cursor: default;
}
.btn--wide { width: 100%; }
.btn--fit { width: auto; }
.btn[hidden] { display: none; }

/* ---------- pills ---------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  border-radius: 20px;
  background: var(--sage);
  color: var(--ink);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.7px;
  text-transform: lowercase;
  white-space: nowrap;
}
.pill--lime { background: var(--lime); }
.pill--orange { background: var(--orange); }
.pill--ink { background: var(--ink); color: var(--cream); }
.pill--leader { background: var(--leader); }
.pill--cream { background: var(--cream); }

/* ---------- segment chips ---------- */

.seg {
  display: inline-flex;
  padding: 12px 18px;
  border: 0;
  border-radius: 22px;
  background: var(--sage-alt);
  color: var(--ink);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  min-height: 44px;
}
.seg--on { background: var(--ink); color: var(--cream); }
.seg-group { display: flex; flex-wrap: wrap; gap: 8px; }

/* ---------- fields ---------- */

.field {
  display: block;
  background: var(--sage);
  border-radius: 14px;
  padding: 16px;
}
.field__label { font-size: 14px; font-weight: 700; margin: 0 0 8px; }
.field__value { font-size: 16px; margin: 0; }
.field__value--placeholder { color: var(--muted); }

/* ---------- cards ---------- */

.card { border-radius: 24px; padding: 18px; }
.card--sm { border-radius: 16px; padding: 16px; }
.card--sage { background: var(--sage); }
.card--lime { background: var(--lime); }
.card--ink { background: var(--ink); color: var(--cream); border-radius: 24px; padding: 24px; }
.card--ink .caption,
.card--ink .footnote { color: var(--lime); }
.card--locked { background: var(--locked); }
.card--you { background: var(--you-row); }
.card--partial { background: var(--partial); }
/* The two download cards hold different amounts of copy — the iPhone blurb runs a line longer than
   the Android one — so in a stretched grid the shorter card's button floated up and the two CTAs
   landed on different lines. As a column with the body absorbing the slack, both buttons are pinned
   to the card's foot, which is one line across the row again. */
.card--cta { display: flex; flex-direction: column; }
.card--cta > .body { flex: 1 0 auto; }

/* ---------- notices ---------- */

.notice {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px;
  border-radius: 16px;
  background: var(--sage);
  color: var(--ink);
}
.notice__body { font-size: 14px; margin: 0; }
.notice--error { background: var(--err-fill); color: var(--err); }
.notice--success { background: var(--lime); color: var(--ink); }

/* ---------- progress ---------- */

.bar { height: 8px; border-radius: 4px; background: var(--track-bar); overflow: hidden; }
.bar--thin { height: 6px; border-radius: 3px; }
.bar__fill { height: 100%; background: var(--ink); border-radius: 4px; }
.bar--thin .bar__fill { border-radius: 3px; }

.unlock-track {
  position: relative;
  height: 32px;
  display: flex;
  align-items: center;
}
.unlock-track::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  height: 7px;
  border-radius: 4px;
  background: var(--unlock-track);
}
.unlock-track__fill {
  position: absolute;
  left: 0;
  height: 7px;
  border-radius: 4px;
  background: var(--ink);
}
.unlock-track__dot {
  position: relative;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--cream);
  flex: 0 0 auto;
}

/* ---------- standings rows ---------- */

.standings { display: grid; gap: 4px; }
.standings__row {
  display: grid;
  grid-template-columns: 26px 40px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 14px 10px;
  border-radius: 16px;
  background: var(--cream);
}
.standings__row--me { background: var(--you-race); }
.standings__name { font-size: 16px; font-weight: 700; margin: 0; }
.standings__sub { font-size: 11px; color: var(--muted); margin: 0; }
.place { font-size: 18px; font-weight: 800; text-align: center; margin: 0; }
.place--1 { font-size: 44px; font-weight: 900; letter-spacing: -1.5px; }
.place--2 { font-size: 38px; font-weight: 900; letter-spacing: -1.5px; }
.place--3 { font-size: 32px; font-weight: 900; letter-spacing: -1.5px; }
.place--n { font-size: 26px; font-weight: 900; letter-spacing: -1.5px; }

/* ---------- avatars, emblems, pips ---------- */

.avatar { width: 44px; height: 44px; }
.avatar--portrait { width: 26px; height: 26px; }
.avatar--crew-row { width: 36px; height: 36px; }
.avatar--walk { width: 40px; height: 48px; }
.avatar--lg { width: 88px; height: 88px; }
.avatar--xl { width: 108px; height: 108px; }
.avatar--badge { width: 64px; height: 64px; }

.emblem { width: 68px; height: 68px; }
.emblem--lg { width: 104px; height: 104px; }
.emblem--sm { width: 48px; height: 48px; }
.pips { width: 64px; height: 14px; }
.pips--lg { width: 88px; height: 18px; }

/* ---------- ranked card row ---------- */

.rankrow { display: flex; gap: 12px; align-items: center; }
.rankrow__id { flex: 1 1 100px; min-width: 0; }

/* ---------- race track ----------
   Faithful translation of RaceLanePainter (race_track.dart:399-441) in CSS. */

.track { display: grid; gap: 18px; }

.lane { display: grid; gap: 6px; }
.lane__head { display: flex; align-items: baseline; gap: 8px; }
.lane__place { font-size: 11px; font-weight: 900; }
.lane__name { font-size: 14px; font-weight: 800; }
.lane__total { font-size: 14px; font-weight: 900; margin-left: auto; font-variant-numeric: tabular-nums; }
.lane__note { font-size: 11px; color: var(--muted); margin: 0; }

.lane__bar {
  position: relative;
  height: 22px;
  border-radius: 11px;
  background: var(--lane-you);
  overflow: visible;
}
.lane__bar--them { background: var(--lane-them); }
.lane__bar::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 11px;
  background-image: repeating-linear-gradient(
    to right,
    var(--lane-tick) 0 2px,
    transparent 2px 14px
  );
  opacity: 0.55;
}
.lane__line {
  position: absolute;
  top: -3px;
  bottom: -3px;
  left: 0;
  width: 4px;
  border-radius: 2px;
  background: var(--lane-line);
}
.lane__avatar {
  position: absolute;
  top: -13px;
  width: 26px;
  height: 26px;
  transform: translateX(-50%);
}
.lane__avatar img { width: 26px; height: 26px; }

.ruler {
  display: flex;
  justify-content: space-between;
  font-size: 10px;
  font-weight: 700;
  color: var(--muted);
  border-top: 1px solid var(--track);
  padding-top: 8px;
}

/* ---------- challenge rail ---------- */

.rail {
  position: relative;
  height: 18px;
  border-left: 4px solid var(--track);
  border-right: 4px solid var(--track);
}
.rail__fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 4px;
  background: var(--ink);
}
.rail__fill--host { background: var(--orange); }
.rail__pin {
  position: absolute;
  top: 50%;
  width: 8px;
  height: 8px;
  background: var(--ink);
  transform: translate(-50%, -50%) rotate(45deg);
}

/* ---------- wolks bar chart ---------- */

.bars { display: flex; align-items: flex-end; gap: 6px; height: 100px; }
.bars__col { flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.bars__bar { width: 22px; border-radius: 8px; background: var(--ink); min-height: 4px; }
.bars__bar--partial { background: var(--orange); }
.bars__bar--none { background: var(--sage); }
.bars__label { font-size: 10px; color: var(--muted); }

/* ---------- mascot ---------- */

.mascot { width: 76px; height: 76px; }
.mascot--48 { width: 48px; height: 48px; }
.mascot--108 { width: 108px; height: 108px; }
.mascot--locked { opacity: 0.4; }
.mascot-strip { display: flex; gap: 6px; justify-content: center; align-items: flex-end; }

/* ---------- result cards ---------- */

.result { border-radius: 24px; padding: 20px; }
.result--win { background: var(--ink); color: var(--cream); }
.result--draw { background: var(--lime); color: var(--ink); }
.result--loss { background: var(--partial); color: var(--ink); }
.result__headline { font-size: 25px; font-weight: 900; line-height: 1.1; margin: 0; }

/* ---------- ladders ---------- */

.ladder { display: grid; gap: 14px; }
.ladder__specimen {
  padding: 14px 4px 20px;
  text-align: center;
  border-bottom: 1px solid var(--hairline);
}
.ladder__name { font-size: 20px; font-weight: 800; margin: 12px 0 0; }
.ladder__rp { font-size: 12px; color: var(--muted); margin: 6px 0 0; }
.ladder__rp--sm { font-size: 10px; }

/* ---------- achievement families ---------- */

.family {
  display: grid;
  gap: 10px;
  padding: 16px;
  border-radius: 20px;
  background: var(--sage);
}
.family--locked { background: var(--locked); }
.family__head { display: flex; gap: 16px; align-items: center; }
.family__name { font-size: 18px; font-weight: 800; margin: 0; }
.family__rule { font-size: 13px; color: var(--muted); margin: 0; }
.family__tiers { display: flex; flex-wrap: wrap; gap: 8px; }
.family__tier {
  font-size: 12px;
  font-weight: 700;
  padding: 7px 11px;
  border-radius: 20px;
  background: var(--cream);
  color: var(--muted);
}
.family__tier--earned { background: var(--lime); color: var(--ink); }

/* ---------- avatar picker ---------- */

.picker { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.picker__tile {
  display: grid;
  justify-items: center;
  gap: 4px;
  padding: 8px 4px;
  border-radius: 16px;
  background: var(--cream);
  border: 1px solid var(--hairline);
  font-size: 10px;
  font-weight: 700;
  color: var(--muted);
}
.picker__tile--on { background: var(--you-row); border: 2px solid var(--ink); color: var(--ink); }
.picker__tile--taken { opacity: 0.4; }
.picker--dense { grid-template-columns: repeat(8, minmax(0, 1fr)); }

/* ---------- questions ---------- */

details summary { cursor: pointer; list-style: none; min-height: 44px; }
details summary::-webkit-details-marker { display: none; }
details summary::after { content: " +"; float: right; font-weight: 800; }
details[open] summary::after { content: " \2212"; }
details[open] summary { margin-bottom: 0; }

/* ---------- footer ---------- */

.site-foot {
  border-top: 1px solid var(--hairline);
  padding-block: 40px;
  margin-top: 40px;
}
.site-foot > .wrap { display: flex; flex-direction: column; align-items: flex-start; gap: 16px; }
.site-foot > .wrap > * { margin: 0; }
.site-foot__links { display: flex; flex-wrap: wrap; gap: 8px 24px; }
.site-foot__links a { display: inline-flex; align-items: center; min-height: 44px; }
.site-foot .footnote { overflow-wrap: anywhere; }
.site-foot a { font-size: 13px; font-weight: 700; text-decoration: none; }

.link-list { display: grid; gap: 12px; padding: 0; margin: 0; list-style: none; }
.link-list a { font-size: 14px; font-weight: 700; text-decoration: none; }

/* ---------- prose (legal pages) ---------- */

.prose { display: grid; gap: 20px; }
.prose h2 { font-size: 24px; font-weight: 800; margin: 24px 0 0; }
.prose h3 { font-size: 18px; font-weight: 800; margin: 0; }
.prose p { margin: 0; font-size: 15px; line-height: 1.65; }
.prose ul { margin: 0; padding-left: 20px; font-size: 15px; line-height: 1.65; }
.prose li + li { margin-top: 6px; }
.toc { display: flex; flex-wrap: wrap; gap: 8px; }
.toc a {
  font-size: 12px;
  font-weight: 700;
  text-decoration: none;
  padding: 8px 12px;
  border-radius: 18px;
  background: var(--sage);
}

/* ---------- touch feedback ----------
   Tapping a button used to flash a grey rectangle across it and then appear to stall, because iOS
   and Android both paint their own tap highlight and neither was turned off. The browser highlight
   is removed site-wide and the pressed states are the only highlight left.

   Hover is confined to devices with a real pointer. On a touch screen :hover latches on tap and
   stays until you tap elsewhere, so a hovered link or tab reads as permanently selected — a stuck
   state that looks exactly like a broken button. */

a,
button,
summary,
[role="button"] {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

@media (hover: hover) {
  .tab:hover { background: var(--track-bar); color: var(--ink); }
  .tab--on:hover { background: var(--ink); color: var(--cream); }
  .toc a:hover { background: var(--filter-on); }
  .site-foot a:hover { text-decoration: underline; }
  .link-list a:hover { text-decoration: underline; }
}

/* Smooth scrolling is for a pointer that can watch it. On a touch screen an in-page link gets a
   seatbelt of animation between the tap and the destination, so the page appears to glide instead
   of answering. It stays on desktop and stays off for anyone who asked for reduced motion. */
@media (hover: none) {
  html { scroll-behavior: auto; }
}

/* ---------- live totals ----------
   The two figures on the landing page. The type size steps with the number's magnitude, which is the
   web equivalent of the app's leaderboardPositionSize(): discrete registered sizes, never a
   continuous scale, so every value renders at one of the type sizes in the scale. The base class
   carries the largest; the two below are applied by assets.js as the digits grow. */

.totals__n {
  margin-top: 8px;
  font-variant-numeric: tabular-nums;
  overflow-wrap: normal;
  word-break: keep-all;
}
/* Two ladders, because the figures are not peers. The all-time total is the section's headline and
   starts at display size; today and this week are supporting figures and start two steps below.
   Each ladder then steps down as its own digits grow, which is the app's FittedNumber behaviour
   applied to magnitude rather than to measured width. */
.totals__n--lg { font-size: 82px; font-weight: 900; letter-spacing: -2px; line-height: 1; margin: 8px 0 0; }
.totals__n--md { font-size: 46px; font-weight: 900; letter-spacing: -2px; line-height: 1; margin: 8px 0 0; }
.totals__n--sm { font-size: 30px; font-weight: 900; line-height: 1.05; margin: 8px 0 0; }

/* The all-time figure is a deliberate exception to the type scale, and this is how it is expressed.
   The app's FittedNumber scales a total to the width of its slot; here that same measurement is used
   in the other direction, so the one number that carries the whole section spans it. The size is a
   ratio of the card's own inline size in cqw, written by assets.js from a real measurement, so it is
   not a px value at all and tools/check.mjs has no reason to reject it — the check scans px in both
   the stylesheet and inline styles, and a percentage-of-container is not a step on the scale.
   WOLKA_WEB_PLAN.md §3 records the exception and why. */
/* No card, no fill, no border: the all-time figure sits straight on the page, because a container
   around it was one more box competing with the number for attention. The only thing this class does
   is declare a query container so the figure can be fitted to the full width below it. */
.totals__hero { container-type: inline-size; }
.totals__hero .totals__n {
  font-size: calc(var(--fit, 20) * 1cqw);
  font-weight: 900;
  letter-spacing: -2px;
  line-height: 1;
  margin: 0;
}

.totals__stamp { color: var(--muted); }

/* ---------- visual landing compositions ----------
   The existing app palette and controls, arranged around the walkers. Live-total
   typography and fitting stay independent of these compositions. */
.landing-hero { display: grid; grid-template-columns: 1.15fr 1fr; gap: 32px; align-items: center; }
.landing-hero__copy { display: grid; gap: 24px; justify-items: start; }
.landing-actions { display: flex; gap: 24px; align-items: center; flex-wrap: wrap; }
.landing-hero__art { position: relative; isolation: isolate; display: grid; place-items: center; }
.landing-hero__disc { position: absolute; width: 90%; aspect-ratio: 1; border-radius: 50%; background: var(--lime); z-index: -1; }
.landing-mascot { width: 100%; height: auto; transform: rotate(-6deg); }
.landing-hero__tag { position: absolute; bottom: 6%; right: 0; transform: rotate(6deg); }
.crew-scene { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; align-items: center; padding: 32px; background: var(--sage); border-radius: 30px; }
.crew-scene__copy { display: grid; gap: 16px; justify-items: start; }
.crew-scene__art { display: grid; gap: 16px; justify-items: center; }
.crew-scene__walkers { display: flex; flex-direction: row; flex-wrap: nowrap; gap: 4px; align-items: end; justify-content: center; width: 100%; min-height: 180px; }
.crew-scene__walkers img { max-width: 30%; height: auto; }
.crew-scene__walkers img:nth-child(2) { max-width: 38%; }
.crew-choices { display: flex; gap: 8px; }
.crew-choice { display: grid; place-items: center; padding: 4px; border: 2px solid transparent; border-radius: 16px; background: var(--cream); cursor: pointer; }
.crew-choice[aria-pressed="true"] { border-color: var(--ink); background: var(--you-row); }
.crew-choice:hover { background: var(--you-row); }
.win-scene { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; align-items: center; }
.win-scene > div { display: grid; gap: 16px; justify-items: start; }
.win-scene > img { width: 100%; max-width: 320px; justify-self: center; height: auto; }
.landing-download { display: grid; gap: 24px; justify-items: center; text-align: center; }
.day-one-note { display: flex; align-items: center; gap: 12px; max-width: 100%; text-align: left; }
.day-one-note > img { width: 44px; height: 44px; flex: 0 0 44px; }
.landing-trust { display: flex; flex-wrap: wrap; justify-content: center; gap: 16px; font-size: 13px; color: var(--muted); margin-top: 16px; }
@media (max-width: 850px) {
  .landing-hero { grid-template-columns: 1fr; gap: 24px; }
  .landing-hero__copy { gap: 20px; }
  .landing-hero__art { max-width: 320px; width: 100%; justify-self: center; }
  .crew-scene { grid-template-columns: 1fr; padding: 24px; gap: 24px; }
  .crew-scene__art { width: 100%; max-width: 320px; justify-self: center; }
  .win-scene { grid-template-columns: 1fr; gap: 24px; }
  .win-scene > img { max-width: 240px; }
}

/* ---------- responsive ----------
   The app branches at ~350 / 380 / 390 / 850 / 1160. The site reuses those. */

@media (max-width: 1160px) {
  .grid--6 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 850px) {
  .grid--2,
  .grid--3 { grid-template-columns: 1fr; }
  .section { padding-block: 48px; }
  .section--airy { padding-block: 64px; }
  .display { font-size: 48px; }
  .stat-xl { font-size: 48px; }
  .stat-l { font-size: 46px; }
  /* The totals ladder is clamped on a phone so an eight-figure all-time total still fits its card. */
  /* Monotonic and every value registered: 44 / 40 / 30, against 82 / 46 / 30 above. */
  .totals__n--lg { font-size: 44px; }
  .totals__n--md { font-size: 40px; }
}

@media (max-width: 390px) {
  :root { --gutter: 16px; }
  .rankrow { flex-wrap: wrap; }
  .rankrow__id { flex: 1 1 100%; }
  .display { font-size: 40px; }
  .headline { font-size: 34px; }
  .grid--6 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .picker { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .frame { padding: 14px; }
  .standings__row { grid-template-columns: 22px 34px 1fr auto; gap: 8px; }
  .tab { padding: 12px 10px; }
}

/* ---------- motion ---------- */

@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;
  }
}

/* Keep the compact download page footer at the viewport bottom. */
.download-page { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; }
.download-page > main { flex: 1 0 auto; }

/* Landing page phone rhythm: compact header-to-intro, generous copy-to-art gaps.
   Keep the crew illustration horizontal independently of the surrounding grid. */
@media (max-width: 850px) {
  .landing-page main > .section--airy:first-child { padding-top: 32px; padding-bottom: 48px; }
  .landing-hero { gap: 40px; }
  .landing-hero__copy { gap: 24px; }
  .landing-actions { width: 100%; flex-direction: column; align-items: stretch; gap: 12px; }
  .landing-actions > a { min-height: 44px; display: flex; align-items: center; justify-content: center; }
  .landing-hero__art { max-width: 288px; }
  .crew-scene { gap: 40px; }
  .crew-scene__copy { gap: 20px; }
  .crew-scene__art { gap: 24px; min-width: 0; }
  .crew-scene__walkers { gap: 8px; min-height: 0; align-items: end; }
  .crew-scene__walkers img { width: 28%; max-width: none; flex: 0 1 28%; }
  .crew-scene__walkers img:nth-child(2) { width: 36%; max-width: none; flex-basis: 36%; }
  .win-scene { gap: 32px; }
  .win-scene > div { gap: 20px; }
  .win-scene a, .crew-scene__copy a { min-height: 44px; display: flex; align-items: center; }
  .landing-download { gap: 32px; }
  .landing-download > .btn { width: 100%; }
  .landing-download .display--sm { font-size: 40px; }
  .landing-trust { gap: 12px 20px; margin-top: 0; }
  .landing-trust > a { flex-basis: 100%; min-height: 44px; display: flex; align-items: center; justify-content: center; }
}
@media (min-width: 360px) and (max-width: 850px) {
  .landing-hero .display { font-size: 48px; }
}

/* Organizer authoring follows the existing field, card and button vocabulary. */
.organizer-login { max-width: 560px; margin-top: 24px; }
.organizer-field { display: grid; gap: 8px; font-size: 14px; font-weight: 700; margin-bottom: 18px; min-width: 0; }
.organizer-field input, .organizer-field textarea, .organizer-field select { font: inherit; font-size: 16px; color: var(--ink); background: var(--cream); border: 1px solid var(--outline); border-radius: 16px; padding: 14px; width: 100%; min-width: 0; box-sizing: border-box; }
.organizer-field textarea { min-height: 120px; resize: vertical; }
.organizer-field input:focus-visible, .organizer-field textarea:focus-visible, .organizer-field select:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.organizer-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 32px; align-items: start; }
.organizer-preview { position: sticky; top: calc(var(--head-h) + 24px); overflow-wrap: anywhere; }
.organizer-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-block: 24px; }
.organizer-actions .btn { width: auto; }
.organizer-section { border: 0; border-top: 1px solid var(--outline); padding: 24px 0; margin: 0; min-width: 0; }
.organizer-section legend { font-size: 20px; font-weight: 800; padding: 0 12px 0 0; }
.event-artwork { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: 18px; margin-bottom: 18px; }
.event-logo { display: block; width: 56px; height: 56px; object-fit: contain; border-radius: 16px; margin-bottom: 12px; }
.organizer-field input[type="checkbox"] { width: 24px; height: 24px; }
.organizer-events { display: grid; gap: 16px; margin-block: 24px; }
.organizer-events .btn { text-align: left; overflow-wrap: anywhere; }
@media (max-width: 760px) { .organizer-layout { grid-template-columns: minmax(0, 1fr); } .organizer-preview { position: static; } .organizer-actions .btn { width: 100%; } }

/* Related text gets deliberate space; type atoms intentionally have no margins. */
.organizer-copy { display: flex; flex-direction: column; align-items: stretch; gap: 16px; }
.organizer-copy > .eyebrow + .section-h { margin-top: 0; }
.organizer-copy > .eyebrow { margin-bottom: -4px; }
.organizer-copy > .grid { margin-top: 8px; }
.organizer-copy > .btn { margin-top: 8px; align-self: flex-start; }
.organizer-copy > .btn + .caption { margin-top: -4px; }
.organizer-page .card--lime.organizer-copy { padding: 24px; }
.organizer-hero { gap: 20px; }
.organizer-hero > .eyebrow { margin-bottom: -4px; }
.organizer-hero > .body { max-width: 62ch; }
.organizer-hero > .caption { max-width: 62ch; }
.organizer-hero > .btn + .caption { margin-top: -8px; }
.organizer-login > .caption { margin-block: 16px; }
.organizer-login > .btn { margin-top: 8px; }
.organizer-preview > * + * { margin-top: 16px; }
.organizer-preview > .event-artwork, .organizer-preview > .event-logo { margin-bottom: 0; }
@media (max-width: 760px) {
  .organizer-page .grid--2 { gap: 32px; }
  .organizer-copy > .btn { align-self: stretch; }
}

/* Event surfaces share one text rhythm instead of relying on zero-margin atoms. */
.events-page { display: flex; flex-direction: column; gap: 64px; padding-bottom: 64px; }
.events-intro { padding-top: 64px; }
.event-copy { display: flex; flex-direction: column; align-items: stretch; gap: 16px; min-width: 0; }
.event-copy > .eyebrow + .section-h { margin-top: 0; }
.event-copy > .btn { align-self: flex-start; margin-top: 8px; }
.event-copy > .grid { margin-top: 8px; }
.event-hero { gap: 20px; }
.event-hero > .lead, .event-hero > .body { max-width: 62ch; }
.events-feedback { padding: 24px; border-radius: 18px; background: var(--sage); }
.events-feedback[hidden] { display: none; }
.events-feedback > .btn { margin-top: 0; }
.event-card { padding: 24px; overflow-wrap: anywhere; }
.event-card > .event-artwork { margin-bottom: 0; }
.event-card > .btn { margin-top: auto; align-self: stretch; }
.events-host-section { border-top: 1px solid var(--hairline); padding-top: 40px; }
.events-host-copy { max-width: 62ch; }
@media (max-width: 850px) {
  .events-page { gap: 48px; padding-bottom: 48px; }
  .events-intro { padding-top: 40px; }
  .events-page .grid--2 { gap: 24px; }
}

.organizer-remember { display: flex; align-items: center; gap: 12px; min-height: 44px; font-size: 14px; }
