/* "Paper sticker" redesign — direction 1B from the Claude Design exploration
   (project aa7f4c13, "Adept Redesign.dc.html"). The mockup itself only
   covered the homepage and Sticks; everything below the sticks section of
   this file extends the same tokens and rules to the rest of the site by
   hand, following the same language rather than a second mockup.

   Loaded after site.css and scoped under body.theme-paper. That class started
   on index.html and sticks.html only; it is now on every page of the site
   (all 16 content pages carry body.theme-paper), so this file is the site's
   design system rather than a two-page experiment. site.css remains the
   substrate underneath it: geometry, layout and the ad-clearance contract.

   The scoping still does the same job it always did — it only ever
   touches decorative properties (color, background, border style/color,
   border-radius, box-shadow, font-family/weight) on the pages that opt in.
   It never changes anything geometry.mjs measures — margins, padding,
   gaps, widths, heights — so the ad-clearance rules stay whatever site.css
   already guarantees. If a component needs a genuinely different layout to
   match the mockup (the sticks board's bar orientation, for one), it was
   left as-is rather than risking that contract; see the README/todo note on
   this redesign for what's still unported.

   Dark mode: originally this file committed to one fixed light look on
   purpose. It now supports a second palette, toggled by theme-toggle.js via
   `data-theme="dark"` on <html> (persisted in localStorage, defaulting to
   the OS preference) rather than by media query alone — a reader has to be
   able to override the OS setting per-site, the way every other dark-mode
   toggle on the web works.

   The trick that keeps ~500 lines of component rules below from needing a
   dark variant each: --rp-ink and --rp-bg are ROLES, not colors, and every
   component rule below reaches for the role. Flipping the two roles' values
   re-themes the whole file. The one place that breaks is the handful of
   components that are deliberately a solid dark card regardless of theme
   (.panel--dark, .result, .portfolio, .intro-tour, .game-gate and the like)
   — those reach for --rp-fill / --rp-on-fill instead, a second pair of
   roles that does NOT flip, so a "dark accent card" stays a dark accent
   card whether the page around it is paper-light or ink-dark. Text sitting
   on --rp-lime (which also does not flip — lime stays lime) reaches for
   --rp-lime-ink for the same reason. */

body.theme-paper {
  --rp-bg:      oklch(0.97 0.004 250);
  --rp-bg-2:    oklch(0.93 0.005 250);
  --rp-ink:     oklch(0.17 0.01 250);
  --rp-ink-2:   oklch(0.32 0.01 250);
  --rp-ink-3:   oklch(0.45 0.01 250);
  --rp-mute:    oklch(0.5 0.01 250);
  --rp-lime:    oklch(0.85 0.19 130);
  --rp-lime-ink:oklch(0.2 0.02 130);
  --rp-green:   oklch(0.55 0.16 145);
  --rp-red:     oklch(0.6 0.18 30);
  --rp-border:  3px;
  --rp-shadow:  6px 6px 0 var(--rp-ink);
  --rp-shadow-sm: 4px 4px 0 var(--rp-ink);

  /* Fixed roles: a "solid dark card" and the text that sits on it, stable
     across both themes rather than flipping with --rp-ink/--rp-bg. */
  --rp-fill:    oklch(0.17 0.01 250);
  --rp-on-fill: oklch(0.97 0.004 250);

  /* A second lime, for large surfaces only (the daily-game card fill) —
     --rp-lime itself stays fixed brightness for small accents (the
     wordmark, badges, key-hover states) where full saturation reads fine.
     Filling most of a card with that same brightness against the dark
     theme's dark surroundings read as glaring, so this dims/desaturates
     only for that large-fill use, and only in dark mode (identical to
     --rp-lime in light mode, where the full-bright card was never a
     problem). */
  --rp-lime-fill:     var(--rp-lime);
  --rp-lime-fill-ink: var(--rp-lime-ink);

  --sans: 'Space Grotesk', system-ui, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, monospace;

  background: var(--rp-bg);
  color: var(--rp-ink);
}

/* Dark palette: --rp-ink and --rp-bg swap roles (paper becomes ink, ink
   becomes paper); --rp-fill/--rp-on-fill hold steady so the accent cards
   stay dark; --rp-lime holds steady because it is the one color in this
   system that is never a surface a reader reads long text off. */
html[data-theme="dark"] body.theme-paper {
  --rp-bg:      oklch(0.19 0.012 255);
  --rp-bg-2:    oklch(0.24 0.014 255);
  --rp-ink:     oklch(0.93 0.006 255);
  --rp-ink-2:   oklch(0.8 0.008 255);
  --rp-ink-3:   oklch(0.68 0.01 255);
  --rp-mute:    oklch(0.58 0.01 255);
  --rp-green:   oklch(0.68 0.15 145);
  --rp-red:     oklch(0.68 0.17 25);
  --rp-lime-fill:     oklch(0.4 0.1 130);
  --rp-lime-fill-ink: oklch(0.93 0.03 130);
}

body.theme-paper .page { background: var(--rp-bg); border-inline-color: var(--rp-ink); }

/* ---------- header / nav ---------- */

body.theme-paper .site-header {
  background: var(--rp-bg);
  color: var(--rp-ink);
  border-bottom: var(--rp-border) solid var(--rp-ink);
}
body.theme-paper .wordmark {
  color: var(--rp-lime-ink);
  background: var(--rp-lime);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 10px;
  padding: 2px 10px;
  box-shadow: 3px 3px 0 var(--rp-ink);
}
body.theme-paper .site-header__section { color: var(--rp-mute); }
body.theme-paper .site-nav { color: var(--rp-ink-2); }
body.theme-paper .site-nav a { color: var(--rp-ink-2); }
body.theme-paper .site-nav a:hover,
body.theme-paper .site-nav a[aria-current="page"] { color: var(--rp-ink); }
body.theme-paper .site-nav a::after { background: var(--rp-lime); }
/* The games dropdown now flips with the theme instead of staying a fixed
   light card: dark mode gets the same --rp-bg/--rp-ink pair the rest of
   the dark page uses, so it reads as part of the page instead of a
   permanently-light square dropped onto a dark one. Text/badge colors
   need no override here — the blanket ".site-nav a" (--rp-ink-2) and
   .game-badge (--rp-ink) rules above already flip correctly once the
   panel behind them is dark too. */
