/* ============================================================================
   SAMBA ART DIRECTION — token override layer.
   Loads AFTER tokens.css and redefines only the palette, type and elevation.
   components.css and every app rule read the tone, fg and bg channels and
   are untouched, so this is a drop-in swap and a one-line revert.

   Three deliberate departures from the source mockups:

   1. FLAT FILLS. The mockups fill buttons and badges with linear-gradients.
      Gradient-filled controls are the part of a 2010s UI that dates first, so
      every fill here is flat; the only gradients kept are the atmospheric
      background radials, which read as room light rather than as chrome.

   2. CONTRAST FLOOR. The mockups' --cream-faint (45% cream) computes to
      3.61:1 on the card ground — under the 4.5:1 AA floor, while carrying
      real body copy. Every fg step below is a solid value measured against
      the surface it sits on; ratios are noted inline.

   3. NO LIGHT VARIANT. Forest is the ground in every colour scheme, on
      purpose — see "ONE GROUND, ALWAYS" below. A cream light mode was tried
      and removed: it erased the identity on any phone set to light, which is
      most of them.
   ========================================================================= */

/* ══ FONTS ═══════════════════════════════════════════════════════════════
   Self-hosted, not CDN: the service worker precaches these, so the app keeps
   its typography offline and never blocks first paint on a third party.
   Fraunces and DM Sans are variable (one file each covers the whole weight
   range); all three are SIL OFL licensed. font-display:swap means text is
   readable in the fallback immediately and reflows once, rather than
   flashing invisible. */
@font-face {
  font-family: "Fraunces"; font-style: normal; font-weight: 100 900;
  font-display: swap; src: url("fonts/fraunces.woff2") format("woff2");
}
@font-face {
  font-family: "Fraunces"; font-style: italic; font-weight: 100 900;
  font-display: swap; src: url("fonts/fraunces-italic.woff2") format("woff2");
}
@font-face {
  font-family: "DM Sans"; font-style: normal; font-weight: 100 1000;
  font-display: swap; src: url("fonts/dmsans.woff2") format("woff2");
}
@font-face {
  font-family: "Caveat"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("fonts/caveat.woff2") format("woff2");
}
/* Les deux polices de la maquette du parcours (DESIGN_SYSTEM.md §3) :
   Fredoka pour les titres, badges et numeros de noeuds ; Plus Jakarta Sans
   pour le corps. Auto-hebergees comme les quatre autres -- l'app est une PWA
   hors-ligne, un lien vers Google Fonts la casserait des que le reseau tombe.
   Sous-ensemble latin uniquement (le premier @font-face servi par Google est
   le cyrillique : 1,7 Ko et aucune lettre utile, piege verifie). */
@font-face {
  font-family: "Fredoka"; font-style: normal; font-weight: 300 700;
  font-display: swap; src: url("fonts/fredoka.woff2") format("woff2");
}
@font-face {
  font-family: "Plus Jakarta Sans"; font-style: normal; font-weight: 200 800;
  font-display: swap; src: url("fonts/jakarta.woff2") format("woff2");
}
/* Fraunces carries an optical-size axis; let the browser drive it from the
   rendered size so the big display numbers get the high-contrast cut and the
   small text stays readable. */
html { font-optical-sizing: auto; }

