:root {
  /* ── Palette ──────────────────────────────────────────────────────────
     Warm paper and vermilion, after the Gofé reference (docs/design/).
     Replaced a near-black shell with a gold accent.

     The six legacy token names are kept deliberately: every component in
     components.css and views.css already reads colour through them, so
     redefining them here re-skins the app without touching component CSS. */

  /* Ground */
  --paper: #F6EDDD;
  --paper-raised: #FFFAF0;
  --paper-sunk: #EADFC9;

  /* Ink, never pure black; the warmth is the point.
     --ink-soft was #6E6255, which measured 4.50:1 on --paper-sunk: AA by
     rounding alone, and the reaction chips and leaderboard ", " rows sit on
     exactly that ground. Four units darker clears it at 4.72 without reading
     as a different grey. */
  --ink: #211C16;
  --ink-soft: #6A5F52;

  /* The one hot accent. It earns attention by being rare, so it is used for
     headings, scores and active state.
     Vermilion is two tokens because a fill and a letterform need different
     things from it (measured Phase 14):

       --vermilion       a FILL carrying a cream label. Was #D6431B, where
                         --paper-raised measured 4.31:1, under AA for every
                         button label in the app, all of which are 13–16px.
                         2.6% darker puts the same label at 4.62:1.
       --vermilion-text  vermilion as a LETTERFORM under 24px. The fill colour
                         reads 4.62 / 4.13 / 3.64 on the three papers, so it
                         cannot double as body text. This clears 4.5 on all
                         three papers and on the four leaderboard tints, worst
                         case 4.71:1, and stays lighter than --vermilion-deep
                         so hover still visibly darkens. */
  --vermilion: #CE401A;
  --vermilion-text: #AC3616;
  --vermilion-deep: #A8330F;

  /* Data colours only, score categories and movement, never chrome.
     --sage-text is the same relationship as vermilion's: --sage is a ramp
     stop and a wash, and at 4.01:1 it was failing as the leaderboard ticker's
     "▲" label. The text variant clears 4.5 on every ground it lands on. */
  --sage: #5F7047;
  --sage-text: #54633F;
  --clay: #B0632C;
  --sky: #4E7FA6;

  /* Antique gold, reserved for awards. Deliberately deep rather than bright:
     #FFD700 sat at 1.21:1 on paper, whereas this carries a paper-coloured
     icon knocked out of it at 4.7:1. Gold is the reward accent, vermilion
     stays the app accent, so a medal never looks like a button. */
  --gold: #96681A;
  --gold-wash: rgba(150, 104, 26, 0.10);

  /* Podium metals for leaderboard ranks 1–3. Darkened from the usual
     #C0C0C0 / #CD7F32, which measure 1.6:1 and 2.6:1 on paper; these are
     4.87:1 and 5.99:1 against a card, so a rank numeral stays readable while
     still reading as silver and bronze. */
  --silver: #6E6E73;
  --bronze: #8A5423;

  /* One shape for every review photo, cropped to fill, uniform down the feed
     with no letterbox bars. Change this single value to restyle every photo
     in the app at once (4 / 5 for a taller, more photo-forward feed). */
  --photo-aspect: 1 / 1;

  /* Hairlines and overlays. On paper these are ink-based; the old values
     were white-on-dark and vanish on a light ground. */
  --hairline: rgba(33, 28, 22, 0.10);
  --hairline-strong: rgba(33, 28, 22, 0.18);
  --wash: rgba(33, 28, 22, 0.04);
  --wash-strong: rgba(33, 28, 22, 0.07);

  /* ── Legacy aliases, what the rest of the CSS actually reads ───────── */
  --bg-color: var(--paper);
  --bg-surface: var(--paper-raised);
  --bg-elevated: var(--paper-raised);
  --text-primary: var(--ink);
  --text-secondary: var(--ink-soft);

  --brand: var(--vermilion);
  --brand-hover: var(--vermilion-deep);

  /* Spacing scale */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 10px;
  --space-4: 12px;
  --space-5: 14px;
  --space-6: 16px;
  --space-7: 18px;
  --space-8: 20px;
  --space-9: 24px;
  --space-10: 28px;
  --space-11: 32px;

  /* Radius scale */
  --radius-xs: 4px;
  --radius-sm: 8px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-pill: 99px;

  /* Elevation, paper wants a hairline, not a glow. These were tuned for a
     near-black ground (card shadow at 40–60% black) and read as grime on
     cream, so they drop to a soft warm lift. Components lean on --hairline
     for definition instead. */
  --shadow-brand-sm: 0 2px 8px rgba(206, 64, 26, 0.14);
  --shadow-brand-md: 0 4px 14px rgba(206, 64, 26, 0.16);
  --shadow-brand-lg: 0 8px 22px rgba(206, 64, 26, 0.20);
  --shadow-card: 0 2px 10px rgba(90, 74, 58, 0.10);
  --shadow-card-press: 0 1px 4px rgba(90, 74, 58, 0.16);

  /* Z-index scale */
  --z-base: 1;
  --z-nav: 10;
  --z-fab: 100;
  --z-sheet: 300;

  /* ── Shell metrics ────────────────────────────────────────────────────
     The nav is a floating pill, so three separate things have to agree on
     where its top edge is: the pill itself, the FAB that sits above it, and
     the scroll padding that stops content hiding behind it. Those were three
     hardcoded numbers (80px / 100px / 96px) that already disagreed, the bar
     grew by env(safe-area-inset-bottom) on a notched phone while the scroll
     padding stayed at a flat 100px, so the last card sat under the nav.
     One source of truth instead. */
  --nav-inset: 12px;            /* gap between pill and viewport bottom */
  --nav-height: 62px;
  --nav-clearance: calc(var(--nav-inset) + var(--nav-height) + env(safe-area-inset-bottom, 0px));

  /* Motion */
  --ease-out-quint: cubic-bezier(0.16, 1, 0.3, 1);
  --duration-fast: 0.18s;
  --duration-base: 0.3s;
  --duration-slow: 0.4s;

  /* Display voice: geometric, monoline, squared terminals, the closest
     common face to the Gofé reference. Body: Outfit, whose circular geometry
     matches the reference's menu type far better than Inter did. */
  --font-display: 'Space Grotesk', 'Outfit', sans-serif;
  --font-body: 'Outfit', system-ui, sans-serif;
  /* Retained: --font-logo is referenced across components.css and views.css. */
  --font-logo: var(--font-display);
  
  --transition: var(--duration-base) var(--ease-out-quint);

  /* ── Type scale ───────────────────────────────────────────────────────
     The CSS had 18 distinct font sizes between 9px and 64px, assigned
     ad-hoc. That absence of a scale is a large part of why the app read as
     utilitarian. These are the sizes worth having; existing rules are
     migrated onto them as each view is reworked. */
  --text-display: 30px;   /* view titles, wordmark-scale headings */
  --text-title: 22px;     /* section titles */
  --text-heading: 17px;   /* card titles, dialogue headings */
  --text-body: 15px;
  --text-meta: 13px;      /* secondary lines, timestamps */
  --text-label: 11px;     /* uppercase eyebrows */

  /* Display type wants negative tracking; small uppercase labels want
     positive. Applying these consistently is most of the "designed" feel. */
  --tracking-display: -0.02em;
  --tracking-label: 0.08em;
}