html[data-theme="dark"] body.theme-paper .site-nav__games-panel {
  background: var(--rp-bg);
  border-color: var(--rp-ink);
}
html[data-theme="dark"] body.theme-paper .site-nav__games-heading { color: var(--rp-mute); }
html[data-theme="dark"] body.theme-paper .site-nav__games-heading:not(:first-child) {
  border-top-color: var(--rp-ink);
}
html[data-theme="dark"] body.theme-paper .site-nav__games-panel a:hover,
html[data-theme="dark"] body.theme-paper .site-nav__games-panel a[aria-current="page"] {
  background: var(--rp-bg-2);
}
body.theme-paper .site-nav__login:hover { background: var(--rp-lime); color: var(--rp-lime-ink) !important; }
body.theme-paper .site-nav__login:focus-visible { outline-color: var(--rp-lime); }
body.theme-paper .site-nav__login {
  border: 2px solid var(--rp-ink);
  color: var(--rp-ink) !important;
  border-radius: 999px;
}
body.theme-paper .site-nav__stat {
  color: var(--rp-lime-ink);
  background: var(--rp-lime);
  border: 2px solid var(--rp-ink);
  border-radius: 999px;
  padding: 3px 10px;
}
body.theme-paper .avatar {
  background: var(--rp-lime);
  color: var(--rp-lime-ink);
  border: 2px solid var(--rp-ink);
}
body.theme-paper .avatar:hover { background: var(--rp-ink); color: var(--rp-lime); }
/* Background left off this rule on purpose: site.css's .account-menu__panel
   already sets --card, the same color the games dropdown uses, and this
   block used to override it to --rp-bg unconditionally — a close but not
   identical shade in light mode. The dark-mode-only rule below still
   matches it to --rp-bg there, same as the games dropdown. */
body.theme-paper .account-menu__panel {
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 12px;
  box-shadow: var(--rp-shadow);
}
html[data-theme="dark"] body.theme-paper .account-menu__panel { background: var(--rp-bg); }
body.theme-paper .account-menu__head { color: var(--rp-mute); }
body.theme-paper .account-menu__label { color: var(--rp-ink-3); }
body.theme-paper .account-menu__input {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 8px;
  color: var(--rp-ink);
}
body.theme-paper .account-menu__note { color: var(--rp-red); }
body.theme-paper .account-menu__save {
  background: var(--rp-lime);
  color: var(--rp-lime-ink);
  border: 2px solid var(--rp-ink);
  border-radius: 999px;
}
body.theme-paper .account-menu__save:hover { background: var(--rp-ink); color: var(--rp-lime); }
body.theme-paper .account-menu__divider { border-top-color: var(--rp-ink); opacity: .25; }
body.theme-paper .account-menu__label--danger { color: var(--rp-red); }
body.theme-paper .account-menu__delete { background: var(--rp-red); color: var(--rp-lime-ink); border-color: var(--rp-ink); }
body.theme-paper .account-menu__delete:hover { background: var(--rp-ink); color: var(--rp-red); }
body.theme-paper .theme-toggle {
  background: transparent;
  border: 2px solid color-mix(in oklch, var(--rp-ink) 30%, transparent);
  color: var(--rp-ink);
}
body.theme-paper .theme-toggle:hover { background: var(--rp-lime); border-color: var(--rp-ink); color: var(--rp-lime-ink); }

body.theme-paper .nav-burger {
  background: transparent;
  border: 2px solid color-mix(in oklch, var(--rp-ink) 30%, transparent);
  color: var(--rp-ink);
}
body.theme-paper .nav-burger:hover,
body.theme-paper .nav-burger[aria-expanded="true"] { background: var(--rp-lime); border-color: var(--rp-ink); color: var(--rp-lime-ink); }
body.theme-paper .site-nav.site-nav--open {
  background: var(--rp-bg);
  border-top: var(--rp-border) solid var(--rp-ink);
  box-shadow: var(--rp-shadow);
}
body.theme-paper .site-nav.site-nav--open a:not(.site-nav__login):not(.site-nav__stat) {
  border-bottom-color: color-mix(in oklch, var(--rp-ink) 14%, transparent);
}
/* The "Menu" eyebrow (site.css's .site-nav--open::before) is hardcoded
   light-on-dark, an assumption from before this theme's light drawer
   background existed — near-white text at 45% opacity on the paper
   theme's light background was essentially invisible, reading as a
   blank gap above "Games" instead of a label. */
body.theme-paper .site-nav.site-nav--open::before { color: color-mix(in oklch, var(--rp-ink) 45%, transparent); }

/* ---------- hero ---------- */

body.theme-paper .hero h1 {
  font: 700 46px/1.08 var(--sans);
  letter-spacing: -.03em;
}
body.theme-paper .hero p { color: var(--rp-ink-3); font-family: var(--sans); }

/* ---------- generic surfaces ---------- */

body.theme-paper .panel {
  background: var(--rp-bg);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 14px;
}
body.theme-paper .panel--dark {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  border: var(--rp-border) solid var(--rp-ink);
}
body.theme-paper .panel--dark .eyebrow { color: var(--rp-lime); }
body.theme-paper .eyebrow { color: var(--rp-mute); font-family: var(--mono); }
body.theme-paper .eyebrow--green { color: var(--rp-green); }
/* .pos/.neg (crypto gains/losses — the leaderboard's Return column,
   every P&L figure on crypto.html) had no theme-paper override at all,
   so they stayed site.css's fixed light-mode green/red instead of this
   theme's own role colors. */
body.theme-paper .pos { color: var(--rp-green); }
body.theme-paper .neg { color: var(--rp-red); }

/* ---------- entry cards (games + tools) ---------- */

body.theme-paper .entry-card {
  border-radius: 16px;
  border: var(--rp-border) solid var(--rp-ink);
  box-shadow: var(--rp-shadow);
  transition: transform .16s ease, box-shadow .16s ease;
}
/* Used to also translate(-3px,-3px) on hover — moving the card up-left
   while its neighbor in the grid stays put opened a sliver of bare page
   background between the two along that shared edge, which read as an
   unwanted gap rather than a "lift". Growing the shadow alone gives the
   same raised-off-the-page feel with the card's own box never moving, so
   there's nothing for a neighbor's edge to separate from. */
body.theme-paper .entry-card:hover {
  box-shadow: 10px 10px 0 var(--rp-ink);
  border-color: var(--rp-ink);
}
/* site.css's a.entry-card.panel--dark:hover outline is a leftover from
   the pre-redesign design system — a fixed, non-theme --green never wired
   into the --rp-* role system, so it showed up as a stray mint/teal ring
   around the card regardless of theme. The box-shadow/border-color above
   already give this theme its own hover feedback. */
body.theme-paper a.entry-card.panel--dark:hover { outline: none; }
body.theme-paper a.entry-card { color: var(--rp-ink); }
body.theme-paper a.entry-card.panel--dark { color: var(--rp-on-fill); }
/* Games get the lime fill (the mockup's "today" treatment); tools stay
   paper-white with a black border, per the 1B layout. */