:root {
  /* ── Raw palette ─────────────────────────────────────────────────────── */
  --forest-deep: #0B2419;
  --forest:      #143C2B;
  --forest-card: #17342A;
  --forest-line: #23553D;

  --cream:      #F6EEDA;
  --cream-soft: #FBF6EA;
  --cream-deep: #EDE3CB;

  --gold:        #D9A441;
  --gold-bright: #F2C14E;
  --terracotta:  #B5502C;
  --terracotta-soft: #D98A63;
  --moss:  #8C9B4A;
  --teal:  #3E6E63;
  --rosewood: #B5566B;
  --copper:   #C87137;
  --indigo:   #4C5E96;

  /* Macaw palette — pulled from the mascot reference (blue/yellow/green
     macaw). Ground stays forest (see ONE GROUND, ALWAYS below — that
     decision was about light-mode legibility, not this mascot, and still
     holds); these two land as two of the seven PACK_TONES accent hues.
     -500 is the saturated macaw fill; -700 is a lighter text-safe variant
     for the same hue, matching how every other tone pair here works —
     verified via a Node luminance calc, not picked by eye: macaw-blue-700
     is 8.87:1 on canvas / 7.28:1 on surface, macaw-green-700 is 10.24:1 /
     8.40:1, macaw-green-500 as a FILL (non-text, 3:1 floor) is 5.54:1 /
     4.55:1 against canvas/surface. */
  /* Path-state greens. "Done" was the same --tone-500 as "current", so the
     two states differed only by shadow depth and a pulse -- you could not
     read your position on the path at a glance. Green-for-done is close to
     universal, so it earns a fixed hue rather than rotating with the pack
     tone. NOT the reference's #10B981: a white icon on it computes to
     2.54:1, under the 3:1 non-text floor this file holds. #059669 gives
     3.77:1 for the icon and 4.35:1 against the forest canvas. */
  --done-green:      #059669;
  --done-green-deep: #04624A;

  --macaw-blue:      #2E6FE0;
  --macaw-blue-soft: #9CC1F5;
  --macaw-green:      #3CAA5C;
  --macaw-green-soft: #A9D9A0;

  /* Light-theme palette — additive only, dark stays exactly as above.
     Solid values, measured the same way as the dark tiers below (not
     lifted from the reference mock's own softer greys/opacities, which
     fall short of the 3:1 non-text / 4.5:1 text floors this file already
     holds itself to — see the contrast-floor note in the header). */
  /* Le fond de page et la surface creusee etaient creme (#FBF6EA / #E6E0CE).
     Passes aux gris froids de la maquette (DESIGN_SYSTEM.md §1.A :
     « Arriere-plan principal (Canvas) : #F8FAFC (bg-slate-50) »), le second
     etant le slate-200 que la maquette utilise deja pour ses noeuds
     verrouilles -- donc pas une teinte inventee pour l'occasion.
     --cream-soft n'est PAS touche : en theme sombre il sert de couleur de
     TEXTE (--fg-primary, 14,8:1 sur forest-card) et de --bg-inverse ; le
     repeindre en gris froid casserait le contraste documente et refroidirait
     tout le mode sombre, qu'on ne cherche pas a changer ici. */
  --lt-page:   #F8FAFC;  --lt-card:   #FFFFFF;  --lt-sunken: #E2E8F0;
  --lt-ink:    #241A12;                              /* fg-primary   — 15.8:1 / 17.1:1 on page/card */
  --lt-ink-70: #5F5852;                              /* fg-secondary —  6.5:1 /  7.0:1 */
  --lt-ink-55: #6C6660;                              /* fg-muted     —  5.3:1 /  5.7:1 (matches the 5.0:1 floor below) */
  --lt-ink-35: #8D8884;                              /* fg-disabled  —  3.3:1 /  3.5:1 */
  --lt-line:        #897C63;                         /* border-subtle — 3.8:1 on page */
  --lt-line-strong: #756750;                         /* border-strong — 5.1:1 on page */
  --lt-green: #143E28;      --lt-green-wash: #E7F1E9; /* 10.4:1 pair */
  --lt-gold:  #775A24;      --lt-gold-wash:  #FFF1D4; /*  5.9:1 pair (app's --gold, darkened for text — --gold-deep itself only clears ~3:1) */
  --lt-terra: #6D301A;      --lt-terra-wash: #FCE4D8; /*  8.2:1 pair (app's --terracotta, darkened for text) */
  --lt-teal:  #223D36;      --lt-teal-wash:  #E2E9E8; /* 10.9:1 pair (app's --teal, darkened for text) */

  /* Kept because app CSS references them directly. */
  --ink-900: var(--forest-deep);
  --paper:   var(--cream-soft);

  /* ── Type ────────────────────────────────────────────────────────────── */
  /* Fraunces carries the Portuguese, DM Sans carries the interface, Caveat is
     rationed to the two human lines. The fallbacks matter: until the webfonts
     land the app still reads correctly rather than reflowing into nothing. */
  --font-display: "Fraunces", "Iowan Old Style", Palatino, Georgia, serif;
  --font-body:    "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-accent:  "Caveat", "Fraunces", Georgia, cursive;

  /* ── Elevation ───────────────────────────────────────────────────────── */
  /* Hard offset shadows, no blur — screenprinted poster, not soft UI. */
  --shadow-1: 0 2px 0 rgb(0 0 0 / 0.18);
  --shadow-2: 0 3px 0 rgb(0 0 0 / 0.22);
  --shadow-3: 0 6px 0 rgb(0 0 0 / 0.24), 0 14px 28px rgb(0 0 0 / 0.18);
  --shadow-inset: inset 0 1px 0 rgb(255 255 255 / 0.28);
}