/* ── Display voice ─────────────────────────────────────────────────────
   Space Grotesk at weight 700 with tight tracking, after the Gofé menus.
   Applied to real headings so new markup inherits it without opting in. */
h1, h2, h3.lb-card-name.view-title {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--tracking-display);
  line-height: 1.15;
}

/* The signature device from the reference: a section heading sitting on a
   thin rule. Cheap, distinctive, and it does the job an icon usually gets
   asked to do. */
.section-heading {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--text-title);
  letter-spacing: var(--tracking-display);
  color: var(--vermilion);
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-6);
  border-bottom: 1.5px solid var(--vermilion);
}

/* A section heading with something on the right, a "View all". The rule
   belongs to the row rather than the heading, so it still spans the full
   width instead of stopping under the words. */
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-3);
  margin-bottom: var(--space-6);
  border-bottom: 1.5px solid var(--vermilion);
}

.section-head .section-heading {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: none;
}

.section-view-all {
  flex: 0 0 auto;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-body);
  font-size: var(--text-meta);
  font-weight: 600;
  color: var(--vermilion-text);
}

.section-view-all:hover {
  color: var(--vermilion-deep);
  text-decoration: underline;
}

/* Small uppercase eyebrow, the counterpart to the display voice. */
.eyebrow {
  font-family: var(--font-body);
  font-size: var(--text-label);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--ink-soft);
}

/* Scores are compared down a column, so they must not shift width between
   values. Applies wherever a numeral is doing data work. */
.lb-score.lb-rank.activity-score-pill.detail-score-value,
.score-value.stat-value, [class*="-score-val"] {
  font-variant-numeric: tabular-nums;
  font-feature-settings: 'tnum' 1;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: var(--font-body);
  background: var(--bg-color);
  color: var(--text-primary);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  overflow: hidden; /* disable main scroll, allow in containers */
}

/* Browsers never inherit font-family into form controls, and only inputs were
   given one, so every button, tab, chip and pill in the app (16 distinct
   kinds) was rendering in Arial. That alone made the typography read as
   off-reference regardless of what the headings were doing. */
button, select, optgroup {
  font-family: var(--font-body);
}

/* Base Inputs */
input, select, textarea {
  width: 100%;
  background: var(--paper-raised);
  /* A transparent border was invisible against a dark ground anyway; on
     paper a field needs a real edge to read as a field. */
  border: 1px solid var(--hairline);
  color: var(--text-primary);
  padding: var(--space-5) var(--space-6);
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-size: 16px;
  margin-bottom: var(--space-8);
  outline: none;
  transition: border-color var(--transition);
}

input:focus, select:focus, textarea:focus {
  border-color: var(--brand);
}

.btn-primary {
  width: 100%;
  padding: var(--space-6);
  background: var(--brand);
  /* Was #121212, which relied on the old gold accent being light. Vermilion
     needs light text: ink on vermilion fails contrast badly. */
  color: var(--paper-raised);
  border: none;
  border-radius: var(--radius-pill);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.2s ease;
}

.btn-primary:active { transform: scale(0.97); }

/* ── Reduced motion ───────────────────────────────────────────────────────
   Before Phase 14 exactly one thing honoured this: the leaderboard ticker.
   Everything else, the view fade, the action sheet, the What's New and
   awards panels, the Rate It stamp press, both skeleton pulses, and every
   transition in the app, kept moving.

   Durations collapse rather than animations being removed, because most of
   the motion here is an *entrance*: `fadeIn ... forwards` ends at opacity 1,
   so a 0.01ms run lands on the intended final state instantly. Deleting the
   animation instead would leave those panels stuck at their opening frame,
   which is opacity 0, a reduced-motion setting that hides the dialogue.

   Two exceptions are handled by name below, both looping, and both of whose
   keyframes rest at a *dim* value (0.52 and 0.45). Collapsed to one
   iteration they would freeze half-faded, so they stop at full strength
   instead. The ticker keeps its own rule further down: stopping it is not
   enough, the strip also has to become hand-scrollable to stay readable. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .explore-save-icon.is-saving,
  .gallery-skeleton-photo {
    animation: none !important;
    opacity: 1 !important;
  }
}