body.theme-paper .panel--dark.entry-card {
  background: var(--rp-lime-fill);
  color: var(--rp-lime-fill-ink);
}
body.theme-paper .panel--dark.entry-card .eyebrow,
body.theme-paper .panel--dark.entry-card .entry-card__reset { color: var(--rp-lime-fill-ink); opacity: .7; }
body.theme-paper .entry-card__title { font-family: var(--sans); letter-spacing: -.02em; }
body.theme-paper .entry-card__cta { font: 700 12px/1 var(--mono); color: var(--rp-ink); }
body.theme-paper .panel--dark.entry-card .entry-card__cta,
body.theme-paper .entry-card.panel--dark .entry-card__cta { color: var(--rp-lime-fill-ink); }
body.theme-paper .entry-card__body { color: var(--rp-ink-3); font-family: var(--sans); }
body.theme-paper .entry-card__guide-link { color: var(--rp-ink-3); font-family: var(--sans); }
body.theme-paper .entry-card__guide-link:hover { color: var(--rp-ink); }
body.theme-paper .panel--dark .entry-card__body,
body.theme-paper .panel--dark.entry-card .entry-card__body { color: var(--rp-lime-fill-ink); opacity: .8; }

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

body.theme-paper .btn {
  font-family: var(--sans);
  border-radius: 999px;
  border: 2px solid var(--rp-ink);
  background: transparent;
  color: var(--rp-ink);
}
body.theme-paper .btn--primary { background: var(--rp-lime); color: var(--rp-lime-ink); }

/* ---------- ad wells ---------- */

body.theme-paper .ad-well {
  background: repeating-linear-gradient(135deg, var(--rp-bg-2) 0 8px, var(--rp-bg) 8px 16px);
  border: 2px dashed color-mix(in oklch, var(--rp-ink) 35%, transparent);
  border-radius: 10px;
}

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

body.theme-paper .site-footer {
  border-top: var(--rp-border) solid var(--rp-ink);
  color: var(--rp-ink-3);
  font-family: var(--mono);
}
body.theme-paper .site-footer__sitemap { border-bottom-color: color-mix(in oklch, var(--rp-ink) 16%, transparent); }
body.theme-paper .site-footer__brand p { color: var(--rp-mute); }
body.theme-paper .site-footer__heading { color: var(--rp-ink); font-family: var(--sans); }
body.theme-paper .site-footer__col a { color: var(--rp-ink-2); }
body.theme-paper .site-footer__col a:hover { color: var(--rp-green); }
body.theme-paper .site-footer__facts { color: var(--rp-mute); }
body.theme-paper .site-footer__links {
  border-top-color: color-mix(in oklch, var(--rp-ink) 16%, transparent);
}
body.theme-paper .site-footer__links a {
  color: var(--rp-ink-2);
  text-decoration-color: color-mix(in oklch, var(--rp-ink) 25%, transparent);
}
body.theme-paper .site-footer__links a:hover { color: var(--rp-green); text-decoration-color: var(--rp-green); }
body.theme-paper .footer-help { color: var(--rp-ink-2); }
body.theme-paper .footer-help:hover { color: var(--rp-green); }

/* ---------- streak strip ---------- */

body.theme-paper .streak-cell { background: var(--rp-bg-2); border: 2px solid var(--rp-ink); border-radius: 4px; }
body.theme-paper .streak-cell--hit { background: var(--rp-lime); }
body.theme-paper .streak-cell--today { background: transparent; border-style: dashed; }

/* ---------- flame ---------- */

body.theme-paper .flame { filter: none; }
/* Needed because `.sticks__score span` (below) outranks a single-class
   selector and loads after site.css, so without the extra `.sticks__score`
   ancestor here to match its specificity, the streak number/flame always
   rendered in the same muted gray as every other span in the stats row — a
   live streak looked identical to no streak at all.

   The flame icon itself needs its own line: it is a <span>, so it is
   directly matched (and overridden) by `.sticks__score span` regardless of
   what color the wrapper around it inherits — a child a rule targets by
   itself never just inherits from an ancestor, no matter how specific that
   ancestor's own rule is. Fixing only the wrapper left the streak *number*
   orange while the flame glyph next to it stayed gray, which is why this
   kept reading as "still gray" after the first fix. */
body.theme-paper .sticks__score .sticks__score-num--streak-on { color: var(--flame); }
body.theme-paper .sticks__score .sticks__score-num--streak-on .flame { color: var(--flame); }

/* ---------- sign-in nudge ---------- */

body.theme-paper .signin-nudge {
  background: var(--rp-fill);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 14px;
}
body.theme-paper .signin-nudge__text { font-family: var(--mono); }
body.theme-paper .signin-nudge__text strong { color: var(--rp-lime); }
body.theme-paper .signin-nudge .btn--primary { background: var(--rp-lime); color: var(--rp-lime-ink); }

/* ---------- sticks ---------- */

body.theme-paper .sticks {
  background: var(--rp-bg);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 16px;
}
body.theme-paper .sticks__prompt { font-family: var(--sans); }
body.theme-paper .sticks__prompt strong {
  color: var(--rp-lime-ink);
  background: var(--rp-lime);
  border-radius: 6px;
  padding: 0 6px;
}
body.theme-paper .sticks__mode { color: var(--rp-mute); font-family: var(--mono); }
body.theme-paper .sticks__score strong { font-family: var(--mono); }
body.theme-paper .sticks__score span { color: var(--rp-mute); font-family: var(--mono); }

body.theme-paper .sticks__board {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 10px;
}
body.theme-paper .sticks__empty { color: var(--rp-ink-3); font-family: var(--mono); }

body.theme-paper .stick__bar {
  background: var(--rp-bg);
  border: 2px solid var(--rp-ink);
  border-radius: 4px;
}
body.theme-paper .stick:hover:not(:disabled) .stick__bar { background: var(--rp-lime); }
body.theme-paper .stick--down .stick__bar {
  background: repeating-linear-gradient(135deg, var(--rp-bg-2) 0 6px, var(--rp-bg) 6px 12px);
  border-color: var(--rp-ink);
  color: var(--rp-ink-3);
  font-family: var(--mono);
}
body.theme-paper .stick--down:hover .stick__bar { background: var(--rp-lime); color: var(--rp-lime-ink); }
body.theme-paper .stick--answer .stick__bar,
body.theme-paper .stick--won .stick__bar { background: var(--rp-lime); border-color: var(--rp-ink); }
body.theme-paper .stick--wrong .stick__bar { background: var(--rp-red); border-color: var(--rp-ink); color: var(--rp-on-fill); }

body.theme-paper .sticks__status { color: var(--rp-ink-3); font-family: var(--mono); }
body.theme-paper .sticks__status--good { color: var(--rp-green); }
body.theme-paper .sticks__status--bad { color: var(--rp-red); }

body.theme-paper .sticks__controls { border-top-color: var(--rp-ink); border-top-width: 2px; }

body.theme-paper .sticks__over {
  background: var(--rp-lime);
  color: var(--rp-lime-ink);
  border-radius: 10px;
  font-family: var(--mono);
}
body.theme-paper .sticks__over strong { font-family: var(--sans); color: var(--rp-lime-ink); }
body.theme-paper .sticks__over a { color: var(--rp-ink); font-weight: 700; }