/* ══ FOREST BY DEFAULT, ALWAYS ═══════════════════════════════════════════
   Forest stays the ground for the SYSTEM preference and for anyone who never
   touches the toggle — that part of "ONE GROUND, ALWAYS" is unchanged. An
   earlier revision let forest mean "the dark theme" and cream mean "the
   light theme" and followed prefers-color-scheme automatically; on a phone
   already set to light that silently erased the identity for every visitor,
   which is what got it pulled. [data-theme="light"] now exists as an
   explicit, user-chosen opt-in (see the toggle in index.html) rather than
   something the OS flips on its own — a different failure mode, so this
   time it gets its own block below instead of being folded into "dark."

   :root and :root:not([data-theme="light"]) inside the dark media query
   still carry identical forest values — that duplication is still needed
   because tokens.css declares ITS dark values at that higher specificity
   and would otherwise win when the phone is in dark mode.
   ===================================================================== */
:root,
[data-theme="dark"] {
  --bg-canvas:  var(--forest-deep);
  --bg-surface: var(--forest-card);
  --bg-sunken:  #081B12;
  --bg-inverse: var(--cream-soft);
  --bg-scrim:   rgb(4 14 9 / 0.66);

  --fg-primary:    var(--cream-soft);   /* 14.8:1 on forest-card */
  --fg-secondary:  #D4C9AF;             /*  8.2:1 */
  --fg-muted:      #A69C86;             /*  5.0:1 — replaces the mockups' 3.6:1 */
  --fg-disabled:   #6B6B5C;
  --fg-on-inverse: var(--forest-deep);
  --fg-on-tone:    var(--forest-deep);

  /* Task 5 of UX Review #3: text contrast was measured and documented
     (see header), component-boundary contrast wasn't. Measured:
     old --border-subtle (#24463A) vs canvas = 1.57:1, needs 3:1 (WCAG
     1.4.11) — cards and buttons were separating from the ground by
     luminance alone. #4A8766 clears 3:1 against BOTH canvas (3.86:1) and
     surface (3.17:1), which no lighter candidate below it does — verified,
     not picked by eye. --border-strong was --forest-line (#23553D,
     1.90:1) — weaker than the new subtle, which would invert the
     hierarchy — so it moves up too, to stay visibly the stronger of the
     two (4.88:1 vs canvas, 4.00:1 vs surface). Neither is ever used for
     text, only borders/fills, so this cannot regress any 4.5:1 text pair. */
  --border-subtle: #4A8766;
  --border-strong: #5B9973;
  --border-ink:    var(--cream-soft);

  --action-solid:    var(--gold-bright);
  --action-solid-fg: var(--forest-deep);
  --accent:      var(--gold-bright);
  --accent-fg:   var(--forest-deep);
  --accent-wash: #2E2A16;
  --focus-ring:  var(--gold-bright);

  --positive: #8FBF8A;            --positive-wash: #16301F;
  --caution:  var(--gold-bright); --caution-wash:  #2E2612;
  --critical: #E89476;            --critical-wash: #35201A;

  --sky-100: #12302B;   --sky-700: #8FC4B4;

  --shadow-1: 0 2px 0 rgb(0 0 0 / 0.34);
  --shadow-2: 0 3px 0 rgb(0 0 0 / 0.4);
  --shadow-3: 0 6px 0 rgb(0 0 0 / 0.42), 0 14px 28px rgb(0 0 0 / 0.4);
  --shadow-inset: inset 0 1px 0 rgb(255 255 255 / 0.06);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg-canvas: var(--forest-deep); --bg-surface: var(--forest-card); --bg-sunken: #081B12;
    --bg-inverse: var(--cream-soft); --bg-scrim: rgb(4 14 9 / 0.66);
    --fg-primary: var(--cream-soft); --fg-secondary: #D4C9AF; --fg-muted: #A69C86;
    --fg-disabled: #6B6B5C; --fg-on-inverse: var(--forest-deep); --fg-on-tone: var(--forest-deep);
    --border-subtle: #4A8766; --border-strong: #5B9973; --border-ink: var(--cream-soft);
    --action-solid: var(--gold-bright); --action-solid-fg: var(--forest-deep);
    --accent: var(--gold-bright); --accent-fg: var(--forest-deep); --accent-wash: #2E2A16;
    --focus-ring: var(--gold-bright);
    --positive: #8FBF8A; --positive-wash: #16301F;
    --caution: var(--gold-bright); --caution-wash: #2E2612;
    --critical: #E89476; --critical-wash: #35201A;
    --sky-100: #12302B; --sky-700: #8FC4B4;
    --shadow-1: 0 2px 0 rgb(0 0 0 / 0.34);
    --shadow-2: 0 3px 0 rgb(0 0 0 / 0.4);
    --shadow-3: 0 6px 0 rgb(0 0 0 / 0.42), 0 14px 28px rgb(0 0 0 / 0.4);
    --shadow-inset: inset 0 1px 0 rgb(255 255 255 / 0.06);
  }
}

