/* Charcoal dark — the site's default theme, layered over style.css.
   This stylesheet is linked for everyone except accounts that selected the
   Space theme (Settings → Appearance); Space ships the base Void/Cyberpunk
   look byte-identical without it.

   Palette is a crisp blackish/grayish charcoal: deep neutral-cool surfaces
   (a touch of blue in the grays so nothing can read as brown or sepia), calm
   gray text, a blue interactive accent, and no glow/starfield atmosphere.
   Contrast comes from DEPTH, not color (docs/memory/clients/web/design-system.md),
   with values measured from live lichess dark: the page opens with a lighter
   116px gradient band; body text is crisp with NO shadow while control labels
   get lichess's 0.5px letterpress; big display text is thin (weight 300) and
   muted, never thick white; boxes have 7px radius and a layered material
   shadow; the move panel uses a lighter zebra strip for move numbers and
   RAISED zebra blocks for variations (bright text on a lighter block — never
   dim text on a darker well). Component rules stay in the shared stylesheets
   and retheme through the token overrides below — new colors belong on
   tokens, not on per-component overrides here. */

@font-face {
  font-family: 'Noto Sans';
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/noto-sans-latin.00427f129772.woff2") format('woff2');
  unicode-range:
    U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Noto Sans';
  font-display: swap;
  font-weight: 100 900;
  src: url("../fonts/noto-sans-latin-ext.2ce8d5ae4de5.woff2") format('woff2');
  unicode-range:
    U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF,
    U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

body.site-theme-charcoal {
  /* Rounded-corner system (owner call: round beats straight edges — lichess
     at its 15px roundness setting is the reference). Controls sit at 6px,
     boxes/cards at 8px. */
  --radius-control: 6px;
  --radius-card: 8px;
  /* Keep each -rgb triplet in sync with its color token, exactly like :root. */
  --void-rgb: 19, 20, 22;
  --deep-rgb: 23, 25, 28;
  --surface-rgb: 30, 33, 36;
  --cyan-rgb: 54, 146, 231;
  --gold-rgb: 179, 147, 98;
  --amber-rgb: 213, 145, 32;
  --mint-rgb: 98, 153, 36;
  --white-rgb: 185, 190, 196;
  --danger-rgb: 210, 77, 77;
  /* Neutral surface ramp: accent color stays in text (--cyan), while every
     glass fill, tinted border, well, panel, and glow goes cool gray. */
  --tint-rgb: 175, 183, 192;
  /* Chrome text goes body-gray like lichess: blue stays on content links,
     hover/focus/selected accents, and data colors only. */
  --chrome: var(--white);
  --tint: #363a3f;
  --glass-rgb: 36, 39, 43;
  --ink-rgb: 11, 12, 14;
  --panel-rgb: 30, 33, 36;
  --slate-rgb: 36, 39, 43;
  --silver-rgb: 143, 149, 156;
  --void: #131416;         /* page background — deep neutral-cool charcoal */
  --deep: #17191c;
  --surface: #1e2124;      /* card/panel background */
  --glass: rgba(36, 39, 43, 0.55);
  --border: #363a3f;
  --cyan: #3692e7;         /* interactive/link accent — hsl(209,79%,56%) */
  --cyan-glow: rgba(0, 0, 0, 0.4);
  --gold: #b39362;         /* structure/data accent — muted antique brass,
                              charcoal's counterpart of the default theme's
                              gold: warm enough to register as a second voice
                              against the blue accent, muted enough to stay
                              structural rather than decorative */
  --amber: #d59120;        /* caution states keep lichess's own orange */
  --gold-glow: rgba(0, 0, 0, 0.4);
  --mint: #629924;         /* positive/live accent — hsl(88,62%,37%) */
  --white: #b9bec4;        /* body text */
  --muted: #8f959c;        /* holds ≥4.5:1 on --void and --surface */
  --data-secondary: #8f959c;
  --danger: #d24d4d;       /* lichess-red lifted two steps so danger text stays
                              readable on the dark surface ramp */
  --name: #b18cf0;         /* the name of a person/event/series/collection when
                              that name is NOT a link. Hue 262 is the one slot
                              nothing else in the palette occupies, so a name can
                              never be mistaken for a link (cyan), a mark (gold),
                              a win (mint) or a loss (danger). 6.1:1 on --surface
                              against link cyan's 4.9:1.
                              Saturation is deliberately high (~77% vs the 40% of
                              the first attempt at #b0a6d9): a low-saturation
                              violet reads as another grey on this ramp, and a
                              name colour that reads as grey defeats its whole
                              purpose (owner, 2026-08-04: "it still looks too
                              much like grey, needs more color"). */
  --name-rgb: 177, 140, 240;

  /* ── Text tiers (docs/memory/clients/web/design-system.md → "charcoal's three type
     tiers"). Scan is what the eye lands on: names, titles, figures, results.
     Read is prose. Ignore is labels and captions. Nothing else. */
  --tier-scan: #dfe3e8;
  --tier-read: #b9bec4;
  --tier-ignore: #8f959c;

  /* ── Type scale. Charcoal owns its own metrics, not just its own face: the
     Space rules are built around condensed display faces and leak 0.62–0.74rem
     sizes with 1–3px tracking into Noto Sans, where they read as thin grey
     wire. Floor is 0.9rem for anything a user has to read. */
  --fs-page-title: clamp(2rem, 4.4vw, 2.9rem);
  --fs-work-title: clamp(1.55rem, 2.6vw, 1.9rem);
  --fs-wordmark: clamp(2.8rem, 8vw, 5.5rem);
  --fs-section: 1.2rem;
  --fs-promotion-title: 1.5rem;
  --fs-name: 1.08rem;
  --fs-body: 1rem;
  --fs-prose: 1.05rem;     /* long-form reading sits one notch above UI body */
  --fs-meta: 0.92rem;
  --fs-label: 0.9rem;

  /* Shared shallow-key material. Roles own the anatomy; content variants may
     borrow this face, edge and catch without inheriting button dimensions. */
  --key-metal-face: linear-gradient(180deg, #454c54, #333940);
  --key-metal-face-hover: linear-gradient(180deg, #525a63, #3e454c);
  --key-metal-face-pressed: linear-gradient(180deg, #3b424a, #2e343a);
  --key-metal-edge: rgba(0, 0, 0, 0.55);
  --key-metal-catch: inset 0 1px 0 rgba(255, 255, 255, 0.07);
  --key-metal-catch-pressed: inset 0 1px 0 rgba(255, 255, 255, 0.035);
  --key-metal-seat: 0 1px 2px rgba(0, 0, 0, 0.5);
  --key-metal-ink-active: #ffffff;

  /* Daily adapts the accepted native feature card as a compact raised key: a
     visibly top-lit satin face, brass frame, lower bevel and tactile states. */
  --daily-face-top: #323438;
  --daily-face-bottom: #1c1e21;
  --daily-face-hover-top: #393c40;
  --daily-face-hover-bottom: #232629;
  --daily-face-pressed-top: #2b2e32;
  --daily-face-pressed-bottom: #181a1d;
  --daily-frame: rgba(var(--gold-rgb), 0.69);
  --daily-frame-hover: rgba(var(--gold-rgb), 0.84);
  --daily-frame-pressed: rgba(var(--gold-rgb), 0.56);
  --daily-frame-radius: 12px;

  /* Page-title ink: scan tier, one step brighter than body grey. Titles are
     solid — the animated hero sheen this token used to feed was tried five
     ways and dropped; see the page-title role in roles.css. */
  --title-ink: #ced3d9;

  /* lichess's signature page depth: a lighter band at the very top fading
     into the dark page over 116px (theirs: rgb(46,42,36)→rgb(22,21,18)),
     adapted to the cool ramp. The trailing color keeps everything below the
     band solid page-dark. */
  background: linear-gradient(180deg, #262a30, #131416 116px) #131416;
  cursor: auto;
}

/* One neutral text face everywhere, mirroring how alternate reading fonts
   replace every face. An explicit non-default reading font still wins: these
   rules only apply while the reading font is the site default. */
body.site-theme-charcoal.reading-font-site-default,
body.site-theme-charcoal.reading-font-site-default * {
  font-family: 'Noto Sans', 'Segoe UI', system-ui, Roboto, Helvetica, Arial, sans-serif;
}

/* Typography: body text is crisp with no shadow, exactly like lichess dark —
   a blanket letterpress makes dense reading text muddy, so it is reserved
   for control labels only (see the buttons block, which wins at higher
   specificity). This blanket rule also keeps the default theme's neon glows
   from leaking through. No ambient backdrop layers: the starfield and galaxy
   renderers in main.js also skip their work when a site-theme-* class is
   present; the display-none rules are the no-JS guarantee. */
body.site-theme-charcoal,
body.site-theme-charcoal *,
body.site-theme-charcoal *::before,
body.site-theme-charcoal *::after {
  text-shadow: none !important;
}
body.site-theme-charcoal::before {
  content: none;
}
body.site-theme-charcoal .corner,
body.site-theme-charcoal .grid-overlay,
body.site-theme-charcoal #stars,
body.site-theme-charcoal .galaxy-field {
  display: none;
}

/* The hero decor washes the dark page in soft gray fog: the skewed stripe
   panel and rule behind the wordmark, the knight halo drop-shadows, and the
   knight ground glow. Charcoal drops all of it for a crisp flat page. */
body.site-theme-charcoal .header::before,
body.site-theme-charcoal .header::after {
  content: none;
}
body.site-theme-charcoal .chess-node {
  filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.55));
}
body.site-theme-charcoal .chess-node::after {
  display: none;
}
body.site-theme-charcoal .header-divider {
  animation: none;
  background: var(--border);
}

/* Hero/dossier/bio titles now belong to the `page-title` role in roles.css:
   the thin weight-300 display treatment is reserved for the CLASSIC CHESS
   wordmark, and every other title is a scan-tier title that happens to be
   large. Applying "thin and muted" to all of them is what produced page
   after page of oversized thin grey headings. */

/* Gold marks page structure in the default theme; charcoal keeps that same
   hierarchy through the brass --gold token above — headings, epithets,
   section marks, table accent columns, and toplines all keep a distinct
   accent instead of collapsing into body gray. */

/* The knight keeps its blue paint — it is the one colorful brand mark on the
   page — just calmed a touch so the neon default sits well on flat charcoal.
   This applies to the static fallback only: that artwork has the Space theme's
   neon baked into the file, whereas the rendered piece is already drawn from
   this theme's own `--cyan` and `--gold`, and filtering it would mute it
   twice. */
body.site-theme-charcoal .chess-node:not(.is-live) {
  filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.55)) saturate(0.75) brightness(0.95);
}

/* Boxes lift off the page: solid surface fill (no frosted glass), a visible
   border, and the lichess elevation shadow. The shimmer sweep and the
   cursor-tracking radial are cut — depth comes from the shadow, not motion.
   Button-like controls also carry .card; the metal rules below override this
   block at equal specificity because they come later in the file. */
body.site-theme-charcoal .card {
  background: var(--surface);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-color: var(--border);
  border-radius: 7px;
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.12),
    0 3px 1px -2px rgba(0, 0, 0, 0.27),
    0 1px 5px rgba(0, 0, 0, 0.15);
}
body.site-theme-charcoal .card::before,
body.site-theme-charcoal .card:not(.rating-card)::after {
  content: none;
}
body.site-theme-charcoal .card:hover {
  background: #24272b;
  border-color: #3d4147;
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.12),
    0 3px 1px -2px rgba(0, 0, 0, 0.27),
    0 1px 5px rgba(0, 0, 0, 0.15);
  transform: none;
}

/* Controls are shallow metal, one step above their box: gradient fill, dark
   border, and an inset top highlight plus a short drop shadow so each button
   registers just a bit on the z axis (the approved Annotated Games / player
   star treatment). Hover lightens the metal and whitens the label. Accent
   color is reserved for selected/active states and primary labels. */
body.site-theme-charcoal .hero-action,
body.site-theme-charcoal .games-filter-btn,
body.site-theme-charcoal .games-page-link,
body.site-theme-charcoal .bio-btn,
body.site-theme-charcoal .bio-index-back,
body.site-theme-charcoal .bio-star-action,
body.site-theme-charcoal .study-player-action,
body.site-theme-charcoal .study-player-bucket-link,
body.site-theme-charcoal .view-btn,
body.site-theme-charcoal .hub-return a,
body.site-theme-charcoal .auth-submit,
body.site-theme-charcoal .collection-form button,
body.site-theme-charcoal .speech-test-btn,
body.site-theme-charcoal .stats-submit {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.55);
  border-radius: var(--radius-control, 6px);
  color: #c2c7cd;
  text-shadow: 0.5px 0.5px 0 rgba(0, 0, 0, 0.8) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .hero-action:hover,
body.site-theme-charcoal .games-filter-btn:hover,
body.site-theme-charcoal .games-page-link:hover,
body.site-theme-charcoal .bio-btn:hover,
body.site-theme-charcoal .bio-index-back:hover,
body.site-theme-charcoal .bio-star-action:hover,
body.site-theme-charcoal .study-player-action:hover,
body.site-theme-charcoal .study-player-bucket-link:hover,
body.site-theme-charcoal .view-btn:hover,
body.site-theme-charcoal .hub-return a:hover,
body.site-theme-charcoal .auth-submit:hover,
body.site-theme-charcoal .collection-form button:hover,
body.site-theme-charcoal .speech-test-btn:hover,
body.site-theme-charcoal .stats-submit:hover,
body.site-theme-charcoal .stats-submit:focus-visible {
  background: linear-gradient(180deg, #525a63, #3e454c);
  border-color: rgba(0, 0, 0, 0.55);
  color: #ffffff;
  text-shadow: 0.5px 0.5px 0 rgba(0, 0, 0, 0.8) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .hero-action:hover {
  transform: none;
}
/* Primary entrances are lichess's primary button cranked into a real key:
   a light-to-dark blue gradient face, a bright top bevel, a deep bottom
   shade, and a 2px drop shadow, so it reads as a pressed-metal blue key,
   never a flat blue slab. */
body.site-theme-charcoal .hero-action-primary,
body.site-theme-charcoal .profile-import-action:not(.profile-secondary-action),
body.site-theme-charcoal .stats-submit {
  background: linear-gradient(180deg, #55a9f4, #2673c8);
  border-color: rgba(0, 0, 0, 0.6);
  color: #ffffff;
  text-shadow: 0.5px 0.5px 0 rgba(0, 0, 0, 0.8) !important;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.5),
    inset 0 3px 7px -2px rgba(220, 238, 255, 0.95),
    inset 0 -8px 12px -4px rgba(10, 58, 106, 1),
    0 3px 5px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .hero-action-primary .hero-action-sub {
  color: rgba(255, 255, 255, 0.8);
}
body.site-theme-charcoal .hero-action-primary:hover,
body.site-theme-charcoal .profile-import-action:not(.profile-secondary-action):hover,
body.site-theme-charcoal .stats-submit:hover,
body.site-theme-charcoal .stats-submit:focus-visible {
  background: linear-gradient(180deg, #61b1f6, #3182d8);
  border-color: rgba(0, 0, 0, 0.6);
  color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 3px 7px -2px rgba(220, 238, 255, 0.95),
    inset 0 -8px 12px -4px rgba(10, 58, 106, 1),
    0 3px 5px rgba(0, 0, 0, 0.5);
}
/* The key physically travels when pressed: it drops the 1px its drop shadow
   gives up, and the bottom shade shallows out as the face flattens. */
body.site-theme-charcoal .hero-action-primary:active,
body.site-theme-charcoal .profile-import-action:not(.profile-secondary-action):active,
body.site-theme-charcoal .stats-submit:active {
  transform: translateY(1px);
  background: linear-gradient(180deg, #3d8fdd, #2b7cd0);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.25),
    inset 0 2px 5px -2px rgba(10, 58, 106, 0.8),
    inset 0 -4px 8px -4px rgba(10, 58, 106, 0.9),
    0 1px 2px rgba(0, 0, 0, 0.45);
}
body.site-theme-charcoal .hero-action-primary:hover .hero-action-sub {
  color: rgba(255, 255, 255, 0.92);
}
/* REMOVED: a page-scoped override that turned the event hero's games button
   into an outlined chip while the identical button on player bios stayed a
   solid blue key. Its comment claimed an owner call that was never made.
   The owner's actual instruction (2026-08-04) is the opposite: the event
   button "should be how player bios are". `.bio-btn-primary` is one
   component shared by study_event_about, study_player_about,
   study_player_notable and pages/android_app — so with this gone, all four
   are the same primary key again. */
/* Selected/active controls must be unmistakable at a glance: white label on
   the metal face plus a filled blue underline bar (lichess's active-tab
   language — blue is the selection accent). The old version reused the exact
   rest-state colors, so a selected filter, bucket, action tab, or starred
   button rendered pixel-identical to unselected. */
body.site-theme-charcoal .games-filter-btn.active,
body.site-theme-charcoal .study-player-bucket-link.active,
body.site-theme-charcoal .study-search-mode.active {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.55);
  color: #ffffff;
  box-shadow:
    inset 0 -2px 0 var(--cyan),
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 1px 2px rgba(0, 0, 0, 0.5);
}
/* A star is a state, not a selection. The blue bar above says "this one of the
   set is the one you picked", which a star does not mean — pressed onto a lone
   star button it read as a stray blue edge with nothing to compare it to
   (owner, 2026-08-06: "the star is randomly a bit blue on the bottom"), and on
   My Library, where every card is starred by definition, it drew that mark on
   every card. Starred is gold, which is what a filled star means everywhere
   else on the site. */
body.site-theme-charcoal .study-player-action.active,
body.site-theme-charcoal .bio-star-action.active {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.55);
  color: var(--gold);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 1px 2px rgba(0, 0, 0, 0.5);
}
/* Keyboard focus must be visible on every metal control and card: the base
   theme's global focus ring loses its box-shadow to the persistent metal
   shadows above, so charcoal draws a real outline instead (outline never
   collides with box-shadow). */
body.site-theme-charcoal .hero-action:focus-visible,
body.site-theme-charcoal .games-filter-btn:focus-visible,
body.site-theme-charcoal .games-page-link:focus-visible,
body.site-theme-charcoal .bio-btn:focus-visible,
body.site-theme-charcoal .bio-index-back:focus-visible,
body.site-theme-charcoal .bio-star-action:focus-visible,
body.site-theme-charcoal .study-player-action:focus-visible,
body.site-theme-charcoal .study-player-bucket-link:focus-visible,
body.site-theme-charcoal .view-btn:focus-visible,
body.site-theme-charcoal .hub-return a:focus-visible,
body.site-theme-charcoal .auth-submit:focus-visible,
body.site-theme-charcoal .collection-form button:focus-visible,
body.site-theme-charcoal .speech-test-btn:focus-visible,
body.site-theme-charcoal .site-nav-link:focus-visible,
body.site-theme-charcoal .account-nav > a:focus-visible,
body.site-theme-charcoal .account-nav .global-search-trigger:focus-visible,
body.site-theme-charcoal .notification-menu-trigger:focus-visible,
body.site-theme-charcoal .account-menu-trigger:focus-visible,
body.site-theme-charcoal .btn-node:focus-visible,
body.site-theme-charcoal .card:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 1px;
}
/* Text-input focus: charcoal's raised-well rule outranks the components'
   :focus rules for border/box-shadow, which left fields with no visible focus
   change at all. Restore an explicit blue focus ring at higher specificity. */
body.site-theme-charcoal select:focus,
body.site-theme-charcoal textarea:focus,
body.site-theme-charcoal input:not([type]):focus,
body.site-theme-charcoal input[type="text"]:focus,
body.site-theme-charcoal input[type="search"]:focus,
body.site-theme-charcoal input[type="email"]:focus,
body.site-theme-charcoal input[type="password"]:focus,
body.site-theme-charcoal input[type="number"]:focus,
body.site-theme-charcoal input[type="url"]:focus {
  border-color: var(--cyan);
  box-shadow:
    inset 0 1px 2px rgba(0, 0, 0, 0.4),
    0 0 0 1px var(--cyan);
  outline: none;
}
body.site-theme-charcoal .global-search-form input[type="search"],
body.site-theme-charcoal .global-search-form input[type="search"]:focus {
  min-height: 30px;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
}
body.site-theme-charcoal .global-search-panel {
  background: var(--surface);
  border-color: var(--border);
  box-shadow: 0 2px 2px rgba(0, 0, 0, 0.35), 0 14px 34px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .global-search-form {
  background: transparent;
}
body.site-theme-charcoal .global-search.is-open .global-search-form {
  background: #2a2d31;
}
body.site-theme-charcoal .account-nav .global-search-trigger svg {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
body.site-theme-charcoal .study-player-notable-link {
  color: var(--chrome);
}

/* Site chrome controls are strongly raised metal — the nav links, search,
   notification bell, and user menu sit several steps above the gradient band
   with near-white labels, so they can never disappear into the page.
   This is deliberately the loudest metal on the site (owner: "crank it"). */
body.site-theme-charcoal .site-nav-link,
body.site-theme-charcoal .account-nav > a,
body.site-theme-charcoal .account-nav .global-search-trigger,
body.site-theme-charcoal .notification-menu-trigger,
body.site-theme-charcoal .account-menu-trigger {
  background: linear-gradient(180deg, #4a525b, #353b42);
  border: 1px solid rgba(0, 0, 0, 0.65);
  border-radius: 4px;
  color: #eef1f4;
  text-shadow: 0.5px 0.5px 0 rgba(0, 0, 0, 0.8) !important;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    0 2px 3px rgba(0, 0, 0, 0.55);
}
body.site-theme-charcoal .site-nav-link:hover,
body.site-theme-charcoal .site-nav-link:focus-visible,
body.site-theme-charcoal .site-nav-dropdown:hover > .site-nav-trigger,
body.site-theme-charcoal .site-nav-dropdown:focus-within > .site-nav-trigger,
body.site-theme-charcoal .account-nav > a:hover,
body.site-theme-charcoal .account-nav .global-search-trigger:hover,
body.site-theme-charcoal .account-nav .global-search-trigger:focus-visible,
body.site-theme-charcoal .notification-menu-trigger:hover,
body.site-theme-charcoal .account-menu-trigger:hover {
  background: linear-gradient(180deg, #59626c, #414850);
  border-color: rgba(0, 0, 0, 0.65);
  color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.18),
    0 2px 4px rgba(0, 0, 0, 0.6);
}
body.site-theme-charcoal .site-nav-link::before {
  background: var(--muted);
  box-shadow: none;
}
/* The dropdown caret hardcodes warm gold in the shared stylesheet; keep it
   on charcoal's own brass accent token. */
body.site-theme-charcoal .site-nav-caret {
  color: rgba(var(--gold-rgb), 0.9);
}
body.site-theme-charcoal .site-nav-link::after {
  content: none;
}
body.site-theme-charcoal .site-nav-menu {
  background: var(--surface);
  border-color: var(--border);
  /* Same radius as every other menu panel, so an open trigger's top corners
     and its menu's bottom corners are cut to one figure. */
  border-radius: var(--radius-card, 8px);
  box-shadow: 0 2px 2px rgba(0, 0, 0, 0.35), 0 10px 24px rgba(0, 0, 0, 0.45);
}
/* Menu labels sit on the same 0.9rem interface floor as every other control
   word. At 0.76rem they were the smallest type in the chrome — on the surface
   a reader uses to get anywhere at all. The tracking comes off with the size:
   1px of letter-spacing is a Space display metric, and a menu label is a word,
   not a caption. The colour is already the read tier (`--chrome` resolves to
   #b9bec4 here), so only the metrics change. */
body.site-theme-charcoal .site-nav-menu-item {
  font-size: var(--fs-label);
  letter-spacing: 0.2px;
}
body.site-theme-charcoal .site-nav-menu-item:hover,
body.site-theme-charcoal .site-nav-menu-item:focus-visible {
  background: #24272b;
  border-color: var(--border);
}

/* ── An open dropdown is one shape ──────────────────────────────────────
   Closed, these triggers are the loudest raised metal on the site and that
   stays. Open, the metal was still there — a lit button with its own radius,
   its own black border and its own drop shadow, with a flat dark panel butted
   underneath it in a different colour and a different radius. Two materials
   meeting at a seam, so the menu read as something that had landed on the nav
   rather than something the nav had opened (owner, 2026-08-05: "color and
   everything between nav and the drop down is consistent vs non consistent").

   Open, the trigger takes the panel's own surface and border, squares the two
   corners at the join, and drops the shadow it would otherwise cast onto the
   thing it is now part of. The panel is pulled up a pixel and the trigger
   raised one step above it, so the trigger's own fill covers the panel's top
   border across its width: the outline runs around the pair instead of ruling
   a line between them.

   Desktop only. At 1100px and below the nav menus are static accordion sections
   inside the slide-in panel, not popovers anchored to a trigger, so there is
   no seam to close and a negative margin would pull a section over its own
   heading. */
@media (min-width: 1101px) {
  body.site-theme-charcoal .site-nav-dropdown:hover > .site-nav-trigger,
  body.site-theme-charcoal .site-nav-dropdown:focus-within > .site-nav-trigger,
  body.site-theme-charcoal .account-menu-trigger[aria-expanded="true"],
  body.site-theme-charcoal .account-nav .notification-menu-trigger[aria-expanded="true"] {
    position: relative;
    background: var(--surface);
    border-color: var(--border);
    border-bottom-color: var(--surface);
    border-radius: var(--radius-card, 8px) var(--radius-card, 8px) 0 0;
    color: var(--tier-scan);
    text-shadow: none !important;
    box-shadow: none;
  }
  /* One step above the panel each one owns, so the seam is covered rather
     than merely aligned. */
  body.site-theme-charcoal .site-nav-dropdown:hover > .site-nav-trigger,
  body.site-theme-charcoal .site-nav-dropdown:focus-within > .site-nav-trigger,
  body.site-theme-charcoal .account-menu-trigger[aria-expanded="true"] {
    z-index: 1003;
  }
  body.site-theme-charcoal .account-nav .notification-menu-trigger[aria-expanded="true"] {
    z-index: 1004;
  }
  /* The menu can never be narrower than the trigger it hangs from, or the
     seam would stop short of the trigger's corner. */
  body.site-theme-charcoal .site-nav-menu {
    min-width: max(150px, 100%);
    margin-top: -1px;
    border-top-left-radius: 0;
  }
  /* These two hang off the right edge, so it is the right corner that joins.
     `:not([hidden])` is not decoration: the blanket rounded-corner rule for
     charcoal panels sits further down this sheet, and a bare class selector
     here would lose the shorthand/longhand race to it. Keyed to the open
     state, the rule both outranks it and says what it means. */
  body.site-theme-charcoal .account-menu-panel:not([hidden]) {
    min-width: max(150px, 100%);
    margin-top: -1px;
    border-top-right-radius: 0;
  }
  body.site-theme-charcoal .notification-menu-panel:not([hidden]) {
    margin-top: -1px;
    border-top-right-radius: 0;
  }
}

/* Inline code and API status codes read as keycap chips: a raised well with
   an inset top highlight — the "bubble with depth" for dense reference text. */
body.site-theme-charcoal .apidoc-inline {
  background: #2a2d31;
  border-color: rgba(0, 0, 0, 0.6);
  border-radius: var(--radius-control, 6px);
  color: #c2c7cd;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06), 0 1px 1px rgba(0, 0, 0, 0.5);
}
/* The bucket "N archives" counters sit against the page, not a card, so the
   standard secondary gray is too faint there. */
body.site-theme-charcoal .study-player-bucket-count {
  color: #a6adb5;
}

/* The video-index pages brighten their secondary text almost to white for
   the dense listing rows; on charcoal that much near-white reads harsh, so
   headings and secondary columns drop to a calm gray. */
body.site-theme-charcoal .pindex {
  --pindex-dim: #9aa1a9;
}

/* Form controls sit in near-black wells in the default theme, which blend
   into flat charcoal. Raise them to a lighter gray than the page, the way
   lichess draws its dropdowns and inputs. background-color (not background)
   preserves the dropdown-arrow background-images some selects carry. */
body.site-theme-charcoal select,
body.site-theme-charcoal textarea,
body.site-theme-charcoal input:not([type]),
body.site-theme-charcoal input[type="text"],
body.site-theme-charcoal input[type="search"],
body.site-theme-charcoal input[type="email"],
body.site-theme-charcoal input[type="password"],
body.site-theme-charcoal input[type="number"],
body.site-theme-charcoal input[type="url"] {
  background-color: #2a2d31;
  border-color: #3d4147;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* Game viewer: the move panel matches lichess — a raised gray panel with
   calm SAN text, and the blue accent on the hovered/current move only.
   game-board.css loads after this file (extra_head), so these selectors
   repeat the page class to outrank its equally specific rules. */
body.site-theme-charcoal.game-board-page .history-column,
body.site-theme-charcoal.game-board-page .position-tools {
  background: var(--surface);
  border-color: var(--border);
  border-radius: 7px;
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.12),
    0 3px 1px -2px rgba(0, 0, 0, 0.27),
    0 1px 5px rgba(0, 0, 0, 0.15);
}
/* The move list is lichess's measured structure: move numbers are dim text
   on their own LIGHTER zebra strip (theirs: #6b6b6b on #33312e over a
   #262421 panel) separated by a hairline, SAN is larger than the chrome
   around it, the hover is a light wash, and the filled blue marks only the
   current move (bold, white). */
/* The index strip is painted ONCE on the list as a continuous band (strip
   fill to 34px, hairline, then panel), not per number cell. Per-cell
   background/borders left dangling box fragments beside every inline
   annotation block that interrupted the rows (owner call, feedback
   round 4: "the weird border glitch"). */
body.site-theme-charcoal.game-board-page .moves-list {
  background: linear-gradient(
    90deg,
    #282b30 0 34px,
    rgba(var(--white-rgb), 0.12) 34px 35px,
    transparent 35px
  );
}
body.site-theme-charcoal.game-board-page .move-num {
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #6a7178;
}
/* Inline annotation notes stay flush with the move rows (owner call: no
   indentation); they simply cover the strip as full-width interrupt
   blocks, and with no per-cell borders nothing dangles at the seams. */
@media(max-width: 900px) {
  body.site-theme-charcoal.game-board-page .moves-list {
    background: linear-gradient(
      90deg,
      #282b30 0 30px,
      rgba(var(--white-rgb), 0.12) 30px 31px,
      transparent 31px
    );
  }
}
body.site-theme-charcoal.game-board-page .move-link {
  color: var(--white);
  font-size: 1.09em;
}
body.site-theme-charcoal.game-board-page .move-link:hover {
  background: rgba(var(--white-rgb), 0.15);
  color: #ffffff;
}
body.site-theme-charcoal.game-board-page .move-link.active {
  background: var(--cyan);
  color: #ffffff;
  font-weight: bold;
}
/* Variation sub-lines are lichess's interrupt blocks, measured: a RAISED
   zebra block — the same lighter strip color as the index column — with
   hairline borders, keeping the moves at full body brightness but slightly
   smaller. The distinction comes from the lighter container, never from
   dimming the text into the panel. These outrank game-board.css (loaded
   after this file) by repeating the page class. */
body.site-theme-charcoal.game-board-page .variation-forest {
  border-top-color: rgba(var(--white-rgb), 0.12);
  border-bottom-color: rgba(var(--white-rgb), 0.12);
  background: #282b30;
  box-shadow: none;
  font-size: 0.95em;
}
body.site-theme-charcoal.game-board-page .variation-line {
  color: var(--white);
}
body.site-theme-charcoal.game-board-page .variation-line:hover {
  background-color: rgba(var(--white-rgb), 0.08);
}
body.site-theme-charcoal.game-board-page .variation-prefix {
  color: var(--muted);
}
/* Inline annotations are the same raised sub-line blocks as variations
   (lichess interrupt): identical #282b30 band, identical hairlines, bright
   text on the lighter block — never a dim floating card. */
body.site-theme-charcoal.game-board-page .annotation-inline-line {
  border-top-color: rgba(var(--white-rgb), 0.12);
  border-bottom-color: rgba(var(--white-rgb), 0.12);
  border-left-color: rgba(var(--white-rgb), 0.25);
  background: #282b30;
  color: var(--white);
}
body.site-theme-charcoal.game-board-page .annotation-inline-line:hover,
body.site-theme-charcoal.game-board-page .annotation-inline-line.current {
  background: #2d3138;
  color: var(--chrome);
}
body.site-theme-charcoal.game-board-page .variation-move {
  color: inherit;
}
body.site-theme-charcoal.game-board-page .variation-menu {
  border-color: var(--border);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal.game-board-page .variation-menu button {
  color: var(--chrome);
}
body.site-theme-charcoal.game-board-page .variation-menu button:hover {
  background: rgba(var(--white-rgb), 0.08);
}
/* The account "neutral" move-tree setting ties the selectors above at equal
   specificity and would win by load order, silently dimming moves back into
   the panel. Charcoal's full-brightness rule keeps priority for users running
   both settings. */
body.site-theme-charcoal.game-board-page.move-tree-theme-neutral .move-link:hover {
  background: rgba(var(--white-rgb), 0.15);
  color: #ffffff;
}
body.site-theme-charcoal.game-board-page.move-tree-theme-neutral .variation-line {
  color: var(--white);
}
/* Selected playlist row highlights blue, not amber. */
body.site-theme-charcoal.game-board-page .game-playlist-row.current {
  background: rgba(var(--cyan-rgb), 0.1);
  box-shadow: inset 3px 0 0 var(--cyan);
}
/* The panel controls — move navigation, flip, opening explorer, engine and
   position actions all render as .btn-node — ship as var(--surface) fills,
   which is the exact color of the charcoal panel they sit on. Raise them to
   the same cranked metal as the rest of the site so every control visibly
   registers on the panel. The .active accents (cyan/mint) in game-board.css
   still win their tie by loading after this file. */
body.site-theme-charcoal.game-board-page .btn-node {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.65);
  border-radius: var(--radius-control, 6px);
  color: #e8ebef;
  text-shadow: 0.5px 0.5px 0 rgba(0, 0, 0, 0.8) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal.game-board-page .btn-node:hover {
  background: linear-gradient(180deg, #525a63, #3e454c);
  border-color: rgba(0, 0, 0, 0.65);
  color: #ffffff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 1px 2px rgba(0, 0, 0, 0.5);
}

/* The rating tiles previously repainted every figure, accent rule and meter
   fill the same brass here, which is how three different rating systems
   ended up looking like one. They are figure tiles now: the tile carries
   `figure-tile`, the number carries `entity-figure` (scan tier, near-white),
   and the per-system hue lives on the accent rule and the meter fill, where
   one hue per tile actually distinguishes something (0.5). Nothing about
   them is set here. */

/* Account + notification flyouts and the account shell hardcode deep
   blue-black panels; keep them on charcoal surfaces here. */
body.site-theme-charcoal .notification-menu-panel,
body.site-theme-charcoal .account-menu-panel,
body.site-theme-charcoal .account-submenu-panel,
body.site-theme-charcoal .account-confirm-dialog-box {
  background: var(--surface);
  border-color: var(--border);
  box-shadow: 0 2px 2px rgba(0, 0, 0, 0.35), 0 10px 24px rgba(0, 0, 0, 0.45);
}
/* Account-menu rows take the same 0.9rem interface floor as the nav menus —
   these are the same kind of object, and at 0.76rem/0.66rem they were the
   smallest type on the site. The state word beside a toggle reads one step
   down but stays on the floor, because "On"/"Off" is the answer to what the
   row is asking. */
body.site-theme-charcoal .account-menu-panel .account-menu-item {
  font-size: var(--fs-label);
  letter-spacing: 0.2px;
}
body.site-theme-charcoal .account-menu-state {
  font-size: var(--fs-label);
  letter-spacing: 0.2px;
  color: var(--tier-ignore);
}
/* The slide-in nav panel is a full-height list of destinations, and its links
   were the smallest touch targets' labels on the phone at 0.82rem tracked out
   to 1.4px. They come to the same interface floor the menu rows inside them
   already took. Panel only — the desktop nav bar is a separate question that
   belongs to the sitewide type pass, not to the mobile one. */
html[data-device="mobile"] body.site-theme-charcoal .site-nav .site-nav-link {
  font-size: var(--fs-label);
  letter-spacing: 0.6px;
}
body.site-theme-charcoal.header-nav-collapsed .site-nav .site-nav-link {
  font-size: var(--fs-label);
  letter-spacing: 0.6px;
}

/* ── The six-column game list keeps production's phone metrics ──────────────
   `/players/<slug>/games/`, `/<user>/games/`, game search and the annotated
   books all render `.games-table`: six columns that only fit a phone because
   the table holds a 680px sideways-scrolling window inside a ~392px viewport
   and shrinks its own type to 0.78rem to do it.

   The role floor broke that. `data-cell`, `pairing`, `column-label` and
   `result-chip` all carry `--fs-meta` (0.92rem), and a role selector
   (`body.site-theme-charcoal .data-cell`, 0-2-0) outranks the phone rule that
   shrinks the table (`.games-table`, 0-1-0). So every cell came back up ~18%
   inside a window that had not grown: player names wrapped to three and four
   lines, rows went 80px -> 106px, and the page went 5735px -> 7479px of
   scrolling. Owner, 2026-08-05: "revert the entire container to how it was
   before ... like to how it is on prod currently ... for mobile only".

   Mobile only is the whole point. The readability pass that raised these sizes
   (owner, 2026-08-05: "the font of games needs to be improved, all game
   interfaces/game-search etc, dates, moves etc should all be easier to read")
   was right on a desktop, where the table has the width to spend, and it stays
   there. On a phone it was spending width the table does not have.

   Every value below is production's measured computed style at 430px, so this
   container renders on a phone exactly as the live site does. The one thing
   not reverted is the casing: production types "PLAYERS" into the markup and
   these templates type "Players" and let `.games-table th` shout it, which
   renders the identical word. */
@media (max-width: 720px) {
  body.site-theme-charcoal .games-table .column-label {
    color: var(--chrome);
    font-size: 0.75rem;
    font-weight: bold;
    letter-spacing: 2px;
    text-shadow: 0 0 10px var(--cyan-glow);
    /* A column heading is one word and never wants a second line. Production
       gets that for free because its date column is 80px wide holding
       "1830.??.??"; these templates print "1830", the column closes to 68px,
       and "DATE ▲" broke in half and took the whole header row from 42px to
       59px with it. The heading holds its line and the column opens to fit it,
       which is production's width either way. */
    white-space: nowrap;
  }
  /* Inherit means the table's own 0.78rem, which is the size that makes six
     columns legible in a 680px window. */
  body.site-theme-charcoal .games-table .data-cell {
    font-size: inherit;
  }
  /* Date and event are production's secondary tier; the table's plain `td`
     colour already matches production for the rest. These three carry the
     `data-cell` class in the selector to outrank `data-cell.is-name` and
     `data-cell.is-numeric` in roles.css, which are the same 0-3-0 weight and
     load after this file. */
  body.site-theme-charcoal .games-table .data-cell.games-date-cell,
  body.site-theme-charcoal .games-table .data-cell.games-event-cell {
    color: var(--data-secondary);
  }
  /* `is-numeric` holds every numeric cell on one line. A date needs that; a
     move count is two or three characters and never wanted it, and production
     lets that column wrap. */
  body.site-theme-charcoal .games-table .data-cell.games-moves-cell {
    white-space: normal;
  }
  body.site-theme-charcoal .games-table .pairing {
    font-size: 0.8rem;
  }
  body.site-theme-charcoal .games-table .pairing .entity-name {
    font-weight: normal;
    letter-spacing: normal;
    line-height: normal;
  }
  body.site-theme-charcoal .games-table .result-chip {
    font-size: inherit;
    font-weight: bold;
    letter-spacing: normal;
  }
  /* REMOVED: the three result colours were here, and only here, so a result
     was painted on a phone and grey on a desktop — on every surface, subject
     or no subject. Colour is a property of the result, not of the viewport.
     `result-chip.is-scored` in roles.css now carries them at every width, on
     the one archive that has a subject. */
}

/* A flash message is a sentence, not a caption: it comes to the interface
   floor and drops the 1px Space tracking that was making three words read as
   wire across the top of the page. */
body.site-theme-charcoal .site-message {
  font-size: var(--fs-label);
  letter-spacing: 0.2px;
}
/* Sound rows are menu rows too, so they take the same floor. The
   `.account-menu-state` beside a sound name keeps its one-step-down relative
   size from the shared sheet. */
body.site-theme-charcoal .sound-set-list .sound-set-item {
  font-size: var(--fs-label);
  letter-spacing: 0.2px;
}
body.site-theme-charcoal .account-nav .notification-menu-item:hover,
body.site-theme-charcoal .account-nav .notification-menu-item:focus-visible {
  background: #292c30;
}

/* Dense-text bio pages get real text tiers instead of one gray sheet: the
   lede and section headings step well above body text, vital values step
   above their labels, and body paragraphs sit a tier below the lede. The
   brass --gold token already carries the epithet, lede border, section
   marks, and stat figures. */
body.site-theme-charcoal .bio-lede {
  color: #d7dce1;
}
body.site-theme-charcoal .bio-section-heading {
  color: #e2e6ea;
}
body.site-theme-charcoal .bio-vital-value {
  color: #ccd2d8;
}
body.site-theme-charcoal .bio-para {
  color: #a2a8af;
}

/* One result language across the four surfaces that share `.games-table`
   (0.3a). /beginners/ was the odd one out: its result cell wore a bordered,
   filled chip while the player game list, the annotated book and game search
   all print the bare figure. A box around three characters is not a
   distinction worth having, and `beginner-games.css` loads after roles.css,
   so this needs the extra class to reach it. */
body.site-theme-charcoal .beginner-games-table .games-result-value {
  padding: 0;
  border: 0;
  background: none;
}

/* The highlight line's green status dot is hidden in charcoal — the gold ◆ is
   the mark here — but `.bio-crown` is an inline-flex row with a 10px gap that
   was spacing that dot. With the dot gone the gap applied to the mark instead,
   on top of the mark's own 0.55em, and the line read "◆     Bronstein won with
   13½/19". Layout, not type, so it is corrected here rather than in roles.css:
   the Space theme still shows the dot and still needs the gap. */
body.site-theme-charcoal .entity-highlight {
  gap: 0;
}

/* With the quote cards gone (the `pull-quote` role), 16px between quotes is
   not enough air to separate them — the box used to do that work. Layout for
   a legacy class, and the Space theme still boxes them, so it belongs here. */
body.site-theme-charcoal .bio-quotes {
  gap: 30px;
}

/* /stats/ repertoire: the two columns were flat outlined boxes sitting inside
   the panel's box, each holding four rows — three levels of container for two
   lists (owner, image 16: "so many flat boxes"). The `section-title` band on
   each column heading separates them now, so the containers come off and the
   columns get their own air instead. Legacy classes and layout, so it lives
   here; the Space theme keeps its outlines. */
body.site-theme-charcoal .stats-insight-column {
  border: 0;
  background: none;
  padding: 0;
}
body.site-theme-charcoal .stats-insight-columns {
  gap: 34px;
}
/* The band's own margin is built for a full-width page section. Inside a
   column it only has to separate the heading from its first row — and it
   needs air above it, or "Repertoire Profile" and "With White" stack as two
   headings with nothing between them. */
body.site-theme-charcoal .stats-insight-column .section-title {
  margin-bottom: 12px;
}
body.site-theme-charcoal .stats-insights-heading h3 {
  margin-bottom: 26px;
}
/* Source links were 0.78rem monospace in cyan at 70% alpha. A link either is
   one or is not; diluting the link colour to three-quarters of itself makes
   it read as a disabled control, and 12.5px is under the interface floor.
   Legacy class, so it is corrected here rather than in roles.css. */
body.site-theme-charcoal .bio-sources a {
  color: var(--cyan);
  font-size: var(--fs-meta);
  letter-spacing: 0;
}

/* Auth prose. The login and register pages are the least-touched surfaces on
   the site and still wear the Space treatment whole: Share Tech Mono at
   0.85rem tracked to 1px, in `--muted`. That is 13.6px of monospace for an
   ordinary English sentence and for the only two links off the login page.
   The route out of a login page is not a caption. Container-level legacy
   classes, so charcoal corrects them here; the elements inside them that
   carry a real role — labels, hints, errors, the submit — take roles in the
   template instead. */
body.site-theme-charcoal .auth-copy,
body.site-theme-charcoal .auth-secondary {
  color: var(--tier-read);
  font-family: inherit;
  font-size: var(--fs-body);
  letter-spacing: 0;
}
body.site-theme-charcoal .auth-consent {
  font-size: var(--fs-body);
}
/* `.auth-field` sets the whole grid uppercase and 0.72rem so its label can be
   wire. The label now carries `field-label` and sizes itself, so the grid
   only has to stop shouting at everything else it contains. */
body.site-theme-charcoal .auth-field {
  font-family: inherit;
  font-size: var(--fs-body);
  letter-spacing: 0;
  text-transform: none;
}

/* REMOVED: a gap under `.support-toward-item .entry-title`. The item's heading
   is a rail label now, beside the paragraph rather than above it, so there is
   no gap for the surface to put back. */

/* The support ask is the one gold control on the site and the one place gold
   is exactly right — it is the page's single action. Only its mobile step
   needs correcting: the 600px rule drops it to 0.88rem, which puts the label
   at 14.1px, just under the floor every other button label sits on. */
@media (max-width: 600px) {
  body.site-theme-charcoal .support-paypal-link {
    font-size: var(--fs-label);
  }
}

/* Event series cards: the default theme gives these tall cards glow and
   tint; charcoal gives them a lit top face, a visible lift, and a stronger
   hover raise so the grid has presence instead of flat gray slabs. Appended
   after the .card rules so these win the same-specificity tie. */
body.site-theme-charcoal .event-series-card {
  /* Proportional, not a 110px stop: the card is no longer a fixed 220px slab,
     so a pixel stop lit the whole face of a dense event card and only the top
     third of a series card. */
  background: linear-gradient(180deg, #24282d, #1e2124 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 2px 2px rgba(0, 0, 0, 0.12),
    0 3px 1px -2px rgba(0, 0, 0, 0.27),
    0 1px 5px rgba(0, 0, 0, 0.15);
}
body.site-theme-charcoal .event-series-card:hover {
  background: linear-gradient(180deg, #2a2f35, #24272b 100%);
  border-color: #454b52;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 6px 14px rgba(0, 0, 0, 0.45),
    0 2px 4px rgba(0, 0, 0, 0.35);
  transform: translateY(-2px);
}
/* (Removed with the card rebuild: three surface rules that set the colour of
   the topline, its first span and the footer. Every one of them is now a role
   — `entity-kind`, `entity-meta`, `entity-figure-line` — and the brass one was
   not merely redundant, it was winning: a two-class-plus-element selector
   outranks `.entity-kind`, so the kind label rendered brass and went on
   competing with the name the role had already stepped it back from. That is
   the exact drift roles.css exists to end; see its closing note. */

/* Notebook workspace: the shared board/move panel retheme already applies
   (the page carries .game-board-page), but the workspace shell keeps its own
   near-black washes and hardcoded warm-gold folder accents from the inline
   template styles. Give the sidebar a real charcoal surface and move the
   warm gold onto the brass --gold token. */
body.site-theme-charcoal .notebook-workspace {
  background: none;
}
body.site-theme-charcoal .notebook-workspace-sidebar {
  background: var(--surface);
  border-right-color: var(--border);
}
body.site-theme-charcoal .workspace-tree-folder-toggle:hover,
body.site-theme-charcoal .workspace-tree-folder-toggle:focus-visible {
  background: rgba(var(--gold-rgb), 0.12);
  outline: 1px solid rgba(var(--gold-rgb), 0.5);
}
body.site-theme-charcoal .workspace-tree-folder-icon {
  background: rgba(var(--gold-rgb), 0.2);
}
body.site-theme-charcoal .workspace-tree-folder.is-collapsed .workspace-tree-folder-icon {
  background: rgba(var(--gold-rgb), 0.1);
}

/* Footer links must read as links: accent color plus the underline the
   shared hover rule already provides. */
body.site-theme-charcoal .footer-links a {
  color: var(--cyan);
}
body.site-theme-charcoal .footer-line span {
  color: var(--muted);
}
body.site-theme-charcoal .footer-links a:hover {
  color: #6db3f2;
}

/* The default theme indents desktop chrome 78px to clear its corner brackets;
   charcoal has no brackets, so the bar aligns to the 24px page gutter. Device
   class—not width—keeps this inset out of the mobile drawer interaction model. */
html[data-device="desktop"] body.site-theme-charcoal .header-nav-row {
  left: 24px;
  right: 24px;
}
@media (max-width: 1100px) {
  html[data-device="desktop"] body.site-theme-charcoal .header-nav-row {
    left: 0;
    right: auto;
  }
}

/* ── Near-black wells raised onto the surface ladder ─────────────────────
   The default theme digs content into ink/black wells (glass-on-void); on
   flat charcoal those read as holes punched in the page. Everything that
   holds content sits ON a surface (box fill + border + elevation shadow);
   only input fields stay gently recessed, via the shared form-control rule
   above. Appended last so these win same-specificity ties. */
body.site-theme-charcoal .game-underboard,
body.site-theme-charcoal .board-editor-card,
body.site-theme-charcoal .stats-panel,
body.site-theme-charcoal .stats-game-results.has-table,
body.site-theme-charcoal .stats-search-help-panel {
  background: var(--surface);
  border-color: var(--border);
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.12),
    0 3px 1px -2px rgba(0, 0, 0, 0.27),
    0 1px 5px rgba(0, 0, 0, 0.15);
}
body.site-theme-charcoal .game-underboard-tabs {
  background: rgba(0, 0, 0, 0.18);
  border-bottom-color: var(--border);
}

/* Rows and option pills inside panels: one step up from their box, never a
   black hole. */
body.site-theme-charcoal .imported-game-source-options label,
body.site-theme-charcoal .study-search-modes {
  background: var(--glass);
  border-color: var(--border);
}

/* Board editor: palette + tool tiles follow the same ladder (the template's
   inline styles use black/void fills). */
body.site-theme-charcoal .board-editor-palette {
  background: rgba(0, 0, 0, 0.18);
  border-color: var(--border);
}
body.site-theme-charcoal .board-editor-tool {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.55);
  border-radius: var(--radius-control, 6px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .board-editor-fen {
  background: #2a2d31;
  border-color: #3d4147;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);
}

/* Confirm-dialog buttons: quiet metal for cancel; danger keeps its tinted
   well but on the raised dialog surface. */
body.site-theme-charcoal .account-confirm-dialog-button {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.55);
  border-radius: var(--radius-control, 6px);
  color: #c2c7cd;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .account-confirm-dialog-button:hover,
body.site-theme-charcoal .account-confirm-dialog-button:focus-visible {
  background: linear-gradient(180deg, #525a63, #3e454c);
  border-color: rgba(0, 0, 0, 0.55);
  color: #ffffff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .account-confirm-dialog-danger {
  background: rgba(var(--danger-rgb), 0.14);
  border-color: rgba(var(--danger-rgb), 0.55);
  color: #e9a1a1;
}
body.site-theme-charcoal .account-confirm-dialog-danger:hover,
body.site-theme-charcoal .account-confirm-dialog-danger:focus-visible {
  background: rgba(var(--danger-rgb), 0.24);
  border-color: var(--danger);
  color: #ffffff;
  box-shadow: none;
}

/* Opening explorer: the mobile sheet and the pager buttons hardcode ink
   fills that beat the theme's metal rule on specificity; repeat the page
   classes to win. */
body.site-theme-charcoal.oe-mobile .oe-sheet {
  background: var(--surface);
  border-top-color: var(--border);
}
body.site-theme-charcoal.opening-explorer-page .oe-pagination .games-page-link {
  background: linear-gradient(180deg, #454c54, #333940);
}
body.site-theme-charcoal.opening-explorer-page .oe-pagination .games-page-link:hover {
  background: linear-gradient(180deg, #525a63, #3e454c);
}

/* Custom form controls the shared input rule can't reach: the token-expiry
   dropdown (a button + menu) and the notebook checkbox. */
body.site-theme-charcoal .api-token-expiry-trigger {
  background: #2a2d31;
  border-color: #3d4147;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.4);
}
body.site-theme-charcoal .api-token-expiry-menu {
  background: var(--surface);
  border-color: var(--border);
  box-shadow: 0 2px 2px rgba(0, 0, 0, 0.35), 0 10px 24px rgba(0, 0, 0, 0.45);
}
body.site-theme-charcoal .notebook-checkbox input {
  background: #2a2d31;
  border-color: #3d4147;
}
body.site-theme-charcoal .notebook-checkbox input:checked {
  background: var(--cyan);
  border-color: var(--cyan);
}

/* ── Metal for the stragglers ────────────────────────────────────────────
   Controls the metal pass missed: engine chrome, playlist autoplay, OE
   filter buttons, collection/notebook management, layout presets, and the
   mobile hamburger. Same shallow-metal grammar as the main button block;
   game-board.css and cast.css load after this file, so their selectors are
   outranked by repeating the page class. Active/selected accents defined in
   those files keep winning their ties, which is intentional — blue stays
   the selection signal. */
body.site-theme-charcoal.game-board-page .engine-power,
body.site-theme-charcoal.game-board-page .engine-icon-toggle,
body.site-theme-charcoal.game-board-page .engine-panel-settings-toggle,
body.site-theme-charcoal.game-board-page .game-playlist-autoplay-toggle,
body.site-theme-charcoal.game-board-page .opening-explorer-filters button,
body.site-theme-charcoal .oe-reset-button,
body.site-theme-charcoal .collection-create-toggle,
body.site-theme-charcoal .profile-secondary-action,
body.site-theme-charcoal .viewer-layout-preset-action,
body.site-theme-charcoal .notebook-manage button,
body.site-theme-charcoal .mobile-nav-toggle {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.55);
  border-radius: var(--radius-control, 6px);
  color: #c2c7cd;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal.game-board-page .engine-power:hover,
body.site-theme-charcoal.game-board-page .opening-explorer-filters button:hover,
body.site-theme-charcoal .oe-reset-button:hover,
body.site-theme-charcoal .oe-reset-button:focus-visible,
body.site-theme-charcoal .collection-create-toggle:hover,
body.site-theme-charcoal .profile-secondary-action:hover,
body.site-theme-charcoal .viewer-layout-preset-action:hover,
body.site-theme-charcoal .viewer-layout-preset-action:focus-visible,
body.site-theme-charcoal .notebook-manage button:hover {
  background: linear-gradient(180deg, #525a63, #3e454c);
  border-color: rgba(0, 0, 0, 0.55);
  color: #ffffff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
/* The hamburger keeps its glow-free bars. */
body.site-theme-charcoal .mobile-nav-toggle span {
  box-shadow: none;
}

/* Destructive controls: danger-tinted wells (same grammar as the confirm
   dialog's danger button) so delete never looks like a neutral button. */
body.site-theme-charcoal .collection-delete-form button,
body.site-theme-charcoal .notebook-collaborators button {
  background: rgba(var(--danger-rgb), 0.14);
  border-color: rgba(var(--danger-rgb), 0.55);
  border-radius: var(--radius-control, 6px);
  color: #e9a1a1;
}
body.site-theme-charcoal .collection-delete-form button:hover,
body.site-theme-charcoal .notebook-collaborators button:hover {
  background: rgba(var(--danger-rgb), 0.24);
  border-color: var(--danger);
  color: #ffffff;
  box-shadow: none;
}

/* Tie-break fixes: these higher-specificity base rules beat the metal
   block, leaving old-theme glow/tint borders on charcoal. */
body.site-theme-charcoal .games-page-link.icon.primary {
  border-color: rgba(0, 0, 0, 0.55);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal.game-board-page .cast-board-container .position-action {
  border-color: rgba(0, 0, 0, 0.65);
}
body.site-theme-charcoal.game-board-page .cast-board-container .position-action:hover {
  border-color: rgba(0, 0, 0, 0.65);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 1px 2px rgba(0, 0, 0, 0.5);
}

/* Search inputs: the accent-colored mono query text is the old theme
   bleeding through; charcoal types in the body face and color (the shared
   form-control rule above already recolors the well itself). */
body.site-theme-charcoal .games-search-input {
  color: var(--white);
}

/* Viewer pages load their stylesheets after this file and re-declare mono/
   display faces on player tags, the result strip, engine chrome, playlists,
   and inputs; repeating the page class outranks them so the one-face rule
   holds across the whole viewer. */
body.site-theme-charcoal.reading-font-site-default.game-board-page *,
body.site-theme-charcoal.reading-font-site-default.opening-explorer-page *,
body.site-theme-charcoal.reading-font-site-default.notebook-workspace-page * {
  font-family: 'Noto Sans', 'Segoe UI', system-ui, Roboto, Helvetica, Arial, sans-serif;
}

/* FEN/PGN import: the ink slab becomes a proper raised panel. The shared
   form-control rule already digs the FEN/PGN fields into gray wells, and the
   metal .btn-node rule carries CLEAR; LOAD is the panel's one primary action,
   so it gets the pressed-blue-key face. */
body.site-theme-charcoal.game-board-page .analysis-import-panel {
  background: var(--surface);
  border-color: var(--border);
  border-radius: 7px;
  overflow: hidden;
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.12),
    0 3px 1px -2px rgba(0, 0, 0, 0.27),
    0 1px 5px rgba(0, 0, 0, 0.15);
}
body.site-theme-charcoal.game-board-page .analysis-import-actions {
  border-top-color: var(--border);
}
body.site-theme-charcoal.game-board-page .btn-node.btn-node-primary {
  background: linear-gradient(180deg, #4aa1f1, #2b7cd0);
  border-color: rgba(0, 0, 0, 0.55);
  color: #ffffff;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.38),
    inset 0 2px 6px -2px rgba(220, 238, 255, 0.9),
    inset 0 -6px 10px -4px rgba(13, 74, 134, 0.95),
    0 2px 4px rgba(0, 0, 0, 0.45);
}
body.site-theme-charcoal.game-board-page .btn-node.btn-node-primary:hover {
  background: linear-gradient(180deg, #5daced, #3b8cdd);
  border-color: rgba(0, 0, 0, 0.55);
  color: #ffffff;
}

/* ── API reference hierarchy ─────────────────────────────────────────────
   The reference page blended into one gray sheet: TOC and endpoint cards
   now ride the surface ladder, code examples recess into a darker well with
   a brass spine (the structural accent marking "example" at a glance), the
   keycap chips get a real key face, and long parameter tables zebra so the
   eye can track rows. */
body.site-theme-charcoal .apidoc-toc,
body.site-theme-charcoal .apidoc-endpoint {
  background: var(--surface);
  border-color: var(--border);
  box-shadow:
    0 2px 2px rgba(0, 0, 0, 0.12),
    0 3px 1px -2px rgba(0, 0, 0, 0.27),
    0 1px 5px rgba(0, 0, 0, 0.15);
}
body.site-theme-charcoal .apidoc-pre {
  background: #17191c;
  border-color: var(--border);
  border-left: 2px solid rgba(var(--gold-rgb), 0.6);
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35);
}
body.site-theme-charcoal .apidoc-inline {
  background: linear-gradient(180deg, #34383d, #292c30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09), 0 1px 1px rgba(0, 0, 0, 0.45);
  color: #d3d7db;
}
body.site-theme-charcoal .apidoc-table tbody tr:nth-child(even) td {
  background: rgba(255, 255, 255, 0.025);
}
/* Adding the event filter makes these parameter tables even-length. Keep the
   borderless final row flush with its endpoint card so its existing keycap
   does not become a third nested painted layer. */
body.site-theme-charcoal .apidoc-event-filter-table tbody tr:last-child td {
  background: transparent;
}
body.site-theme-charcoal .apidoc-method {
  color: #ffffff;
  text-shadow: 0.5px 0.5px 0 rgba(0, 0, 0, 0.6) !important;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.4);
}
body.site-theme-charcoal .apidoc-download {
  background: linear-gradient(180deg, #454c54, #333940);
  border-color: rgba(0, 0, 0, 0.55);
  border-radius: var(--radius-control, 6px);
  color: #c2c7cd;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .apidoc-download:hover {
  background: linear-gradient(180deg, #525a63, #3e454c);
  color: #ffffff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), 0 1px 2px rgba(0, 0, 0, 0.5);
}
body.site-theme-charcoal .apidoc-download .apidoc-inline {
  color: #d3d7db;
}

/* Beginner curriculum: stage headers become lit metal bands so the five
   stages read as physical shelf dividers, not just tinted rows. */
body.site-theme-charcoal .beginner-games-table .beginner-stage-row th {
  background: linear-gradient(180deg, #2c3036, #23262a);
  border-top-color: rgba(255, 255, 255, 0.06);
  border-bottom-color: rgba(0, 0, 0, 0.5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.06);
}
body.site-theme-charcoal .beginner-games-table .games-result-value {
  background: var(--glass);
  border-color: var(--border);
}

/* ── Page hero hierarchy ───────────────────────────────────────────────
   The hero's three lines each need their own register or they blend into one
   grey sheet. The title and the kicker now belong to the `page-title` /
   `page-kicker` roles in roles.css; only the intro paragraph, which recedes,
   is set here.
   The kicker was brass running text, which is gold used as a font rather
   than as punctuation — on charcoal a muted brass sentence inside grey reads
   as dirty grey, which is what "not gold enough" actually meant. The role
   steps it UP to near-white at weight 600 and keeps the warm voice as a gold
   ◆ mark, so de-golding gains contrast instead of producing a grey wall. */
/* Same correction on the front door: the site name in the hero lede was
   brass running text. It steps up to scan tier with the emphasis voice
   (never a hue) rather than collapsing into body grey. */
body.site-theme-charcoal .hero-lede strong {
  color: var(--tier-scan);
  font-weight: 600;
}
body.site-theme-charcoal .seo-intro {
  color: #878d94;
  font-size: 0.98rem;
}
body.site-theme-charcoal .seo-intro strong {
  color: #b9bfc6;
}

/* Player index cards: brass portrait frame over dark matting, so the
   photos read as mounted portraits instead of raw crops. */
body.site-theme-charcoal .study-player-portrait {
  border-color: rgba(var(--gold-rgb), 0.5);
  background: #17191c;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.7), 0 1px 3px rgba(0, 0, 0, 0.4);
}

/* ── Round 3: rounded corners across charcoal ─────────────────────────
   Straight edges read harsh on the flat charcoal surfaces; boxes and
   cards pick up --radius-card, controls already carry --radius-control
   through the metal/key blocks above. */
body.site-theme-charcoal .card,
body.site-theme-charcoal .account-menu-panel,
body.site-theme-charcoal .account-submenu-panel,
body.site-theme-charcoal .notification-menu-panel,
body.site-theme-charcoal .account-confirm-dialog-box,
body.site-theme-charcoal .game-underboard,
body.site-theme-charcoal .game-info-table,
body.site-theme-charcoal .stats-panel,
body.site-theme-charcoal .stats-game-results.has-table,
body.site-theme-charcoal .stats-search-help-panel,
body.site-theme-charcoal .apidoc-toc,
body.site-theme-charcoal .apidoc-endpoint,
body.site-theme-charcoal .apidoc-pre,
body.site-theme-charcoal .oe-sheet,
body.site-theme-charcoal .engine-panel-settings-popover,
body.site-theme-charcoal .variation-menu,
body.site-theme-charcoal .game-save-notebook-menu,
body.site-theme-charcoal .seo-intro,
body.site-theme-charcoal .games-search-input,
body.site-theme-charcoal .imported-game-search input,
body.site-theme-charcoal .stats-game-search-row input,
body.site-theme-charcoal .stats-input {
  border-radius: var(--radius-card);
}
body.site-theme-charcoal.game-board-page .analysis-panel,
body.site-theme-charcoal.game-board-page .move-panel,
body.site-theme-charcoal.game-board-page .history-column,
body.site-theme-charcoal.game-board-page .move-navigation,
body.site-theme-charcoal.game-board-page .game-rail-panel,
body.site-theme-charcoal.game-board-page .opening-explorer-panel {
  border-radius: var(--radius-card);
}
body.site-theme-charcoal .game-share-action,
body.site-theme-charcoal .games-filter-btn,
body.site-theme-charcoal .study-player-portrait {
  border-radius: var(--radius-control);
}