/* ---------- flappy ---------- */

body.theme-paper .flappy {
  background: var(--rp-bg);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 16px;
}
body.theme-paper .flappy__prompt { font-family: var(--sans); }
body.theme-paper .flappy__mode { color: var(--rp-mute); font-family: var(--mono); }
body.theme-paper .flappy__stage canvas { border: 2px solid var(--rp-ink); border-radius: 10px; }
body.theme-paper .flappy__status { color: var(--rp-ink-3); font-family: var(--mono); }
body.theme-paper .flappy__fullscreen {
  border: 2px solid color-mix(in oklch, var(--rp-ink) 30%, transparent);
  color: var(--rp-ink);
}
body.theme-paper .flappy__fullscreen:hover { background: var(--rp-lime); border-color: var(--rp-ink); color: var(--rp-lime-ink); }

/* ---------- wordle ---------- */

body.theme-paper .wordle {
  background: var(--rp-bg);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 16px;
  box-shadow: var(--rp-shadow);
}
body.theme-paper .wordle__prompt { font-family: var(--sans); }
body.theme-paper .wordle__mode { color: var(--rp-mute); font-family: var(--mono); }
/* site.css sets this cell's text from --ink, a token that never flips with
   the dark toggle (only the --rp-* roles do) — so a typed letter stayed
   dark-on-dark once the cell's own background flipped to near-black. --rp-ink
   is the one that actually tracks the toggle. */