/* ══ LIGHT THEME — explicit opt-in only ═════════════════════════════════
   Reached only via the toggle in index.html, never via prefers-color-scheme
   — see the note above. Cream/white ground, warm-ink text.

   :root[data-theme="light"], not the plain attribute selector: tokens.css
   ships its OWN dormant :root[data-theme="light"] block (0,2,0 specificity)
   left over from before the samba layer existed — never reachable before
   because nothing ever set the attribute, so it was safe to ignore. Now
   that the toggle actually sets it, that block wakes up and, at only
   (0,1,0), a plain [data-theme="light"] here loses to it — silently
   reverting --action-solid, --critical, --shadow-*, etc. to tokens.css's
   own uncoordinated light values. Matching specificity is what actually
   fixes it; source order then wins the tie because this file loads last. */
:root[data-theme="light"] {
  --bg-canvas:  var(--lt-page);
  --bg-surface: var(--lt-card);
  --bg-sunken:  var(--lt-sunken);
  --bg-inverse: var(--forest-deep);   /* inverted from dark mode on purpose — a dark chip on a light page */
  --bg-scrim:   rgb(36 26 18 / 0.28);

  --fg-primary:    var(--lt-ink);
  --fg-secondary:  var(--lt-ink-70);
  --fg-muted:      var(--lt-ink-55);
  --fg-disabled:   var(--lt-ink-35);
  --fg-on-inverse: var(--cream-soft);
  --fg-on-tone:    var(--lt-ink);

  --border-subtle: var(--lt-line);
  --border-strong: var(--lt-line-strong);
  --border-ink:    var(--lt-ink);

  --action-solid:    var(--gold-bright);
  --action-solid-fg: var(--forest-deep);
  --accent:      var(--gold-bright);
  --accent-fg:   var(--forest-deep);
  --accent-wash: var(--lt-gold-wash);
  --focus-ring:  var(--lt-gold);

  --positive: var(--lt-green); --positive-wash: var(--lt-green-wash);
  --caution:  var(--lt-gold);  --caution-wash:  var(--lt-gold-wash);
  --critical: var(--lt-terra); --critical-wash: var(--lt-terra-wash);

  --sky-100: var(--lt-teal-wash); --sky-700: var(--lt-teal);

  --shadow-1: 0 2px 0 rgb(36 26 18 / 0.10);
  --shadow-2: 0 3px 0 rgb(36 26 18 / 0.14);
  --shadow-3: 0 6px 0 rgb(36 26 18 / 0.16), 0 14px 28px rgb(36 26 18 / 0.12);
  --shadow-inset: inset 0 1px 0 rgb(255 255 255 / 0.5);
}

/* Every [data-tone] block hardcodes dark-forest values for 100/300/700
   (see TONE RAMPS below) — same specificity as this rule, so without the
   extra [data-theme="light"] ancestor selector here to win on specificity,
   dark tone chips would leak through on cards inside a light-toggled page.
   Formula-derived from the SAME --tone-500 every tone already sets, so it
   covers all seven without hand-picking 21 more hex values: 100 flattens to
   the page (matches dark mode, where tone-100 already equals bg-canvas);
   300 and 700 are light/dark tints of each pack's own fill, verified against
   the weakest of the seven (gold) at 8.4:1 text-on-chip, min 3.3:1 chip-vs-page. */