body.theme-paper .wordle__cell { background: var(--rp-bg-2); border-color: var(--rp-ink); border-radius: 6px; font-family: var(--sans); color: var(--rp-ink); }
body.theme-paper .wordle__cell--filled { border-color: var(--rp-ink); }
body.theme-paper .wordle__cell--cursor { border-color: var(--rp-ink-3); }
body.theme-paper .wordle__cell--cursor::after { background: var(--rp-ink); }
body.theme-paper .wordle__cell--hit { background: var(--rp-green); border-color: var(--rp-ink); }
body.theme-paper .wordle__cell--present { background: #d8a531; border-color: var(--rp-ink); }
body.theme-paper .wordle__cell--miss { background: var(--rp-ink-3); border-color: var(--rp-ink); }
body.theme-paper .wordle__status { color: var(--rp-red); font-family: var(--mono); }
body.theme-paper .wordle__key { background: var(--rp-bg-2); border: 2px solid var(--rp-ink); border-radius: 6px; font-family: var(--sans); color: var(--rp-ink); }
body.theme-paper .wordle__key:hover { background: var(--rp-lime); }
body.theme-paper .wordle__key--hit { background: var(--rp-green); color: var(--rp-on-fill); }
body.theme-paper .wordle__key--present { background: #d8a531; color: var(--rp-on-fill); }
body.theme-paper .wordle__key--miss { background: var(--rp-ink-3); color: var(--rp-on-fill); }
/* --rp-lime-fill/-ink (see the daily-game entry-card, the other full-bleed
   lime surface) rather than --rp-lime directly — full-bright --rp-lime is a
   fixed accent that never dims on its own, glaring against an otherwise
   near-black dark-mode page. This used to hand-roll its own dark-mode fix
   with color-mix(lime, --rp-bg-2), but oklch color-mix interpolates hue
   circularly between lime's yellow-green and --rp-bg-2's blue-gray, and the
   35%-lime result landed in teal/cyan territory — nothing like this site's
   design language. --rp-lime-fill is a fixed dark olive tone instead (same
   hue, just lower lightness/chroma), so it never drifts hue on mixing. */
body.theme-paper .wordle__over { background: var(--rp-lime-fill); color: var(--rp-lime-fill-ink); border-radius: 10px; font-family: var(--mono); }
body.theme-paper .wordle__over strong { font-family: var(--sans); color: var(--rp-lime-fill-ink); }
body.theme-paper .wordle__over a { color: var(--rp-lime-fill-ink); font-weight: 700; }
/* Inline color chips in the explainer text — same treatment as the grid
   cells above, so they're readable on the flipped dark background too. */
body.theme-paper .wordle__swatch--hit { background: var(--rp-green); border-color: var(--rp-ink); color: var(--rp-on-fill); }
body.theme-paper .wordle__swatch--present { background: #d8a531; border-color: var(--rp-ink); color: var(--rp-on-fill); }
body.theme-paper .wordle__swatch--miss { background: var(--rp-ink-3); border-color: var(--rp-ink); color: var(--rp-on-fill); }

/* --rp-ink-3 is a mid-gray in light mode (dark enough for --rp-on-fill's
   near-white text) but flips to a light gray in dark mode, so the "miss"
   tile/key/swatch above would otherwise pair light text on a light-gray
   tile. --rp-fill/--rp-on-fill don't flip, so pin the text to --rp-fill
   (fixed dark ink) once the tile itself has gone light. */
/* ---------- game badge (shared: nav dropdown, achievements, stats hub,
   toast) ---------- */

/* Never got this theme's sticker treatment at all — every other small
   graphic element here (the wordmark, buttons, chips) carries a bold ink
   border and a hard offset shadow; without either, these plain flat
   colored squares read as generic/off-brand next to everything around
   them. Border width/shadow offset are smaller than --rp-border/
   --rp-shadow-sm, which are sized for much bigger elements (the wordmark,
   panels) — at this badge's 26px size, that weight would swallow it. */
body.theme-paper .game-badge {
  border: 2px solid var(--rp-ink);
  box-shadow: 2px 2px 0 var(--rp-ink);
}

/* ---------- achievements ---------- */
body.theme-paper .achievements-progress__bar { background: var(--rp-bg-2); }
body.theme-paper .achievements-progress__fill { background: var(--rp-green); }
body.theme-paper .achievements-progress__count { color: var(--rp-ink); }
body.theme-paper .achievements-grid__heading { color: var(--rp-ink-2); }
body.theme-paper .achievement-card {
  background: var(--rp-bg-2);
  border-color: var(--rp-ink);
  border-left-color: color-mix(in oklch, var(--card-accent, var(--rp-mute)) 55%, transparent);
}
body.theme-paper .achievement-card--earned {
  background: color-mix(in oklch, var(--card-accent) 16%, var(--rp-bg));
  border-color: color-mix(in oklch, var(--card-accent) 45%, var(--rp-ink));
  border-left-color: var(--card-accent);
}
body.theme-paper .achievement-card__label { color: var(--rp-ink); }
body.theme-paper .achievement-card__desc { color: var(--rp-ink-3); }
body.theme-paper .achievement-card__check { border-color: var(--rp-bg-2); }
body.theme-paper .achievement-card--earned .achievement-card__check { border-color: var(--rp-bg); }

/* ---------- 2048 ----------
   The numbered tile palette is left alone — like wordle's green/yellow/gray
   marks, it's the game's own established colors, not a site theme choice —
   every tier pins its own --tile-bg/--tile-ink in site.css, so tiles read
   correctly without help here. Only the board container and the empty-cell
   background pick up the paper theme's tokens. */
body.theme-paper .game2048__grid { background: var(--rp-bg-2); border: 2px solid var(--rp-ink); border-radius: 10px; }
/* .game2048__cell is only ever the static empty-slot background now (see
   site.css: live tiles are .game2048__tile, a separate overlay layer) —
   this used to also match tiles (same class, keyed by a [data-v]
   attribute) and, being more specific than site.css's
   .game2048__cell[data-v], clobbered every tile's colored background
   regardless of value, so the whole board rendered flat gray. */
body.theme-paper .game2048__cell { background: color-mix(in oklch, var(--rp-ink) 6%, transparent); }

/* ---------- reaction time ---------- */

/* Each cell gets its own hue (a fixed --cell-hue, not a theme role) rather
   than one flat neutral fill for all nine — idle it's a faint tint, lit it
   jumps to full saturation, so the "poppy" read comes from color variety
   rather than just the flame-orange flash the site's other lit-states use. */
body.theme-paper .reaction__cell {
  background: oklch(0.94 0.03 var(--cell-hue, 250) / 1);
  border-color: color-mix(in oklch, oklch(0.6 0.18 var(--cell-hue, 250)) 45%, var(--rp-ink) 55%);
}
html[data-theme="dark"] body.theme-paper .reaction__cell {
  background: oklch(0.28 0.05 var(--cell-hue, 250));
}
body.theme-paper .reaction__cell:nth-child(1) { --cell-hue: 20; }
body.theme-paper .reaction__cell:nth-child(2) { --cell-hue: 55; }
body.theme-paper .reaction__cell:nth-child(3) { --cell-hue: 95; }
body.theme-paper .reaction__cell:nth-child(4) { --cell-hue: 140; }
body.theme-paper .reaction__cell:nth-child(5) { --cell-hue: 175; }
body.theme-paper .reaction__cell:nth-child(6) { --cell-hue: 220; }
body.theme-paper .reaction__cell:nth-child(7) { --cell-hue: 265; }
body.theme-paper .reaction__cell:nth-child(8) { --cell-hue: 310; }
body.theme-paper .reaction__cell:nth-child(9) { --cell-hue: 350; }
body.theme-paper .reaction__cell--lit {
  background: oklch(0.72 0.22 var(--cell-hue, 250));
  border-color: oklch(0.72 0.22 var(--cell-hue, 250));
  box-shadow: 0 0 0 8px oklch(0.72 0.22 var(--cell-hue, 250) / .3);
}
body.theme-paper .reaction__start .btn { border-radius: 28px; }

html[data-theme="dark"] body.theme-paper .wordle__cell--miss { color: var(--rp-fill); }
html[data-theme="dark"] body.theme-paper .wordle__key--miss,
html[data-theme="dark"] body.theme-paper .wordle__swatch--miss { color: var(--rp-fill); }

/* ---------- sudoku ---------- */

body.theme-paper .sudoku {
  background: var(--rp-bg);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 16px;
  box-shadow: var(--rp-shadow);
}
body.theme-paper .sudoku__prompt { font-family: var(--sans); }
body.theme-paper .sudoku__mode { color: var(--rp-mute); font-family: var(--mono); }
body.theme-paper .sudoku__difficulty { color: var(--rp-ink-3); font-family: var(--mono); }
body.theme-paper .sudoku__difficulty select {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 8px;
  color: var(--rp-ink);
  font-family: var(--sans);
}
body.theme-paper .sudoku__difficulty select:hover { border-color: var(--rp-ink-2); }
body.theme-paper .sudoku__difficulty select:focus-visible { outline: 2px solid var(--rp-lime); outline-offset: 2px; }
body.theme-paper .board-filter__select-wrap::after { color: var(--rp-ink-3); }
body.theme-paper .board-filter__select {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 8px;
  color: var(--rp-ink);
  font-family: var(--sans);
}
body.theme-paper .board-filter__select:hover { border-color: var(--rp-ink-2); }
body.theme-paper .board-filter__select:focus-visible { outline: 2px solid var(--rp-lime); outline-offset: 2px; }
body.theme-paper .sudoku__grid { border-color: var(--rp-ink); border-radius: 10px; overflow: hidden; }
body.theme-paper .sudoku__cell {
  background: var(--rp-bg-2);
  border-color: color-mix(in oklch, var(--rp-ink) 14%, transparent);
  color: var(--rp-ink-2);
  font-family: var(--sans);
}
body.theme-paper .sudoku__cell--top { border-top-color: var(--rp-ink); }
body.theme-paper .sudoku__cell--left { border-left-color: var(--rp-ink); }
body.theme-paper .sudoku__cell--bottom { border-bottom-color: var(--rp-ink); }
body.theme-paper .sudoku__cell--right { border-right-color: var(--rp-ink); }
/* Given digits (the clues) read as plain ink in both themes; a player's own
   entries stay pure white on the flipped dark background rather than the
   dimmer --rp-ink-2 used elsewhere — small digits in a 9x9 grid are the one
   place this site's usual "muted secondary text" reads as low-contrast
   rather than intentionally quiet.

   That earlier fix for legibility had a side effect: in dark mode --rp-ink
   itself flips to a near-white too, so a bold given digit and a bright
   white entry ended up almost the same color — bold weight was the only
   thing left telling them apart, easy to miss glancing at a 9x9 grid, and
   the reported cause of more than one "this puzzle is broken" that turned
   out to be a player's own unflagged entry. A shaded background on given
   cells gives a second, color-independent cue that doesn't fight the
   dark-mode contrast fix above — a given cell now looks visibly like a
   fixed clue, a played cell looks like open board, in every theme. */
body.theme-paper .sudoku__cell--given { color: var(--rp-ink); background: color-mix(in oklch, var(--rp-ink) 9%, var(--rp-bg-2)); }
html[data-theme="dark"] body.theme-paper .sudoku__cell { color: #fff; }
html[data-theme="dark"] body.theme-paper .sudoku__cell--given { color: var(--rp-ink); }
body.theme-paper .sudoku__cell--peer { background: color-mix(in oklch, var(--rp-lime) 16%, var(--rp-bg-2)); }
body.theme-paper .sudoku__cell--match { color: var(--rp-green); }
body.theme-paper .sudoku__cell--selected { background: var(--rp-lime); color: var(--rp-lime-ink); }
body.theme-paper .sudoku__cell--selected.sudoku__cell--given { color: var(--rp-lime-ink); }
body.theme-paper .sudoku__cell--bad { color: var(--rp-red); background: color-mix(in oklch, var(--rp-red) 32%, var(--rp-bg-2)); }
/* The dark-theme base color rule above (line 429) targets .sudoku__cell
   directly and outspecifies the plain .sudoku__cell--bad selector, so a
   conflicting digit was rendering plain white instead of red — the only
   surviving cue was a faint background tint, easy to miss next to the
   teal peer/selection highlighting. This matches that rule's specificity
   so a genuine conflict is never silently invisible in dark mode. */
html[data-theme="dark"] body.theme-paper .sudoku__cell--bad { color: var(--rp-red); }
body.theme-paper .sudoku__cell--pulse { animation-name: sudoku-pulse-paper; }
@keyframes sudoku-pulse-paper {
  0%, 100% { box-shadow: none; }
  35% { box-shadow: inset 0 0 0 2px var(--rp-red); }
}
body.theme-paper .sudoku__notes span { color: var(--rp-ink-3); }
html[data-theme="dark"] body.theme-paper .sudoku__notes span { color: var(--rp-ink-3); }
body.theme-paper .sudoku__tool {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 8px;
  color: var(--rp-ink-2);
}
body.theme-paper .sudoku__tool:hover { background: var(--rp-lime); color: var(--rp-lime-ink); }
body.theme-paper .sudoku__tool--active,
body.theme-paper .sudoku__tool[aria-pressed="true"] { background: var(--rp-lime); color: var(--rp-lime-ink); }
body.theme-paper .sudoku__key {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 8px;
  color: var(--rp-ink);
}
body.theme-paper .sudoku__key:hover { background: var(--rp-lime); }
body.theme-paper .sudoku__key--done { color: var(--rp-mute); background: transparent; }
body.theme-paper .sudoku__pause {
  background: transparent;
  border: 2px solid color-mix(in oklch, var(--rp-ink) 30%, transparent);
  color: var(--rp-ink);
}
body.theme-paper .sudoku__pause:hover,
body.theme-paper .sudoku__pause[aria-pressed="true"] { background: var(--rp-lime); border-color: var(--rp-ink); color: var(--rp-lime-ink); }
body.theme-paper .sudoku__paused {
  background: var(--rp-bg);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 10px;
}

/* ---------- rangeinput (the odds dial) ---------- */

/* color, not just font-family — site.css's --ink-2 is a fixed dark-gray
   tuned for a light background and never adapts to dark mode, so this
   text (Sticks' "N sticks · pays N points" readout) was near-unreadable
   against the paper theme's dark background. */
body.theme-paper .range__value { font-family: var(--mono); color: var(--rp-ink-2); }
body.theme-paper input[type="range"] { accent-color: var(--rp-lime); }

/* ---------- forms (print cost, login) ---------- */

body.theme-paper .field .eyebrow { color: var(--rp-mute); }
body.theme-paper .input {
  background: var(--rp-bg);
  border: 2px solid var(--rp-ink);
  border-radius: 8px;
}
body.theme-paper .input input { font-family: var(--mono); color: var(--rp-ink); }
body.theme-paper .input input:focus-visible { outline-color: var(--rp-ink); }
body.theme-paper .input__prefix,
body.theme-paper .input__suffix { color: var(--rp-mute); font-family: var(--mono); }
body.theme-paper .input__suffix { border-left-color: var(--rp-ink); border-left-width: 2px; }
body.theme-paper .field__hint--ok { color: var(--rp-green); }
body.theme-paper .field__hint--bad { color: var(--rp-red); }
body.theme-paper .input--valid { border-color: var(--rp-green); }
body.theme-paper .input--invalid { border-color: var(--rp-red); }
body.theme-paper .range input { background: var(--rp-bg-2); }
body.theme-paper .range input::-webkit-slider-thumb { background: var(--rp-ink); }
body.theme-paper .range input::-moz-range-thumb { background: var(--rp-ink); }

body.theme-paper .btn--ghost { border: 2px solid var(--rp-ink); color: var(--rp-ink); }

body.theme-paper .result {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  border-radius: 14px;
}
body.theme-paper .result .eyebrow { color: var(--rp-lime); }
body.theme-paper .result__total { font-family: var(--mono); }
body.theme-paper .result__lines { color: color-mix(in oklch, var(--rp-on-fill) 75%, transparent); }
body.theme-paper .result__actions { border-top-color: color-mix(in oklch, var(--rp-on-fill) 18%, transparent); }

body.theme-paper .share-card {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 10px;
}
body.theme-paper .share-card__brand { font-family: var(--sans); }
body.theme-paper .share-card__total { font-family: var(--mono); }
body.theme-paper .share-bar span:nth-child(1) { background: var(--rp-lime); }
body.theme-paper .share-bar span:nth-child(2) { background: var(--rp-ink); }
body.theme-paper .share-bar span:nth-child(3) { background: var(--rp-mute); }
body.theme-paper .share-bar span:nth-child(4) { background: var(--rp-bg-2); border: 1px solid var(--rp-ink); }

body.theme-paper .saved,
body.theme-paper .toast {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  font-family: var(--mono);
  border-radius: 10px;
}

/* ---------- switch comparator (filters + table) ---------- */

body.theme-paper .filters__title { font-family: var(--sans); }
body.theme-paper .check__box { border: 2px solid var(--rp-ink); border-radius: 3px; }
body.theme-paper .check input:checked + .check__box { border-color: var(--rp-ink); background: var(--rp-lime); }
body.theme-paper .check input:focus-visible + .check__box { outline-color: var(--rp-ink); }
body.theme-paper .check:hover .check__box { border-color: var(--rp-lime); }
body.theme-paper .chip { border: 2px solid var(--rp-ink); color: var(--rp-ink); border-radius: 999px; font-family: var(--mono); }
/* site.css's own :hover:not([aria-pressed]) rule sets border-color/color
   too (to the plain --green/--ink it uses everywhere else) — matching
   specificity meant only `background` here ever actually won, leaving a
   plain-green border and a color that goes invisible on a dark page. Pin
   all three so the paper theme's hover is self-consistent. */
body.theme-paper .chip:hover:not([aria-pressed="true"]) {
  background: var(--rp-bg-2);
  border-color: var(--rp-ink);
  color: var(--rp-ink);
}
body.theme-paper .chip[aria-pressed="true"] { background: var(--rp-lime); color: var(--rp-lime-ink); border-color: var(--rp-ink); }
body.theme-paper .chip:focus-visible { outline-color: var(--rp-lime); }
body.theme-paper .chip[aria-pressed="true"]:hover { background: color-mix(in oklch, var(--rp-lime) 80%, var(--rp-ink)); }
body.theme-paper .board-switch__toggle { background: var(--rp-bg); border: 2px solid var(--rp-ink); border-radius: 10px; color: var(--rp-ink); }
body.theme-paper .board-switch__toggle:hover { background: var(--rp-bg-2); }
/* Only touches the dropdown presentation .chips#board-switch gets below
   760px (site.css) — scoped the same way so the desktop inline chip row
   (same element) doesn't pick up a boxed border/shadow it never had. */
@media (max-width: 760px) {
  body.theme-paper .chips#board-switch { background: var(--rp-bg); border: 2px solid var(--rp-ink); border-radius: 10px; box-shadow: var(--rp-shadow); overflow: hidden; }
  body.theme-paper .chips#board-switch .chip { border-bottom-color: color-mix(in oklch, var(--rp-ink) 14%, transparent); }
  body.theme-paper .chips#board-switch .chip[aria-pressed="true"] { background: var(--rp-lime); color: var(--rp-lime-ink); }
}
body.theme-paper .filters__reset { color: var(--rp-ink); border-top-color: var(--rp-ink); font-family: var(--mono); }
body.theme-paper .filters__reset:hover { color: var(--rp-mute); }

body.theme-paper .results-count { font-family: var(--sans); }
body.theme-paper .results-sort { color: var(--rp-mute); font-family: var(--mono); }

body.theme-paper .table { background: var(--rp-bg); border: 2px solid var(--rp-ink); border-radius: 10px; overflow: hidden; }
body.theme-paper .trow { border-bottom-color: color-mix(in oklch, var(--rp-ink) 14%, transparent); }
body.theme-paper .trow--head {
  background: var(--rp-bg-2);
  border-bottom: 2px solid var(--rp-ink);
  color: var(--rp-ink-3);
  font-family: var(--mono);
}
body.theme-paper .trow:hover { background: var(--rp-bg-2); }
body.theme-paper .trow--head:hover { background: var(--rp-bg-2); }
body.theme-paper .trow--picked,
body.theme-paper .trow--picked:hover { background: color-mix(in oklch, var(--rp-lime) 35%, var(--rp-bg)); }
body.theme-paper .trow__name { font-family: var(--sans); }
body.theme-paper .trow__cell { font-family: var(--mono); color: var(--rp-ink-2); }
body.theme-paper .table__empty { color: var(--rp-ink-3); }

body.theme-paper .compare-tray {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  border-top: 3px solid var(--rp-ink);
}
body.theme-paper .tray-chip {
  background: color-mix(in oklch, var(--rp-on-fill) 12%, transparent);
  color: var(--rp-on-fill);
  border-radius: 999px;
  font-family: var(--sans);
}
body.theme-paper .read-next { font-family: var(--sans); }

/* ---------- crypto desk ---------- */

body.theme-paper .settle-banner {
  background: var(--rp-lime);
  color: var(--rp-lime-ink);
  border: 2px solid var(--rp-ink);
  border-radius: 10px;
  font-family: var(--mono);
}
body.theme-paper .portfolio {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  border-radius: 14px;
}
body.theme-paper .portfolio__value strong { font-family: var(--mono); }
body.theme-paper .portfolio__chart { background: color-mix(in oklch, var(--rp-on-fill) 6%, transparent); }
body.theme-paper .portfolio__chart > div { background: var(--rp-lime); }
body.theme-paper .chart-range button { color: var(--rp-on-fill); border-color: color-mix(in oklch, var(--rp-on-fill) 25%, transparent); }
body.theme-paper .chart-range button:hover { border-color: color-mix(in oklch, var(--rp-on-fill) 55%, transparent); }
body.theme-paper .chart-range button[aria-pressed="true"] { background: var(--rp-on-fill); color: var(--rp-fill); border-color: var(--rp-on-fill); }
body.theme-paper .ledger { background: var(--rp-bg); border: 2px solid var(--rp-ink); border-radius: 14px; }
body.theme-paper .ledger__rows { font-family: var(--mono); color: var(--rp-ink-2); }
body.theme-paper .ledger__row--total { border-top-color: var(--rp-ink); }
body.theme-paper .leaders { font-family: var(--mono); }
body.theme-paper .leaders__row--you { color: var(--rp-ink); font-weight: 700; }

body.theme-paper .call-card { background: var(--rp-bg); border: 3px solid var(--rp-ink); border-radius: 16px; }
body.theme-paper .call-card__symbol,
body.theme-paper .call-card__price { font-family: var(--mono); }
body.theme-paper .call-card__sub { color: var(--rp-ink-3); font-family: var(--sans); }
body.theme-paper .call-card__sub--warn { color: var(--rp-red); }

body.theme-paper .call-btn { background: var(--rp-fill); color: var(--rp-on-fill); border-radius: 10px; }
body.theme-paper .call-btn__label { font-family: var(--sans); }
body.theme-paper .call-btn__note { font-family: var(--mono); }
body.theme-paper .call-btn--yes { background: var(--rp-lime); color: var(--rp-lime-ink); }
body.theme-paper .call-btn--neutral {
  background: var(--rp-bg-2);
  color: var(--rp-ink);
  border: 2px solid var(--rp-ink);
}
body.theme-paper .call-btn--neutral .call-btn__note { color: var(--rp-mute); }
body.theme-paper .call-btn[aria-pressed="true"] { outline-color: var(--rp-ink); }
body.theme-paper .call-btn:hover:not([disabled]) { box-shadow: var(--rp-shadow-sm); }
body.theme-paper .call-meta { color: var(--rp-mute); font-family: var(--mono); }
body.theme-paper .trade-feedback { font-family: var(--sans); border-radius: 8px; }
body.theme-paper .trade-feedback--good { background: color-mix(in oklch, var(--rp-green) 16%, var(--rp-bg-2)); color: var(--rp-green); }
body.theme-paper .trade-feedback--bad { background: color-mix(in oklch, var(--rp-red) 16%, var(--rp-bg-2)); color: var(--rp-red); }
body.theme-paper .trade-feedback--neutral { background: var(--rp-bg-2); color: var(--rp-ink-2); }

/* ---------- leaderboard ---------- */

body.theme-paper .rank { font-family: var(--mono); }
body.theme-paper .rank-note { color: var(--rp-ink-3); font-family: var(--mono); }
body.theme-paper .board-scope__code { color: var(--rp-ink-3); font-family: var(--mono); }

/* ---------- long-form (guide-switches) ---------- */

body.theme-paper .prose h2 { font-family: var(--sans); }
body.theme-paper .prose p, body.theme-paper .prose li { color: var(--rp-ink-2); font-family: var(--sans); }
body.theme-paper .prose strong { color: var(--rp-ink); }

/* ---------- first-visit welcome ---------- */

body.theme-paper .intro-tour {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 16px;
  box-shadow: var(--rp-shadow);
}
body.theme-paper .intro-tour__eyebrow { color: var(--rp-lime); }
body.theme-paper .intro-tour__title { font-family: var(--sans); color: var(--rp-on-fill); }
body.theme-paper .intro-tour__num {
  background: var(--rp-lime);
  color: var(--rp-lime-ink);
  font-family: var(--mono);
}
body.theme-paper .intro-tour__copy { font-family: var(--sans); color: color-mix(in oklch, var(--rp-on-fill) 80%, transparent); }
body.theme-paper .intro-tour__copy strong { color: var(--rp-on-fill); }
body.theme-paper .intro-tour__close:hover { color: var(--rp-on-fill); background: color-mix(in oklch, var(--rp-on-fill) 12%, transparent); }

/* ---------- consent banner ----------
   Listed further down as one of the fixed-dark-card components, but it
   never actually picked up the paper theme's border/radius/shadow
   language — it sat as a flat rectangle with a colored edge, which read as
   a bolted-on generic cookie banner rather than part of this design. */
body.theme-paper .consent {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  border: var(--rp-border) solid var(--rp-ink);
  border-left: var(--rp-border) solid var(--rp-lime);
  border-radius: 14px;
  box-shadow: var(--rp-shadow);
}
body.theme-paper .consent__text strong { font-family: var(--sans); color: var(--rp-on-fill); }
body.theme-paper .consent__text p { color: color-mix(in oklch, var(--rp-on-fill) 80%, transparent); }
body.theme-paper .consent__text a { color: var(--rp-lime); }
body.theme-paper .consent__btn {
  border-radius: 999px;
  border-color: color-mix(in oklch, var(--rp-on-fill) 45%, transparent);
  color: var(--rp-on-fill);
}
body.theme-paper .consent__btn:hover { background: color-mix(in oklch, var(--rp-on-fill) 12%, transparent); }
body.theme-paper .consent__btn--primary { background: var(--rp-lime); border-color: var(--rp-lime); color: var(--rp-lime-ink); }
body.theme-paper .consent__btn--primary:hover { background: color-mix(in oklch, var(--rp-lime) 80%, var(--rp-ink)); }
body.theme-paper .consent__keep { color: color-mix(in oklch, var(--rp-on-fill) 70%, transparent); }
body.theme-paper .consent__keep:hover { color: var(--rp-on-fill); }

/* ---------- game gate ---------- */

body.theme-paper .game-gate {
  background: var(--rp-fill);
  color: var(--rp-on-fill);
  border: var(--rp-border) solid var(--rp-ink);
  border-radius: 16px;
  box-shadow: var(--rp-shadow);
}
body.theme-paper .game-gate__eyebrow { color: var(--rp-lime); }
body.theme-paper .game-gate__title { font-family: var(--sans); color: var(--rp-on-fill); }
body.theme-paper .game-gate__body { font-family: var(--sans); color: color-mix(in oklch, var(--rp-on-fill) 80%, transparent); }
body.theme-paper .game-gate__actions .btn--ghost { border-color: color-mix(in oklch, var(--rp-on-fill) 30%, transparent); color: var(--rp-on-fill); }
body.theme-paper .game-gate__actions .btn--ghost:hover { background: color-mix(in oklch, var(--rp-on-fill) 12%, transparent); }

/* ---------- accounts (login) ---------- */

body.theme-paper .auth__panel { border: 3px solid var(--rp-ink); border-radius: 14px; overflow: hidden; }
body.theme-paper .auth__tabs { border-bottom: 2px solid var(--rp-ink); }
body.theme-paper .auth__tab[aria-selected="true"] { color: var(--rp-ink); border-bottom-color: var(--rp-lime); }
body.theme-paper .auth__tab:hover:not([aria-selected="true"]) { color: var(--rp-ink); border-bottom-color: var(--rp-ink-3); }
body.theme-paper .auth__list strong { color: var(--rp-ink); }
body.theme-paper .auth__note { color: var(--rp-ink-3); }
body.theme-paper .auth__offline code { background: var(--rp-bg-2); padding: 0 4px; }
body.theme-paper .auth__done-title { font-family: var(--sans); }

/* ---------- legal pages ---------- */

/* site.css's own .legal__todo is a fixed light-mode callout (pale yellow,
   dark-brown text) — this only ever overrode the background to the flipped
   --rp-bg-2 role, so in dark mode the text stayed that same dark brown on
   a background that had gone from pale-yellow to near-black. Overriding the
   text colors too, not just the background, is what actually makes it
   legible in both themes. */
body.theme-paper .legal__todo {
  background: var(--rp-bg-2);
  border: 2px solid var(--rp-ink);
  border-radius: 10px;
  font-family: var(--sans);
  color: var(--rp-ink-2);
}
body.theme-paper .legal__todo strong { color: var(--rp-ink); }
/* Same gap as .legal__todo above: site.css's .legal p/li read from --ink-2,
   a token that only ever existed for the fixed-light page, so this long-form
   prose (the bulk of both legal pages) stayed dark-gray-on-near-black once
   the page itself flipped. .legal code is the opposite case — its own
   background (--well) never flips, so it needs the base *non-flipping*
   --ink kept explicit here rather than inheriting the now-light paragraph
   color, or the code chips go light-on-light instead. */
body.theme-paper .legal p,
body.theme-paper .legal li { color: var(--rp-ink-2); }
body.theme-paper .legal code { color: var(--ink); }
body.theme-paper .legal h2 { font-family: var(--sans); }

/* ---------- dark-mode gaps ----------
   Muted/secondary text that only ever existed on the fixed-light page
   background in site.css — never re-declared here, so it stayed the same
   dark-gray-on-white color even once the page background flips to near-
   black in dark mode, reading as invisible or near-invisible. Everything
   below sits directly on the page (or a surface that already flips, like
   .share-card), as opposed to components that are deliberately a fixed
   dark card in both themes (.consent, .to-top, .filters__jump, .group-code,
   .wall-counter — those keep var(--ink)/var(--card) on purpose, see the
   note at the top of this file). */
body.theme-paper .wall-end p,
body.theme-paper .wall-intro__note,
body.theme-paper .board-scope__code,
body.theme-paper .prose__standfirst,
body.theme-paper .prose__foot,
body.theme-paper .auth__intro p,
body.theme-paper .auth__done p,
body.theme-paper .saved__row,
body.theme-paper .saved__empty,
body.theme-paper .streak-caption,
body.theme-paper .share-card__meta {
  color: var(--rp-ink-3) !important;
}
body.theme-paper .wall-intro p,
body.theme-paper .ad-wall__more {
  color: var(--rp-mute);
}
body.theme-paper .prose__foot { border-top-color: color-mix(in oklch, var(--rp-ink) 14%, transparent); }
body.theme-paper .saved__row { border-bottom-color: color-mix(in oklch, var(--rp-ink) 14%, transparent); }
body.theme-paper .auth__done-links a,
body.theme-paper .saved__name { color: var(--rp-green); }
body.theme-paper .saved--groups .saved__row { background: var(--rp-bg-2); border-color: var(--rp-ink); }

/* The 1B mockup was a fixed light design; dark mode (top of file, and
   assets/js/theme-toggle.js) is this site's own extension of it, not part
   of the original mockup. */