[data-theme="light"] [data-tone] {
  --tone-100: var(--bg-canvas);
  --tone-300: color-mix(in srgb, var(--tone-500) 18%, white);
  --tone-700: color-mix(in srgb, var(--tone-500) 40%, black);
}

/* ══ TONE RAMPS ══════════════════════════════════════════════════════════
   The [data-tone] mechanism is preserved exactly, but its meaning shifts:
   every card keeps the SAME forest ground and the pack's colour arrives
   through its badge and meter (--tone-500/700) instead of tinting the card.
   Ramp names are unchanged so PACK_TONES and every data-tone attribute in
   the app keep working untouched.
   100 = ground   300 = raised chip   500 = fill   700 = text-safe on forest
   ===================================================================== */
[data-tone="lilac"]   { --tone-100:var(--forest-deep); --tone-300:#2C3A1F; --tone-500:var(--gold);       --tone-700:var(--gold-bright);     --fg-on-tone:var(--forest-deep); }
[data-tone="blush"]   { --tone-100:var(--forest-deep); --tone-300:#3A2318; --tone-500:var(--terracotta); --tone-700:var(--terracotta-soft); --fg-on-tone:var(--cream-soft);  }
[data-tone="butter"]  { --tone-100:var(--forest-deep); --tone-300:#2C331A; --tone-500:var(--moss);       --tone-700:#BCC97A;                --fg-on-tone:var(--forest-deep); }
[data-tone="sky"]     { --tone-100:var(--forest-deep); --tone-300:#1B3A34; --tone-500:var(--teal);       --tone-700:#8FC4B4;                --fg-on-tone:var(--cream-soft);  }
[data-tone="sage"]    { --tone-100:var(--forest-deep); --tone-300:#1A2E4A; --tone-500:var(--macaw-blue);  --tone-700:var(--macaw-blue-soft);  --fg-on-tone:var(--cream-soft);  }
[data-tone="apricot"] { --tone-100:var(--forest-deep); --tone-300:#3A2A1A; --tone-500:var(--copper);     --tone-700:#E5A470;                --fg-on-tone:var(--cream-soft);  }
[data-tone="mint"]    { --tone-100:var(--forest-deep); --tone-300:#1B3A20; --tone-500:var(--macaw-green); --tone-700:var(--macaw-green-soft); --fg-on-tone:var(--forest-deep); }

/* ══ ATMOSPHERE ══════════════════════════════════════════════════════════
   The one gradient kept from the mockups — warm gold from the top corner,
   terracotta from the bottom — plus the drumhead dot weave. Fixed to the
   shell so it reads as room light behind the content.
   Painted as background layers on #app itself rather than an overlay
   pseudo-element. An earlier revision used #app::before plus
   "#app > * { position: relative }" to stack content above it — and that
   selector (specificity 1,0,0) silently beat ".word-sheet { position: fixed }"
   (0,1,0), un-fixing both bottom sheets and adding their height to the page.
   Background layers need no stacking fix, so nothing can be clobbered. */
#app {
  background-image:
    radial-gradient(circle at 12% 3%,  rgb(242 193 78 / 0.10), transparent 38%),
    radial-gradient(circle at 90% 97%, rgb(181 80 44 / 0.12), transparent 42%),
    radial-gradient(rgb(255 255 255 / 0.035) 1px, transparent 1.5px);
  background-size: auto, auto, 14px 14px;
  background-repeat: no-repeat, no-repeat, repeat;
}

/* Portuguese always arrives in Fraunces — the word under test, the sung line,
   the lyric chips. The interface stays in DM Sans. */
.sentence, .ms-word, .ws-head, .ap-answer, .build-chip, .lyric-chip { font-family: var(--font-display); }
.ms-word, .ws-head { font-style: italic; }

/* ══ THE PANDEIRO ════════════════════════════════════════════════════════
   The one piece of the direction that is an object rather than a colour: the
   session count sits in a tambourine head, ringed by six platinelas. Built
   from two divs and a box-shadow ring — no images, nothing to load. */
.pandeiro {
  position: relative; width: 168px; height: 168px;
  margin-bottom: var(--space-6); flex-shrink: 0;
}
.pandeiro__head {
  position: absolute; inset: 0; border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%, rgb(255 255 255 / 0.55), transparent 45%),
    var(--cream-soft);
  border: 6px solid var(--gold);
  box-shadow: 0 8px 0 rgb(0 0 0 / 0.22), inset 0 0 0 2px rgb(20 60 43 / 0.08);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 800; font-size: 60px;
  line-height: 1; color: var(--forest-deep);
}
.pandeiro .jingle {
  position: absolute; width: 16px; height: 16px; border-radius: 50%;
  background: var(--gold); box-shadow: 0 2px 3px rgb(0 0 0 / 0.35), inset 0 1px 1px rgb(255 255 255 / 0.55);
}
.pandeiro .j1 { top: -2px;  left: 50%; margin-left: -8px; }
.pandeiro .j2 { top: 26px;  right: 2px; }
.pandeiro .j3 { bottom: 26px; right: 2px; }
.pandeiro .j4 { bottom: -2px; left: 50%; margin-left: -8px; }
.pandeiro .j5 { bottom: 26px; left: 2px; }
.pandeiro .j6 { top: 26px;  left: 2px; }

/* Handwritten, rotated, on cream — the one place the interface speaks
   Portuguese in its own voice rather than reporting a number. */
.done-eyebrow {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--cream-soft); color: var(--forest);
  padding: 6px 16px 8px; border-radius: var(--radius-pill);
  font-family: var(--font-accent); font-weight: 700; font-size: 21px;
  box-shadow: 0 3px 0 rgb(0 0 0 / 0.18);
  transform: rotate(-2deg); margin-bottom: var(--space-6);
}
#done-affirm { font-family: var(--font-accent); font-size: 25px; color: var(--gold-bright); font-weight: 700; }
#done-sub strong, #done-sub b { color: var(--gold-bright); }

/* Brand-coloured ribbons, not rainbow chaos. Decorative, motion-gated. */
.confetti { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.confetti i {
  position: absolute; top: -14px; width: 6px; height: 12px; border-radius: 2px;
  opacity: 0; animation: ribbon-drift 5.5s ease-in-out infinite;
}
@keyframes ribbon-drift {
  0%   { transform: translateY(-10px) rotate(0deg);    opacity: 0; }
  12%  { opacity: 0.9; }
  100% { transform: translateY(620px) rotate(200deg);  opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .confetti i { animation: none; opacity: 0.45; transform: translateY(90px); }
}

/* ══ LIGHT THEME — component-level fixes ═══════════════════════════════
   --lt-page (#FBF6EA) turned out to exactly equal the existing --cream-soft
   raw token — a coincidence, not a rename. Two spots hardcode --cream-soft
   as their OWN background (not text-on-a-fill, where it's unaffected): the
   pandeiro head and the done-screen eyebrow chip. On the forest ground
   that's the intended pop; on the light ground it's now the same colour as
   the page behind it, so both go invisible. Repointed to --bg-surface
   (white on the light page) instead of adding yet another raw colour. */
[data-theme="light"] .pandeiro__head {
  background:
    radial-gradient(circle at 32% 28%, rgb(255 255 255 / 0.7), transparent 45%),
    var(--bg-surface);
}
[data-theme="light"] .done-eyebrow { background: var(--bg-surface); }

/* The "Today" hero is plain .card everywhere else in the app (no colour
   identity of its own to inherit from a token swap) but IS the one card the
   light reference gives a specific treatment — a terracotta field, matching
   --terracotta/--tone-500 of the "blush" pack tone so it stays inside the
   existing palette rather than introducing a new hue. Welcome/first-run
   variant (.hero-welcome) is left on the plain card: the reference has no
   first-run state to match against. */
[data-theme="light"] .hero-card:not(.hero-welcome) {
  background: var(--terracotta);
  box-shadow: 0 4px 0 color-mix(in srgb, var(--terracotta) 70%, black), var(--shadow-1);
}
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-label,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-today-sub,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-new-line,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-stack-legend,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-stat-head { color: rgb(255 255 255 / 0.82); }
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-num,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-stat-num--mastered { color: #FFFFFF; }
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-divider,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-stack { background: rgb(255 255 255 / 0.28); }
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-stack__seg--mastered,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-dot--mastered { background: #FFFFFF; }
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-stack__seg--progress,
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-dot--progress { background: rgb(255 255 255 / 0.55); }
[data-theme="light"] .hero-card:not(.hero-welcome) .hero-dot--new { background: rgb(255 255 255 / 0.28); border-color: rgb(255 255 255 / 0.4); }
