@font-face {
  font-family: 'Orbitron';
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("../fonts/orbitron-latin.5d281085f727.woff2") format('woff2');
  unicode-range: U+0000-2653, U+2660-10FFFF;
}
@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url("../fonts/rajdhani-300-latin.ea321f644782.woff2") format('woff2');
  unicode-range: U+0000-2653, U+2660-10FFFF;
}
@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/rajdhani-400-latin.cac31f26b77e.woff2") format('woff2');
  unicode-range: U+0000-2653, U+2660-10FFFF;
}
@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/rajdhani-600-latin.ad9c55ecf039.woff2") format('woff2');
  unicode-range: U+0000-2653, U+2660-10FFFF;
}
@font-face {
  font-family: 'Share Tech Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/share-tech-mono-latin.65d3eea7a186.woff2") format('woff2');
  unicode-range: U+0000-2653, U+2660-10FFFF;
}

/* One tiny OFL subset supplies portable chess figures to every shipped site
   face. Reusing the family names makes this a Unicode-range extension: pages
   retain their typography while U+2654-265F always resolve to bundled bytes. */
@font-face {
  font-family: 'Orbitron';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/noto-sans-symbols-chess.dc22e960b319.woff2") format('woff2');
  unicode-range: U+2654-265F;
}
@font-face {
  font-family: 'Rajdhani';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/noto-sans-symbols-chess.dc22e960b319.woff2") format('woff2');
  unicode-range: U+2654-265F;
}
@font-face {
  font-family: 'Share Tech Mono';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/noto-sans-symbols-chess.dc22e960b319.woff2") format('woff2');
  unicode-range: U+2654-265F;
}
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/noto-sans-symbols-chess.dc22e960b319.woff2") format('woff2');
  unicode-range: U+2654-265F;
}

:root {
  /* Raw channel triplets exist so component rules can keep their own alpha
     (rgba(var(--cyan-rgb), 0.15)) while the hue follows the active site theme
     (body.site-theme-*). Keep each triplet in sync with its color token. */
  --void-rgb: 2, 4, 8;
  --deep-rgb: 5, 13, 20;
  --surface-rgb: 10, 24, 40;
  --cyan-rgb: 0, 200, 255;
  --gold-rgb: 255, 201, 74;
  /* Amber: caution/partial states (video-index review queue). */
  --amber-rgb: 255, 176, 0;
  --mint-rgb: 0, 255, 159;
  --white-rgb: 232, 244, 255;
  --danger-rgb: 255, 74, 110;
  /* Surface-role triplets. --tint-rgb colors glass fills, tinted borders, and
     glow shadows (accent-colored surfaces); --cyan-rgb stays for accent text.
     --ink/--panel/--slate are the dark surface ramp (wells, panels, chrome)
     and --silver is dim secondary text. Themes override these to retheme
     every surface without touching accent colors. */
  --tint-rgb: 0, 200, 255;
  /* Chrome/content split: --chrome is interactive chrome text (nav, menus,
     buttons, labels, table headers, control text) and --tint is solid
     decorative fills/rules; --cyan stays on content links, hover/focus/
     selected accents, and data colors. Both resolve to the accent here so the
     default theme is unchanged; themes may neutralize chrome independently. */
  --chrome: var(--cyan);
  --tint: var(--cyan);
  --glass-rgb: 10, 40, 80;
  --ink-rgb: 2, 8, 14;
  --panel-rgb: 6, 16, 28;
  --slate-rgb: 17, 25, 31;
  --silver-rgb: 183, 199, 211;
  --void: #020408;
  --deep: #050d14;
  --surface: #0a1828;
  --glass: rgba(var(--glass-rgb),0.35);
  --border: rgba(var(--tint-rgb),0.15);
  --cyan: #00c8ff;
  --cyan-glow: rgba(var(--cyan-rgb),0.6);
  --gold: #ffc94a;
  --amber: #ffb000;
  --gold-glow: rgba(var(--gold-rgb),0.5);
  --mint: #00ff9f;
  --white: #e8f4ff;
  /* 0.45 fell below the 4.5:1 AA floor (~4.2:1, and ~3.3:1 once a warm
     night-light filter drains this blue-heavy palette). 0.72 was already proven
     on mobile after a reader reported unreadable text there; desktop now gets
     the same value instead of keeping the quieter treatment. */
  --muted: rgba(232,244,255,0.72);
  /* Secondary data text on working surfaces (table date/event columns). Now
     equal to --muted; kept as a distinct token so data rows can be tuned
     independently of chrome. Use on data rows, not chrome. */
  --data-secondary: rgba(232,244,255,0.72);
  --danger: #ff4a6e;
}

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

html {
  scroll-behavior: smooth;
  overflow-x: hidden;
  overflow-x: clip;
  /* Always reserve the scrollbar gutter. Without it a short page has no
     scrollbar and a long one does, so every navigation between the two nudges
     the whole centered layout sideways by the scrollbar width. Nothing should
     move when moving between pages. */
  scrollbar-gutter: stable;
  /* Every site theme is dark. Without this the browser renders its LIGHT
     native UI — scrollbars, select dropdowns, date pickers — against the dark
     page. Token-driven scrollbar colors keep the thumb on the theme ramp. */
  color-scheme: dark;
  scrollbar-color: rgba(var(--silver-rgb), 0.3) transparent;
}

::selection {
  background: rgba(var(--cyan-rgb), 0.35);
}

body {
  background: var(--void);
  color: var(--white);
  font-family: 'Rajdhani', sans-serif;
  min-height: 100vh;
  overflow-x: hidden;
  overflow-x: clip;
  cursor: crosshair;
}

/* The default preserves the established Rajdhani/Orbitron/Share Tech Mono
   system. Alternate reading fonts intentionally replace every text face so an
   accessibility choice is consistent across the site, including controls. */
body.reading-font-system-sans {
  --reading-font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
body.reading-font-arial {
  --reading-font-family: Arial, Helvetica, sans-serif;
}
body.reading-font-verdana {
  --reading-font-family: Verdana, Geneva, sans-serif;
}
body.reading-font-tahoma {
  --reading-font-family: Tahoma, Verdana, sans-serif;
}
body.reading-font-trebuchet-ms {
  --reading-font-family: 'Trebuchet MS', Arial, sans-serif;
}
body.reading-font-georgia {
  --reading-font-family: Georgia, 'Times New Roman', serif;
}
body.reading-font-palatino {
  --reading-font-family: 'Palatino Linotype', 'Book Antiqua', Palatino, serif;
}
body.reading-font-times-new-roman {
  --reading-font-family: 'Times New Roman', Times, serif;
}
body.reading-font-courier-new {
  --reading-font-family: 'Courier New', Courier, monospace;
}
body.reading-font-system-sans,
body.reading-font-system-sans *,
body.reading-font-arial,
body.reading-font-arial *,
body.reading-font-verdana,
body.reading-font-verdana *,
body.reading-font-tahoma,
body.reading-font-tahoma *,
body.reading-font-trebuchet-ms,
body.reading-font-trebuchet-ms *,
body.reading-font-georgia,
body.reading-font-georgia *,
body.reading-font-palatino,
body.reading-font-palatino *,
body.reading-font-times-new-roman,
body.reading-font-times-new-roman *,
body.reading-font-courier-new,
body.reading-font-courier-new * {
  font-family: var(--reading-font-family) !important;
}
body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(circle at 24% 28%, rgba(var(--tint-rgb),0.032), transparent 42%),
    radial-gradient(circle at 78% 66%, rgba(var(--gold-rgb),0.024), transparent 38%),
    radial-gradient(circle at 60% 18%, rgba(var(--mint-rgb),0.022), transparent 30%),
    linear-gradient(180deg, rgba(var(--tint-rgb),0.06), transparent 18%, transparent 76%, rgba(var(--tint-rgb),0.05)),
    repeating-linear-gradient(90deg, transparent 0 119px, rgba(var(--tint-rgb),0.035) 120px, transparent 121px),
    repeating-linear-gradient(0deg, transparent 0 119px, rgba(var(--tint-rgb),0.028) 120px, transparent 121px);
  opacity: 0.72;
}
body.game-board-page::before {
  background:
    linear-gradient(180deg, rgba(var(--tint-rgb),0.06), transparent 18%, transparent 76%, rgba(var(--tint-rgb),0.05)),
    repeating-linear-gradient(90deg, transparent 0 119px, rgba(var(--tint-rgb),0.035) 120px, transparent 121px),
    repeating-linear-gradient(0deg, transparent 0 119px, rgba(var(--tint-rgb),0.028) 120px, transparent 121px);
}

/* ── STARFIELD ── */
#stars {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
}

/* ── GRID OVERLAY ── */
.grid-overlay {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(var(--tint-rgb),0.03) 1px, transparent 1px),
    linear-gradient(90deg, rgba(var(--tint-rgb),0.03) 1px, transparent 1px);
  background-size: 60px 60px;
  /* Stepped, not continuous: this faint grid sits BEHIND the glass cards, so a
     60fps opacity tween forces every card's backdrop-filter to re-blur 60x/sec.
     Stepping updates it ~3x/sec (visually identical on a near-invisible grid)
     and removes the dominant re-blur driver, which is what made the page choppy
     on Intel GPUs. */
  animation: gridPulse 8s steps(24) infinite;
}
@keyframes gridPulse {
  0%,100% { opacity:0.6; }
  50% { opacity:1; }
}

html.motion-deferred .grid-overlay,
html.motion-deferred .header-name,
html.motion-deferred .header-name::after,
html.motion-deferred .data-feed span,
html.motion-deferred .galaxy-disc,
html.motion-deferred .galaxy-drift,
html.motion-deferred .section-title::before,
html.motion-deferred .section-title::after,
html.motion-deferred .bio-section-mark {
  animation-play-state: paused !important;
}

/* ── CORNER DECORATIONS ── */
.corner {
  position: fixed; width: 60px; height: 60px; z-index: 10; pointer-events: none;
}
.corner::before, .corner::after {
  content: ''; position: absolute; background: var(--tint);
}
.corner::before { width: 2px; height: 30px; }
.corner::after { width: 30px; height: 2px; }
.corner-tl { top: 20px; left: 20px; }
.corner-tl::before { top:0; left:0; }
.corner-tl::after { top:0; left:0; }
.corner-tr { top: 20px; right: 20px; }
.corner-tr::before { top:0; right:0; }
.corner-tr::after { top:0; right:0; }
.corner-bl { bottom: 20px; left: 20px; }
.corner-bl::before { bottom:0; left:0; }
.corner-bl::after { bottom:0; left:0; }
.corner-br { bottom: 20px; right: 20px; }
.corner-br::before { bottom:0; right:0; }
.corner-br::after { bottom:0; right:0; }

/* ── LAYOUT ── */
/* The shell is a centred column on desktop and edge-to-edge on phones. The
   owner asked for the full width on mobile ("355 of 375 ... should be 375 of
   375") and rejected it on desktop ("the change was for mobile only"), so the
   cap and gutter below stay and the phone rule in the max-width:720px block
   takes them off. */
.page { position: relative; z-index: 1; max-width: 1100px; margin: 0 auto; padding: 80px 24px 80px; }
/* Homepage hero sits near the top: trim the large top padding so the cube/title
   are not pushed into the vertical middle of the viewport. */
body.home-page .page { padding-top: 62px; }
/* The desktop identity stack keeps the production top rhythm. A prior fold
   pass pulled the entire composition roughly 30px toward the navigation even
   though the revised strip and smaller Daily tile leave that space available.
   Mobile owns its separate doorway geometry in the phone rule below. */
html[data-device="desktop"] body.home-page .page { padding-top: 92px; }
html[data-device="desktop"] body.home-page {
  --home-player-name-size: 0.76rem;
  --home-desktop-wordmark-size: clamp(2.5rem, 6vw, 4.3rem);
}

/* The footer sits below the fold on every page, always.
   A short page used to leave it floating in the middle of a tall viewport with
   black space under it, which reads as the end of the site rather than the end
   of the page. The homepage and /stats/ each fixed that for themselves; this is
   the same fix made once, for everything (owner: "footers should always be at
   the bottom requiring scrolling to see - made that systemwide always").

   The floor is on the content, not on .page: a viewport-tall .page would put
   the footer AT the bottom edge and therefore in view, which is not what was
   asked for. Giving the content the floor pushes the footer past it, so
   reaching the footer always takes a scroll. Long pages are already taller
   than the floor and are unaffected. */
.page {
  display: flex;
  flex-direction: column;
}
.page-body {
  min-height: 100vh;
  /* Small viewports: 100vh is the URL-bar-hidden height, so it overshoots by
     the bar and adds a scroll nobody asked for. dvh is the visible height. */
  min-height: 100dvh;
}
.footer { margin-top: auto; }

/* ── HEADER ── */
.header {
  text-align: center;
  margin-bottom: 36px;
  position: relative;
  isolation: isolate;
  animation: fadeDown 1s ease forwards;
}
.header::before {
  content: '';
  position: absolute;
  left: 50%;
  top: 42%;
  width: min(920px, 88vw);
  height: 1px;
  transform: translateX(-50%);
  background: linear-gradient(90deg, transparent, rgba(var(--tint-rgb),0.24), transparent);
  box-shadow: 0 0 28px rgba(var(--tint-rgb),0.18);
  z-index: -1;
}
.header::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 42%;
  width: min(520px, 70vw);
  height: 120px;
  transform: translate(-50%, -50%) skewX(-12deg);
  border: 1px solid rgba(var(--tint-rgb),0.07);
  background:
    linear-gradient(90deg, transparent, rgba(var(--tint-rgb),0.045), transparent),
    repeating-linear-gradient(90deg, rgba(var(--tint-rgb),0.04) 0 1px, transparent 1px 42px);
  opacity: 0.72;
  z-index: -1;
  animation: headerField 9s ease-in-out infinite;
}
@keyframes fadeDown {
  from { opacity:0; transform: translateY(-30px); }
  to   { opacity:1; transform: translateY(0); }
}
@keyframes headerField {
  0%,100% { opacity:0.42; transform: translate(-50%, -50%) skewX(-12deg) translateY(0); }
  50% { opacity:0.78; transform: translate(-50%, -50%) skewX(-12deg) translateY(8px); }
}

.header-label {
  font-family: 'Share Tech Mono', monospace;
  font-size: 11px;
  letter-spacing: 6px;
  color: var(--chrome);
  text-transform: uppercase;
  margin-bottom: 16px;
  opacity: 0.8;
}
.header-label-spacer {
  height: 13px;
}

.header-name {
  font-family: 'Orbitron', monospace;
  font-size: clamp(2.8rem, 8vw, 5.5rem);
  font-weight: 900;
  line-height: 1.22;
  letter-spacing: 0;
  /* Cyan→gold base with a concentrated white highlight band (~48–52%) that
     sweeps across the letters for a stronger shimmer. */
  background: linear-gradient(100deg,
    var(--white) 0%, var(--cyan) 28%, #eafaff 46%, #ffffff 50%, #eafaff 54%,
    var(--gold) 74%, var(--white) 100%);
  background-size: 230% 100%;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  text-shadow: none;
  position: relative;
  overflow-wrap: anywhere;
  animation: titlePrism 5.5s ease-in-out infinite;
}
@keyframes titlePrism {
  0%,100% { background-position: 0% 50%; filter: drop-shadow(0 0 16px rgba(var(--tint-rgb),0.10)); }
  50%     { background-position: 100% 50%; filter: drop-shadow(0 0 32px rgba(var(--tint-rgb),0.24)); }
}

.header-sub {
  font-family: 'Orbitron', monospace;
  font-size: clamp(0.9rem, 2vw, 1.1rem);
  font-weight: 400;
  color: var(--muted);
  letter-spacing: 8px;
  margin-top: 12px;
  text-transform: uppercase;
}

.header-divider {
  width: 200px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--tint), transparent);
  margin: 28px auto;
}

/* Crawlable, keyword-rich lead paragraph under section headers. Reads as a
   native subtitle; carries body content for SEO on the player/game pages. */
.seo-intro {
  max-width: 760px;
  margin: -8px auto 32px;
  padding: 0 20px;
  text-align: center;
  font-family: 'Rajdhani', sans-serif;
  font-size: 1.02rem;
  line-height: 1.6;
  color: var(--muted);
}

.seo-intro strong {
  color: var(--white);
  font-weight: 600;
}

.seo-intro a {
  color: var(--cyan);
  text-decoration: none;
  /* Link underline follows the accent, not the surface tint. */
  border-bottom: 1px solid rgba(var(--cyan-rgb), 0.3);
  white-space: nowrap;
}

.seo-intro a:hover {
  border-bottom-color: var(--cyan);
}

/* Move-by-move game annotations (e.g. Capablanca's public-domain notes),
   rendered as readable, crawlable text below the board. */
.game-annotations {
  max-width: 860px;
  margin: 32px auto 8px;
  padding: 0 20px;
  font-family: 'Rajdhani', sans-serif;
}

.game-annotations-heading {
  font-family: 'Orbitron', monospace;
  font-size: 1.1rem;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--chrome);
  margin-bottom: 16px;
}

.game-annotations-intro {
  color: var(--white);
  line-height: 1.7;
  font-size: 1.05rem;
  margin-bottom: 24px;
  opacity: 0.92;
}

.game-annotations-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.game-annotation {
  display: flex;
  gap: 14px;
  line-height: 1.6;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--border);
}

.game-annotation-move {
  flex: 0 0 auto;
  min-width: 72px;
  font-family: 'Share Tech Mono', monospace;
  color: var(--gold);
  font-weight: 600;
}

.game-annotation-text {
  color: var(--muted);
}

.game-annotations-source {
  margin-top: 18px;
  font-size: 0.9rem;
  color: var(--muted);
  font-style: italic;
}

.game-annotations-source a {
  color: var(--cyan);
  text-decoration: none;
}

.header-tagline {
  font-size: 1rem;
  color: var(--muted);
  letter-spacing: 2px;
  font-weight: 300;
}
.hero-actions {
  width: min(100%, 520px);
  margin: 36px auto 0;
  display: grid;
  gap: 14px;
}
.hero-action {
  display: block;
  padding: 12px 24px;
  min-height: 44px;
  box-sizing: border-box;
  text-decoration: none;
  color: var(--cyan);
  font-family: 'Orbitron', sans-serif;
  letter-spacing: 2px;
  font-size: 0.9rem;
  border-color: var(--tint);
  box-shadow: inset 0 0 24px rgba(var(--tint-rgb),0.04), 0 0 24px rgba(var(--tint-rgb),0.06);
}
.hero-action:hover {
  color: var(--white);
  transform: translateY(-2px);
}
.hero-action-placeholder {
  visibility: hidden;
  pointer-events: none;
}

/* ── HOMEPAGE FRONT DOOR ──
   Affordances under the hero wordmark so the homepage reads as a door, not just
   a poster: a plain-language value line, then a curated-first doorway. On
   desktop the portrait row is that doorway; destinations already present in
   global navigation do not get a second rail. Mobile retains its deployed
   doorway and utility links. */
.hero-lede {
  max-width: 640px;
  margin: 18px auto 0;
  padding: 0 18px;
  font-family: 'Rajdhani', sans-serif;
  font-size: clamp(1rem, 2.4vw, 1.18rem);
  line-height: 1.55;
  color: var(--muted);
  text-align: center;
}
.hero-lede strong {
  color: var(--white);
  font-weight: 600;
  letter-spacing: 0.4px;
}

.hero-doorway {
  width: min(100%, 560px);
  margin: 28px auto 0;
  display: grid;
  gap: 14px;
}
.hero-action-primary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 16px 24px;
  background: rgba(var(--tint-rgb), 0.08);
  border-color: var(--tint);
  box-shadow: inset 0 0 26px rgba(var(--tint-rgb),0.06), 0 0 26px rgba(var(--tint-rgb),0.10);
}
.hero-action-title {
  font-family: 'Orbitron', sans-serif;
  letter-spacing: 2px;
  font-size: 0.98rem;
}
.hero-action-sub {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted);
}
.hero-action-primary:hover .hero-action-sub { color: var(--cyan); }
.hero-secondary-links {
  width: 100%;
  margin: 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.hero-secondary-links .hero-action {
  text-align: center;
  font-size: 0.82rem;
  letter-spacing: 1px;
}
.hero-spacer { margin: 20px 0 30px; height: 60px; }

/* Each named portrait is a destination while two identical sequences still
   make one continuous transform-only loop. The second sequence is hidden from
   assistive technology and the browser cache keeps duplicate URLs to one
   transfer. The restored aperture has one dark material edge; portraits and
   their quiet names remain unboxed. A cyan moving perimeter remains rejected. */
.home-player-strip {
  width: min(100%, 960px);
  margin: 10px auto 0;
}
.home-player-strip-viewport {
  position: relative;
  width: 100%;
  height: 136px;
  display: block;
  overflow: hidden;
  background: var(--surface);
  border: 0;
  border-radius: var(--radius-card, 8px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.16),
    0 2px 0 rgba(0, 0, 0, 0.7),
    0 8px 18px -7px rgba(0, 0, 0, 0.7),
    0 18px 30px -18px rgba(0, 0, 0, 0.82);
}
.home-player-strip-viewport::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset: 0;
  box-sizing: border-box;
  border: 2px solid rgba(0, 0, 0, 0.72);
  border-radius: inherit;
  pointer-events: none;
}
.home-player-strip-track {
  width: max-content;
  height: 136px;
  display: flex;
  animation: homePlayerStripScroll 240s linear infinite;
  will-change: transform;
}
.home-player-strip-sequence {
  height: 136px;
  display: flex;
  flex: none;
  gap: 6px;
  padding-right: 6px;
}
.home-player-strip-player {
  width: 112px;
  height: 136px;
  display: grid;
  grid-template-rows: 112px 24px;
  flex: 0 0 112px;
  color: var(--tier-ignore, var(--muted));
  text-decoration: none;
  background: transparent;
  border: 0;
  box-shadow: none;
  cursor: pointer;
}
.home-player-strip-portrait {
  width: 112px;
  height: 112px;
  display: block;
  object-fit: cover;
  object-position: center;
  filter: brightness(0.8) contrast(1.04);
  transition: filter 180ms ease;
}
.home-player-strip-name {
  width: 112px;
  height: 24px;
  display: block;
  overflow: hidden;
  color: inherit;
  font-size: var(--home-player-name-size);
  font-weight: 500;
  line-height: 24px;
  text-align: center;
  white-space: nowrap;
  background: transparent;
  border: 0;
  box-shadow: none;
  text-decoration: none;
  transition: color 180ms ease;
}
.home-player-strip-viewport:hover .home-player-strip-track,
.home-player-strip-viewport:focus-within .home-player-strip-track {
  animation-play-state: paused;
}
.home-player-strip-player:hover .home-player-strip-portrait,
.home-player-strip-player:focus-visible .home-player-strip-portrait {
  filter: brightness(1.06) contrast(1.06);
}
.home-player-strip-player:hover .home-player-strip-name,
.home-player-strip-player:focus-visible .home-player-strip-name {
  color: var(--cyan);
}
.home-player-strip-player:focus-visible,
.home-player-strip-browse:focus-visible,
.home-daily-card:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 3px;
}
.home-player-strip-player:focus-visible {
  position: relative;
  z-index: 3;
  outline-offset: -3px;
}
.home-player-strip-browse-row {
  display: flex;
  justify-content: center;
  margin-top: 12px;
}
.home-player-strip-browse {
  width: min(100%, 420px);
  min-height: 44px;
  padding: 10px 24px;
  justify-content: center;
  text-align: center;
  text-decoration: none;
}
.home-player-strip a,
.home-player-strip a:hover,
.home-player-strip a:focus-visible {
  text-decoration: none;
}
@keyframes homePlayerStripScroll {
  to { transform: translate3d(-50%, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .home-player-strip-track {
    animation: none;
    transform: translate3d(0, 0, 0);
    will-change: auto;
  }
}
.home-front-door-note {
  display: block;
  color: var(--tier-ignore, var(--muted));
  font-size: var(--fs-label);
  font-weight: 400;
  line-height: 1.4;
  text-transform: none;
  letter-spacing: 0;
}

/* Game of the Day adapts the complete native reference composition: framed
   satin face, chess-piece kicker, matchup, details and replay affordance. */
.home-daily {
  width: min(100%, 960px);
  margin: 90px auto 16px;
  /* Make the section's measured box include the painted shadow so fold checks
     cannot pass while the material depth is clipped by the viewport. */
  padding-bottom: 16px;
}
/* The owner's browser leaves roughly 780px for page content below its chrome.
   Keep the Daily tile's lower beat distinct without pushing its material shadow
   below that real desktop fold. Mobile renders its separate doorway instead. */
html[data-device="desktop"] body.home-page .home-daily {
  margin-top: 14px;
}
body.site-theme-charcoal .home-daily {
  padding-bottom: 20px;
}
.home-daily-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: max-content;
  max-width: 100%;
  margin: 0 auto;
  padding: 14px 22px;
  box-sizing: border-box;
  color: inherit;
  text-decoration: none;
  text-align: center;
  text-transform: none;
  letter-spacing: 0;
  background: var(--tint);
  border: 0;
  border-radius: var(--radius-card, 8px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 2px 0 rgba(0, 0, 0, 0.74),
    0 8px 18px -10px rgba(0, 0, 0, 0.7);
  cursor: pointer;
  transition:
    background-color 0.16s ease,
    box-shadow 0.16s ease,
    transform 0.16s ease;
}
.home-daily-card:hover {
  background: color-mix(in srgb, var(--tint) 86%, var(--cyan) 14%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 3px 0 rgba(0, 0, 0, 0.78),
    0 9px 20px -13px rgba(0, 0, 0, 0.78);
  transform: translateY(-1px);
}
body.site-theme-charcoal .home-daily-card {
  /* Daily metadata changes every midnight, but the accepted compact key does
     not. This is the measured width of the 2026-08-30 Fischer–Andersson card;
     longer event names wrap inside it instead of resizing the whole object. */
  width: min(100%, 258px);
  min-height: 138px;
  padding: 10px 18px 9px;
  background-color: var(--daily-face-bottom);
  background-image: linear-gradient(
    180deg,
    var(--daily-face-top),
    var(--daily-face-bottom)
  );
  border-radius: var(--daily-frame-radius);
  box-shadow:
    inset 0 1px 0 rgba(var(--gold-rgb), 0.28),
    inset 0 -2px 0 rgba(0, 0, 0, 0.52),
    inset 0 0 0 1px var(--daily-frame),
    0 3px 0 rgba(0, 0, 0, 0.78),
    0 12px 22px -14px rgba(0, 0, 0, 0.88);
}
body.site-theme-charcoal .home-daily-card:hover {
  background-image: linear-gradient(
    180deg,
    var(--daily-face-hover-top),
    var(--daily-face-hover-bottom)
  );
  box-shadow:
    inset 0 1px 0 rgba(var(--gold-rgb), 0.38),
    inset 0 -2px 0 rgba(0, 0, 0, 0.58),
    inset 0 0 0 1px var(--daily-frame-hover),
    0 4px 0 rgba(0, 0, 0, 0.82),
    0 14px 26px -16px rgba(0, 0, 0, 0.92);
}
body.site-theme-charcoal .home-daily-card:active {
  background-image: linear-gradient(
    180deg,
    var(--daily-face-pressed-top),
    var(--daily-face-pressed-bottom)
  );
  box-shadow:
    inset 0 1px 0 rgba(var(--gold-rgb), 0.18),
    inset 0 -2px 0 rgba(0, 0, 0, 0.6),
    inset 0 0 0 1px var(--daily-frame-pressed),
    0 1px 0 rgba(0, 0, 0, 0.74),
    0 5px 12px -8px rgba(0, 0, 0, 0.76);
  transform: translateY(1px);
}
@media (prefers-reduced-motion: reduce) {
  .home-daily-card {
    transition: none;
  }
}
.home-daily-topline {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.35em;
}
.home-daily-piece,
.home-daily-open {
  display: none;
}
.home-daily-headline {
  display: grid;
  justify-items: center;
  gap: 3px;
  min-width: 0;
  margin-top: 4px;
  line-height: 1.3;
  text-align: center;
  white-space: normal;
}
body.site-theme-charcoal .home-daily-topline {
  gap: 8px;
}
body.site-theme-charcoal .home-daily-piece {
  display: block;
  width: 22px;
  height: 22px;
  flex: 0 0 22px;
  color: var(--gold);
  fill: currentColor;
}
body.site-theme-charcoal .home-daily .home-front-door-note {
  color: var(--gold);
  font-size: var(--fs-label);
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
body.site-theme-charcoal .home-daily-headline {
  gap: 3px;
  margin-top: 7px;
  line-height: 1.14;
}
body.site-theme-charcoal .home-daily-pairing.pairing.is-lead,
body.site-theme-charcoal .home-daily-pairing.pairing.is-lead .entity-name,
body.site-theme-charcoal .home-daily .pairing-vs {
  color: var(--name);
  font-size: 20px;
  font-weight: 700;
  line-height: 1.14;
}
body.site-theme-charcoal .home-daily-year {
  margin-inline: 0.225em;
}
body.site-theme-charcoal .home-daily-meta,
body.site-theme-charcoal .home-daily .home-daily-result.result-chip,
body.site-theme-charcoal .home-daily .data-cell,
body.site-theme-charcoal .home-daily .meta-sep {
  color: var(--tier-read);
  font-size: 14.5px;
  font-weight: 400;
  line-height: 1.16;
}
body.site-theme-charcoal .home-daily-meta {
  /* Inline flow wraps the complete metadata sentence efficiently. Flex-wrap
     treated every separator and value as a separate item and turned this same
     line into four rows at the compact card width. */
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}
body.site-theme-charcoal .home-daily-open {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  /* Balance the trailing 18px chevron and 4px gap so the action label itself
     shares the card's text axis instead of sitting 11px left of center. */
  padding-left: 22px;
  margin-top: 6px;
  color: var(--cyan);
  font-size: var(--fs-label);
  font-weight: 700;
  line-height: 1;
}
body.site-theme-charcoal .home-daily-chevron {
  width: 18px;
  height: 18px;
  flex: 0 0 18px;
  fill: currentColor;
}
.home-daily-pairing,
.home-daily-meta {
  display: inline-flex;
  align-items: baseline;
  flex-wrap: wrap;
}
.home-daily-pairing {
  /* Center each wrapped line. The year's symmetric spacing keeps an orphaned
     date on the card axis while retaining the same total inline separation. */
  justify-content: center;
}
.home-daily-meta {
  justify-content: center;
  gap: 5px;
  line-height: 1.4;
}
/* Space has no role stylesheet. Preserve its pre-existing tile typography
   while Charcoal renders directly from the shared semantic roles above it. */
body.home-page:not(.site-theme-charcoal) .home-daily-pairing.pairing.is-lead,
body.home-page:not(.site-theme-charcoal) .home-daily-pairing.pairing.is-lead .entity-name {
  font-size: var(--fs-section);
  font-weight: 700;
  line-height: 1.2;
}
body.home-page:not(.site-theme-charcoal) .home-daily-meta {
  color: var(--tier-scan, var(--text));
  font-size: var(--fs-body);
  font-weight: 600;
}
body.home-page:not(.site-theme-charcoal) .home-daily .home-daily-event.data-cell,
body.home-page:not(.site-theme-charcoal) .home-daily .home-daily-site.data-cell {
  color: var(--tier-scan, var(--text));
  font-weight: 600;
}
body.home-page:not(.site-theme-charcoal) .home-daily-year {
  margin-inline: 0.225em;
}
body.home-page:not(.site-theme-charcoal) .home-daily .pairing-vs,
body.home-page:not(.site-theme-charcoal) .home-daily-result,
body.home-page:not(.site-theme-charcoal) .home-daily .meta-sep {
  color: var(--tier-ignore, var(--muted));
}
body.home-page:not(.site-theme-charcoal) .home-daily .home-daily-result.result-chip {
  color: var(--tier-ignore, var(--muted));
  font-weight: 400;
}
/* The deployed mobile doorway retains its quiet utility links. Desktop routes
   these destinations through the global navigation and renders no duplicate
   rail. */
.hero-explore {
  width: min(100%, 560px);
  margin: 22px auto 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 7px;
  color: var(--muted);
}
.hero-explore-route {
  padding: 2px 1px;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.16s ease;
}
.hero-explore-separator {
  color: rgba(var(--tint-rgb), 0.38);
}
.hero-explore-route:hover,
.hero-explore-route:focus-visible {
  color: var(--cyan);
  outline: none;
}
.hero-explore-route:focus-visible {
  text-decoration: underline;
  text-underline-offset: 3px;
}
/* The mobile homepage is frozen to its deployed doorway. Keep its legacy
   metrics behind the device-class boundary instead of letting them leak into
   the Charcoal desktop component. */
html[data-device="mobile"] body.home-page .hero-explore {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.76rem;
  letter-spacing: 0.2px;
}
/* Clearing the nav is a collision fix, so it is not inside the desktop query
   below. Logged out at phone widths the LOGIN/REGISTER pair sits directly over
   the knight's ears, and gating this at 721px left the one layout that
   overlaps as the one layout that could not be nudged. */
html[data-device="mobile"] body.home-page.home-fit-knight-clear .chess-node {
  transform: translateY(28px);
}
.about-actions {
  margin-top: 24px;
}

.about-feed {
  margin-bottom: 34px;
}

.about-site-header {
  margin-bottom: 52px;
}

.about-site-section {
  margin-bottom: 58px;
}

.about-copy-card {
  max-width: 860px;
  margin: 0 auto;
  padding: 28px 30px;
  font-family: 'Rajdhani', sans-serif;
  color: var(--muted);
  line-height: 1.7;
  font-size: 1.06rem;
}

.about-copy-card p + p {
  margin-top: 18px;
}

.about-copy-card p {
  margin: 0;
}

/* Inline links in this prose had no rule at all, so they fell back to the
   browser default and read as body text on this palette. Matches the .legal-doc
   treatment: the underline is what makes them findable mid-sentence. */
.about-copy-card a {
  color: var(--cyan);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.about-copy-card a:hover,
.about-copy-card a:focus-visible {
  color: var(--gold);
}

.about-metric-grid {
  max-width: 940px;
  margin: 0 auto;
}

.about-metric-compact {
  font-size: 2.35rem;
}

/* The capability list on /about/. It was six cards in a two-column grid, which
   put six identical rectangles on a page whose whole point that week was that
   a box is not contrast. This is layout only: a label rail and a body column,
   with the type doing the separating.

   The rail collapses below 620px rather than shrinking, because a 150px
   column of wrapped small caps beside a wrapped paragraph is two ragged
   columns and no rail at all. */
.feature-list {
  max-width: 940px;
  margin: 0 auto;
  display: grid;
  gap: 30px;
}

.feature-entry {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: 0 26px;
  align-items: start;
}

.feature-entry dt {
  margin: 0;
  /* Optical, not metric: the label's cap height has to sit on the title's,
     and the title is the larger face. */
  padding-top: 3px;
}

.feature-detail {
  margin: 0;
  display: grid;
  gap: 6px;
}

.feature-detail p {
  margin: 0;
}

@media (max-width: 620px) {
  .feature-entry {
    grid-template-columns: minmax(0, 1fr);
    gap: 8px;
  }

  .feature-entry dt {
    padding-top: 0;
  }
}

/* ── SUPPORT PAGE ──
   Intentionally card-free. The about pages stack bordered panels, and repeating
   that idiom here produced a third page of nested boxes with the one action
   buried two thirds down it. Hierarchy comes from type and space, hairlines
   separate the sections, and the only bordered object on the page is the button
   a visitor is meant to press. */
.support-header {
  margin-bottom: 46px;
}

/* The shared display size wraps this title onto two lines and spends the whole
   first screen on it, which is what pushed the ask below the fold on the
   previous version. This page needs the heading present, not monumental. */
.support-header .header-name {
  font-size: clamp(1.9rem, 4.4vw, 3rem);
}

/* Without the cards, nothing supplies an inset any more, so the prose needs its
   own gutter or it runs to the screen edge on a phone. */
.support-page {
  max-width: 760px;
  margin: 0 auto;
  padding: 0 20px;
  font-family: 'Rajdhani', sans-serif;
  color: var(--muted);
}

.support-lede p {
  margin: 0;
  color: var(--white);
  font-size: 1.2rem;
  line-height: 1.65;
}

.support-lede p + p {
  margin-top: 20px;
  color: var(--muted);
  font-size: 1.06rem;
}

.support-toward {
  margin-top: 54px;
}

/* Nothing else to declare: this list is `.feature-list`, the about page's label
   rail and body column, and it carries that page's type as well (owner,
   2026-08-06: "suppport should use bullets exactly like" it). The hairline over
   each item, the item's own heading language and its larger body size all went
   with the change — they were drawing a box and a second voice around a list
   that reads as a list. */

.support-ask {
  margin-top: 66px;
  text-align: center;
}

.support-ask-lead {
  margin: 0;
  color: var(--white);
  font-family: 'Orbitron', sans-serif;
  font-size: 1rem;
  line-height: 1.55;
}

.support-ask-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  margin-top: 28px;
}

/* PayPal draws its own button into this mount. It stays collapsed until the SDK
   reports success so a blocked or failed script leaves no empty gap above the
   PayPal.Me link. */
.support-donate-mount {
  display: none;
}

.support-donate-mount.is-ready {
  display: block;
  min-height: 42px;
}

/* Gold is the action accent in this palette, so the single ask is also the only
   warm element on the page. */
.support-paypal-link {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 13px 24px;
  border: 1px solid var(--gold);
  border-radius: 3px;
  color: var(--gold);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.95rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background 0.18s ease, color 0.18s ease;
}

.support-paypal-link:hover,
.support-paypal-link:focus-visible {
  background: var(--gold);
  color: var(--void);
}

/* When PayPal has drawn its own button the page should make one ask, not two.
   The direct link stays reachable for anyone whose popup is blocked, but drops
   to a quiet text link so it stops competing with the button above it. */
.support-donate-mount.is-ready ~ .support-paypal-link {
  width: auto;
  flex-direction: row;
  border-color: transparent;
  padding: 4px 8px;
  color: var(--muted);
  font-size: 0.82rem;
}

.support-donate-mount.is-ready ~ .support-paypal-link:hover,
.support-donate-mount.is-ready ~ .support-paypal-link:focus-visible {
  background: transparent;
  color: var(--gold);
}

.support-paypal-link-host {
  font-size: 0.78rem;
  opacity: 0.72;
}

.support-donate-status {
  margin: 18px 0 0;
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.9rem;
}

.support-ask-note {
  max-width: 560px;
  margin: 26px auto 0;
  font-size: 0.9rem;
  line-height: 1.6;
  opacity: 0.8;
}

.support-closing {
  margin-top: 66px;
  padding-top: 26px;
  border-top: 1px solid var(--border);
}

.support-closing p {
  margin: 0;
  font-size: 0.98rem;
  line-height: 1.62;
}

@media (max-width: 600px) {
  .support-lede p {
    font-size: 1.08rem;
  }

  .support-toward,
  .support-ask,
  .support-closing {
    margin-top: 44px;
  }

  /* The label needs two lines at this width, which left the host hint centered
     against a taller block. Stacking puts it under the label instead. */
  .support-paypal-link {
    width: 100%;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    padding: 14px 18px;
    font-size: 0.88rem;
    letter-spacing: 0.04em;
  }

  /* Demoted to one quiet line at this width, the destination hint is what
     pushes it to two and goes ragged. PayPal's own button above it already
     says where the money goes. */
  .support-donate-mount.is-ready ~ .support-paypal-link .support-paypal-link-host {
    display: none;
  }
}

/* ── SUPPORT REQUEST PAGE ── */
.support-request-header {
  margin-bottom: 42px;
}

.support-request-header .header-name {
  font-size: clamp(1.9rem, 4.4vw, 3rem);
}

.support-request-page {
  max-width: 700px;
  margin: 0 auto;
  padding: 0 20px;
}

.support-request-intro {
  margin-bottom: 30px;
}

.support-request-intro p {
  margin: 0;
}

.support-request-intro p + p {
  margin-top: 14px;
}

.support-request-identity {
  display: grid;
  grid-template-columns: minmax(110px, auto) minmax(0, 1fr);
  gap: 7px 22px;
  margin-bottom: 26px;
  padding: 18px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  color: var(--muted);
}

.support-request-identity .block-label {
  grid-row: 1 / span 2;
}

.support-request-identity strong {
  color: var(--white);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.92rem;
  letter-spacing: 0.06em;
}

.support-request-anonymous-note {
  margin: 0 0 26px;
  padding: 15px 18px;
  border-left: 2px solid var(--cyan);
  background: rgba(var(--tint-rgb), 0.05);
}

.support-request-form {
  gap: 20px;
}

.support-request-privacy {
  margin: 22px 0 0;
  line-height: 1.55;
  text-align: center;
}

@media (max-width: 600px) {
  .support-request-identity {
    grid-template-columns: minmax(0, 1fr);
  }

  .support-request-identity .block-label {
    grid-row: auto;
  }
}

/* ── CREATOR OTB CTA ──
   Focal element of the creator page: the one bold card, pointing at Christian's
   real over-the-board games. Everything else on the page stays quiet. */
.creator-otb {
  display: flex;
  align-items: center;
  gap: 22px;
  max-width: 940px;
  margin: 0 auto 34px;
  padding: 24px 28px;
  text-decoration: none;
  transition: transform 0.2s ease, border-color 0.2s ease;
}
.creator-otb:hover {
  transform: translateY(-2px);
  border-color: var(--cyan);
}
.creator-otb-mark {
  font-size: 2.6rem;
  line-height: 1;
  color: var(--cyan);
  flex-shrink: 0;
}
.creator-otb-text {
  flex: 1;
}
.creator-otb-title {
  font-family: 'Orbitron', sans-serif;
  font-size: 1rem;
  letter-spacing: 1px;
  color: var(--cyan);
  margin-bottom: 6px;
}
.creator-otb-text p {
  margin: 0;
  font-family: 'Rajdhani', sans-serif;
  color: var(--muted);
  font-size: 0.98rem;
  line-height: 1.55;
}
.creator-otb-arrow {
  font-size: 1.5rem;
  color: var(--gold);
  flex-shrink: 0;
  transition: transform 0.2s ease;
}
.creator-otb:hover .creator-otb-arrow {
  transform: translateX(5px);
}
@media (max-width: 560px) {
  .creator-otb {
    flex-wrap: wrap;
    gap: 14px;
  }
  .creator-otb-mark {
    font-size: 2rem;
  }
}

/* ── CHESS NODE: 3D KNIGHT ──
   Hero mark: a carved knight solid rendered in WebGL in polished chrome, lit
   and turning on its vertical axis. `hero-knight.ts` draws it; the mesh is carved from this
   repository's own knight artwork by tools/build_hero_knight_mesh.py.

   Mobile keeps the flat fallback. Desktop reserves the same fixed geometry but
   paints no substitute, so the SVG cannot flash before the first WebGL frame.
   Motion is covered by the animations-disabled / reduce-motion kill switches
   inside the module. */
.chess-node {
  position: relative;
  width: 130px;
  height: 130px;
  margin: 0 auto 30px;
  background: url("../knight-face.312f04fe7bd0.svg") center / 100px 100px no-repeat;
  filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.55))
          drop-shadow(0 0 18px rgba(var(--tint-rgb), 0.30));
}
html[data-device="desktop"] body.home-page .chess-node {
  width: 130px;
  height: 130px;
  margin-bottom: 30px;
  background: none;
}
html[data-device="desktop"] body.home-page .header-name {
  margin: 0;
  font-size: var(--home-desktop-wordmark-size);
}
html[data-device="desktop"] body.home-page .hero-lede {
  margin-top: 10px;
  line-height: 1.4;
}
/* Browser chrome can leave a wide desktop with only 700px of content height.
   Reclaim the empty space above and below the unchanged 130px knight only as
   the Daily tile approaches the fold. Space's shorter tile needs less room.
   At 780px and above the accepted desktop geometry remains unchanged; very
   short windows retain normal document scrolling after these gaps run out. */
@media (min-width: 1101px) and (max-height: 779px) {
  html[data-device="desktop"] body.home-page {
    --home-fold-height: 714px;
  }
  html[data-device="desktop"] body.home-page.site-theme-charcoal {
    --home-fold-height: 780px;
  }
  html[data-device="desktop"] body.home-page .page {
    padding-top: clamp(56px, calc(100dvh - var(--home-fold-height) + 92px), 92px);
  }
  html[data-device="desktop"] body.home-page .chess-node {
    margin-bottom: clamp(0px, calc(100dvh - var(--home-fold-height) + 66px), 30px);
  }
}
html[data-device="desktop"] body.home-page.site-theme-charcoal .chess-node {
  filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.55));
}
html[data-device="desktop"] body.home-page.site-theme-charcoal .chess-node::after {
  content: none;
}
/* Soft ground glow under the knight. */
.chess-node::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 100%;
  width: 92px;
  height: 26px;
  transform: translate(-50%, 4px) rotateX(80deg);
  background: radial-gradient(ellipse, rgba(var(--tint-rgb), 0.30), transparent 68%);
  filter: blur(7px);
  pointer-events: none;
}
.chess-knight {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
}
/* Swapped only once the renderer has drawn. On desktop the node keeps its
   production geometry when WebGL is unavailable, preventing reflow while the
   wordmark remains the only visible identity. */
.chess-node.is-live {
  background-image: none;
}
.chess-node.is-live .chess-knight {
  opacity: 1;
}

/* ── SECTION TITLE ── */
.section-title {
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  letter-spacing: 5px;
  color: var(--chrome);
  text-transform: uppercase;
  margin-bottom: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
}
.section-title::before,
.section-title::after {
  content: '';
  flex: 1;
  height: 1px;
}
.section-title::before {
  background: linear-gradient(90deg, transparent, var(--border));
}
.section-title::after {
  background: linear-gradient(90deg, var(--border), transparent);
}

/* ── GLASS CARD ── */
.card {
  background: var(--glass);
  border: 1px solid var(--border);
  border-radius: 4px;
  /* 6px blur: backdrop-blur cost grows ~quadratically with radius and runs at
     the full device resolution, so on a HiDPI Intel iGPU (where Firefox also
     can't use the native compositor) this is the single biggest GPU saving.
     Still clearly reads as frosted glass. */
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  position: relative;
  overflow: hidden;
  transition: border-color 0.3s, box-shadow 0.3s, transform 0.25s ease, background 0.25s ease;
}
.card::before {
  content: '';
  position: absolute; top:0; left:-100%; width:60%; height:100%;
  background: linear-gradient(90deg, transparent, rgba(var(--tint-rgb),0.06), transparent);
  transition: left 0.6s ease;
}
.card:hover::before { left: 120%; }
.card:hover {
  border-color: rgba(var(--tint-rgb),0.4);
  background: rgba(var(--glass-rgb),0.42);
  box-shadow: 0 10px 34px rgba(0,0,0,0.28), 0 0 30px rgba(var(--tint-rgb),0.1), inset 0 0 30px rgba(var(--tint-rgb),0.03);
  transform: translateY(-1px);
}

/* ── RATINGS GRID ── */
.ratings-section { margin-bottom: 60px; animation: fadeUp 1s 0.3s ease both; }
.ratings-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}
@media(max-width:600px) { .ratings-grid { grid-template-columns: 1fr; } }

.rating-card {
  padding: 28px 24px;
  text-align: center;
  position: relative;
}
.rating-card::after {
  content: '';
  position: absolute; bottom:0; left:0; width:100%; height:3px;
}
.rating-card.regular::after { background: linear-gradient(90deg, var(--cyan), transparent); }
.rating-card.quick::after  { background: linear-gradient(90deg, var(--mint), transparent); }
.rating-card.fide-standard::after  { background: linear-gradient(90deg, var(--gold), transparent); }
/* The same three accent rules for /about/'s site metrics, which is the other
   surface this tile serves. They used the rating-type names — the master
   database was `fide-standard` — which reads as a claim about a rating that
   does not exist there. Same hues, honest names. */
.rating-card.metric-archive::after { background: linear-gradient(90deg, var(--cyan), transparent); }
.rating-card.metric-public::after  { background: linear-gradient(90deg, var(--mint), transparent); }
.rating-card.metric-master::after  { background: linear-gradient(90deg, var(--gold), transparent); }

.rating-type {
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  letter-spacing: 4px;
  color: var(--muted);
  margin-bottom: 12px;
}
.rating-value {
  font-family: 'Orbitron', monospace;
  font-size: 2.8rem;
  font-weight: 900;
  line-height: 1;
  letter-spacing: 0;
}
.rating-card.regular .rating-value { color: var(--cyan); }
.rating-card.quick .rating-value   { color: var(--mint); }
.rating-card.fide-standard .rating-value   { color: var(--gold); }
.rating-card.metric-archive .rating-value { color: var(--cyan); }
.rating-card.metric-public .rating-value  { color: var(--mint); }
.rating-card.metric-master .rating-value  { color: var(--gold); }
.rating-digits {
  display: flex;
  justify-content: center;
  gap: 0.08em;
  letter-spacing: 0;
}

.rating-floor {
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  color: var(--muted);
  margin-top: 8px;
  letter-spacing: 2px;
}
.floor-val {
  color: var(--white);
  font-size: 11px;
}

/* REMOVED: a rating meter whose fill widths were hardcoded at 78%, 58% and
   66% — three invented numbers presented as data. Owner, 2026-08-05: "the
   lines seem to be of arbitrary length, if we are gonna do bars there has to
   be some meaning behind it - i cant think of any meaning here". Neither
   could the numbers. A bar returns only if it measures something true. */

/* ── PROFILE GRID ── */
.profiles-section { margin-bottom: 60px; animation: fadeUp 1s 0.5s ease both; }
.profiles-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
@media(max-width:580px) { .profiles-grid { grid-template-columns: 1fr; } }

.profile-link {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 18px 22px;
  text-decoration: none;
  color: inherit;
  transition: transform 0.2s;
}
.profile-link:hover { transform: translateX(4px); }

.profile-icon {
  width: 42px; height: 42px;
  border-radius: 3px;
  display: flex; align-items: center; justify-content: center;
  font-size: 20px;
  flex-shrink: 0;
  position: relative;
}
.profile-icon::after {
  content: '';
  position: absolute; inset: 0;
  border-radius: 3px;
  border: 1px solid currentColor;
  opacity: 0.3;
}
.profile-icon img,
.social-icon img {
  width: 24px;
  height: 24px;
  display: block;
}
.profile-icon.fide img,
.profile-icon.uschess img {
  width: 32px;
  height: 32px;
  object-fit: contain;
}
.profile-icon.fide   { background: rgba(var(--tint-rgb),0.1); color: var(--cyan); }
.profile-icon.uschess{ background: rgba(255,80,80,0.1); color: #ff6060; }
.profile-icon.lichess{ background: rgba(255,255,255,0.08); color: #e8e8e8; }
.profile-icon.chesscom{background: rgba(118,210,109,0.1); color: #76d26d; }

.profile-info {}
.profile-platform {
  font-family: 'Share Tech Mono', monospace;
  font-size: 9px;
  letter-spacing: 3px;
  color: var(--muted);
  text-transform: uppercase;
  margin-bottom: 3px;
}
.profile-handle {
  font-family: 'Orbitron', monospace;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--white);
}
.profile-arrow {
  margin-left: auto;
  font-size: 18px;
  color: var(--muted);
  transition: color 0.2s, transform 0.2s;
}
.profile-link:hover .profile-arrow {
  color: var(--cyan);
  transform: translateX(4px);
}

/* ── USCHESS RATINGS DISPLAY ── */
.uschess-badge {
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  color: var(--muted);
  margin-top: 4px;
  letter-spacing: 1px;
}
.uschess-badge span {
  color: #ff6060;
  font-size: 12px;
  font-weight: bold;
}

/* ── SOCIAL LINKS ── */
.socials-section { margin-bottom: 60px; animation: fadeUp 1s 0.7s ease both; }
.socials-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
@media(max-width:400px) { .socials-grid { grid-template-columns: 1fr; } }

.social-link {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 18px 22px;
  text-decoration: none;
  color: inherit;
  transition: transform 0.2s;
}
.social-link:hover { transform: translateX(4px); }

.social-icon {
  width: 40px; height: 40px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px;
  flex-shrink: 0;
}
.social-icon.twitter  { background: rgba(255,255,255,0.08); color: #ffffff; }
.social-icon.instagram{ background: rgba(225,48,108,0.15); color: #e1306c; }
.social-icon.github   { background: rgba(255,255,255,0.1); color: #ffffff; }
.social-icon.hackthebox {
  background: transparent;
  border-radius: 0;
  color: #9fef00;
}

.social-name {
  font-family: 'Orbitron', monospace;
  font-size: 0.85rem;
  font-weight: 600;
}
.social-handle {
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  color: var(--muted);
  letter-spacing: 1px;
  margin-top: 2px;
}

.hub-return {
  margin-top: 20px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
.hub-return a {
  display: inline-block;
  padding: 9px 18px;
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 12px;
  letter-spacing: 2px;
  text-decoration: none;
  border: 1px solid rgba(var(--tint-rgb), 0.42);
  background: rgba(var(--tint-rgb), 0.06);
  box-shadow: 0 0 18px rgba(var(--tint-rgb), 0.08), inset 0 0 18px rgba(var(--tint-rgb), 0.04);
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.hub-return a:hover {
  color: var(--white);
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.12);
  box-shadow: 0 0 24px rgba(var(--tint-rgb), 0.22), inset 0 0 22px rgba(var(--tint-rgb), 0.08);
}
.portfolio-section { animation-delay: 0.7s; }

/* ── FOOTER ── */
.footer {
  text-align: center;
  margin-top: 80px;
  animation: fadeUp 1s 1s ease both;
}
.footer-line {
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  letter-spacing: 4px;
  color: var(--muted);
  text-transform: uppercase;
}
.footer-line span { color: var(--chrome); }

/* ── SITE / ACCOUNT ACCESS ── */
.mobile-nav-toggle,
.mobile-nav-close {
  display: none;
}

.header-nav-row {
  /* Keep the shared DOM group for device routing, but preserve the desktop
     placement from the Apps + Donate launch: primary navigation is anchored
     from the left and account/search from the right. At the finite width where
     those reference bars cannot fit, the desktop-only fallback below keeps one
     horizontally scrollable row without ever exposing the mobile drawer. */
  --header-nav-min-gap: 16px;
  position: absolute;
  top: 18px;
  left: 78px;
  right: 78px;
  z-index: 1001;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--header-nav-min-gap);
  pointer-events: none;
}
.header-nav-row > .site-nav,
.header-nav-row > .account-nav {
  pointer-events: auto;
}

.site-nav {
  --site-nav-drawer-label-size: 0.9rem;
  position: static;
  flex: 0 1 max-content;
  min-width: 0;
  max-width: 100%;
  z-index: 1001;
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 8px;
  font-family: 'Share Tech Mono', monospace;
}
.site-nav > .site-nav-link,
.site-nav > .site-nav-dropdown {
  flex: none;
}

.site-nav-link {
  position: relative;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 14px;
  border: 1px solid rgba(var(--tint-rgb), 0.38);
  background: rgba(var(--void-rgb), 0.78);
  color: var(--chrome);
  font-size: 0.76rem;
  letter-spacing: 1.7px;
  text-transform: uppercase;
  text-decoration: none;
  box-shadow: inset 0 0 16px rgba(var(--tint-rgb), 0.04), 0 0 14px rgba(var(--tint-rgb), 0.08);
  text-shadow: 0 0 12px rgba(var(--cyan-rgb), 0.24);
  transition: color 0.18s ease, border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}
.site-nav-link::before {
  content: '';
  width: 4px;
  height: 4px;
  margin-right: 8px;
  display: inline-block;
  background: var(--tint);
  box-shadow: 0 0 10px rgba(var(--tint-rgb), 0.65);
}
.site-nav-link::after {
  content: '';
  position: absolute;
  left: 8px;
  right: 8px;
  bottom: 3px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(var(--tint-rgb), 0.62), transparent);
  opacity: 0.65;
  transition: opacity 0.18s ease, left 0.18s ease, right 0.18s ease;
}
.site-nav-link:hover,
.site-nav-link:focus-visible,
.site-nav-dropdown:hover > .site-nav-trigger,
.site-nav-dropdown:focus-within > .site-nav-trigger {
  color: var(--white);
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.12);
  box-shadow: inset 0 0 18px rgba(var(--tint-rgb), 0.08), 0 0 20px rgba(var(--tint-rgb), 0.22);
}
.site-nav-link:hover::after,
.site-nav-link:focus-visible::after,
.site-nav-dropdown:hover > .site-nav-trigger::after,
.site-nav-dropdown:focus-within > .site-nav-trigger::after {
  opacity: 1;
  left: 4px;
  right: 4px;
}
.site-nav-link.action-prominent {
  border-color: rgba(var(--cyan-rgb), 0.72);
  background: linear-gradient(180deg, rgba(var(--cyan-rgb), 0.3), rgba(var(--cyan-rgb), 0.13));
  color: var(--white);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 0 18px rgba(var(--cyan-rgb), 0.24);
}
.site-nav-link.action-prominent:hover,
.site-nav-link.action-prominent:focus-visible {
  border-color: var(--cyan);
  background: linear-gradient(180deg, rgba(var(--cyan-rgb), 0.4), rgba(var(--cyan-rgb), 0.2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 0 24px rgba(var(--cyan-rgb), 0.34);
}
.site-nav-dropdown {
  position: relative;
}
.site-nav-dropdown::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 0;
  z-index: 1001;
  display: none;
  width: 100%;
  min-width: 214px;
  height: 6px;
}
.site-nav-dropdown:hover::after,
.site-nav-dropdown:focus-within::after {
  display: block;
}
.site-nav-trigger {
  gap: 7px;
}
.site-nav-caret {
  margin-left: 2px;
  color: rgba(var(--gold-rgb), 0.82);
  font-size: 0.7rem;
  line-height: 1;
}
.site-nav-menu {
  position: absolute;
  /* Flush against its trigger, not floating 6px below it (owner, 2026-08-05:
     "there is a gap between the nav and the drop down"). The gap also had to be
     crossed by the pointer on the way into the menu, so a hover-opened menu
     could close on the way to the thing it opened for. */
  top: 100%;
  left: 0;
  z-index: 1002;
  /* Sized by its longest label, not a fixed 214px. That hardcoded width is the
     dead space in the STUDY and account menus (owner images 12, 13) — a menu
     is as wide as its words. The floor stops a two-word menu becoming a sliver
     next to its trigger; the cap stops a long label running off a phone.
     `max-content` is what actually reads the words: an absolutely positioned
     box shrink-to-fits against its containing block, which here is the trigger,
     so without it "Opening Explorer" wraps inside a 127px ARCHIVE button. */
  width: max-content;
  min-width: 150px;
  max-width: min(300px, calc(100vw - 32px));
  padding: 6px;
  border: 1px solid rgba(var(--tint-rgb), 0.42);
  background: rgba(var(--ink-rgb), 0.98);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.46), 0 0 28px rgba(var(--tint-rgb), 0.14);
  display: none;
  flex-direction: column;
  gap: 2px;
}
.site-nav-dropdown:hover .site-nav-menu,
.site-nav-dropdown:focus-within .site-nav-menu {
  display: flex;
}
/* Keyboard focus deliberately opens the same flush menu as hover. Escape must
   also be able to close it without throwing focus out of the header; the
   controller holds this one-turn suppression until focus or the pointer leaves
   the dropdown, while keeping the existing hover/focus anatomy unchanged. */
.site-nav-dropdown.is-keyboard-dismissed:focus-within::after,
.site-nav-dropdown.is-keyboard-dismissed:focus-within .site-nav-menu {
  display: none;
}
.site-nav-menu-item {
  min-height: 36px;
  display: flex;
  align-items: center;
  padding: 0 10px;
  color: var(--chrome);
  font-size: 0.76rem;
  letter-spacing: 1px;
  text-transform: none;
  text-decoration: none;
  border: 1px solid transparent;
}
.site-nav-menu-item:hover,
.site-nav-menu-item:focus-visible {
  color: var(--white);
  border-color: rgba(var(--tint-rgb), 0.4);
  background: rgba(var(--tint-rgb), 0.08);
}

/* ── STATS AND GAME SEARCH ── */
/* Desktop keeps the 920px column: a lone search field stretched across a 1600px
   screen is what the owner rejected ("that shouldnt be like that"). The phone
   rule in the max-width:720px block drops the `- 36px` inset instead. */
.stats-header {
  width: min(920px, calc(100vw - 36px));
  max-width: none;
  margin-left: auto;
  margin-right: auto;
  text-align: center;
}
.stats-header::before {
  content: '';
  display: block;
  height: 1.2rem;
}
/* Game search and /stats/, not the Opening Explorer. On /stats/ the search sat
   flush against the bottom of the title with no gap at all while game search
   had 56px — same header, same control, two different pages — so the gap moved
   off the game-search class. The explorer keeps the flush spacing it ships
   with: its panel is the page, and 56px under the title pushed the board most
   of a screen down (owner, 2026-08-06: "the title of the page is pushing the
   entire thing down too uch"). */
body:not(.opening-explorer-page) .stats-header {
  margin-bottom: clamp(32px, 3vw, 40px);
}
.stats-panel {
  width: min(920px, calc(100vw - 36px));
  margin: 0 auto 56px;
  border: 1px solid rgba(var(--tint-rgb), 0.3);
  background: rgba(var(--ink-rgb), 0.82);
  box-shadow: 0 0 34px rgba(var(--tint-rgb), 0.1), inset 0 0 20px rgba(var(--tint-rgb), 0.04);
  padding: 22px;
}
/* 120px of air belonged to the state where this search was the whole page.
   Results now sit beneath it, so the region keeps the family's own 56px. */
.stats-game-search-panel {
  margin-bottom: 56px;
}
.stats-form {
  display: grid;
  gap: 12px;
}
.stats-fields {
  display: grid;
  grid-template-columns: minmax(220px, 1fr) auto;
  align-items: end;
  gap: 12px;
}
.stats-field {
  display: grid;
  gap: 7px;
}
.stats-field span {
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.stats-field input {
  min-height: 42px;
  width: 100%;
  border: 1px solid rgba(var(--tint-rgb), 0.35);
  border-radius: 0;
  background: rgba(0, 0, 0, 0.28);
  color: var(--white);
  padding: 0 12px;
  font: 0.95rem 'Inter', sans-serif;
}
.stats-field input:focus {
  outline: none;
  border-color: rgba(var(--tint-rgb), 0.78);
  box-shadow: 0 0 16px rgba(var(--tint-rgb), 0.16);
}
.stats-submit {
  min-height: 42px;
  white-space: nowrap;
  border: 1px solid rgba(var(--tint-rgb), 0.5);
  border-radius: 0;
  background: rgba(var(--tint-rgb), 0.08);
  color: var(--chrome);
  padding: 0 18px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.74rem;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: inset 0 0 16px rgba(var(--tint-rgb), 0.05), 0 0 14px rgba(var(--tint-rgb), 0.08);
  transition: color 0.18s ease, border-color 0.18s ease, background 0.18s ease, box-shadow 0.18s ease;
}
.stats-submit:hover,
.stats-submit:focus-visible {
  color: var(--white);
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.14);
  box-shadow: inset 0 0 18px rgba(var(--tint-rgb), 0.08), 0 0 20px rgba(var(--tint-rgb), 0.18);
  outline: none;
}
.stats-notice {
  margin: 18px 0 0;
  color: var(--muted);
  font-size: 0.92rem;
  line-height: 1.6;
}
.stats-resolution-feedback {
  width: min(620px, 100%, calc(100vw - 28px));
  margin: 18px auto 42px;
}
.stats-candidate-list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}
.stats-candidate-list a {
  border: 1px solid rgba(var(--tint-rgb), 0.28);
  color: var(--cyan);
  padding: 6px 9px;
  text-decoration: none;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.76rem;
}
.stats-candidate-list a:hover,
.stats-candidate-list a:focus-visible {
  color: var(--white);
  border-color: var(--cyan);
}
.stats-result {
  margin-top: 24px;
  border-top: 1px solid rgba(var(--tint-rgb), 0.22);
  padding-top: 20px;
}
.stats-result-heading span {
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 1.6px;
  /* Casing belongs to the kicker, not the template (see .games-table th). The
     template used to type PLAYER RECORD / HEAD TO HEAD in capitals itself. */
  text-transform: uppercase;
}
.stats-result-heading h2 {
  margin: 6px 0 16px;
  color: var(--white);
  font-size: clamp(1.35rem, 3vw, 2rem);
  font-weight: 500;
  letter-spacing: 0;
}
.stats-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 10px;
}
.stats-grid div {
  min-height: 74px;
  display: grid;
  align-content: center;
  gap: 4px;
  border: 1px solid rgba(var(--tint-rgb), 0.22);
  background: rgba(var(--tint-rgb), 0.04);
  padding: 10px;
}
.stats-grid span {
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 1.1px;
  text-transform: uppercase;
}
.stats-grid strong {
  color: var(--white);
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: 0;
}
.stats-insights {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid rgba(var(--tint-rgb), 0.18);
}
.stats-insights-heading span {
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 1.6px;
  text-transform: uppercase;
}
.stats-insights-heading h3 {
  margin: 6px 0 16px;
  color: var(--white);
  font-size: 1.15rem;
  font-weight: 500;
  letter-spacing: 0;
}
.stats-insight-columns {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}
.stats-insight-column {
  min-width: 0;
  border: 1px solid rgba(var(--tint-rgb), 0.22);
  background: rgba(var(--tint-rgb), 0.035);
  padding: 12px;
}
.stats-insight-column h4 {
  margin: 0 0 10px;
  color: var(--gold);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  letter-spacing: 1.4px;
  text-transform: uppercase;
}
.stats-opening-row {
  display: grid;
  gap: 7px;
  padding: 10px 0;
  border-top: 1px solid rgba(var(--tint-rgb), 0.14);
  /* Moved off an inline style attribute on the anchor. Inline declarations
     outrank every layer of the cascade, so neither theme could touch this
     row's voice — which is the whole reason the role system exists. */
  text-decoration: none;
  color: inherit;
}
.stats-opening-row:first-of-type {
  border-top: 0;
  padding-top: 2px;
}
.stats-opening-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content;
  align-items: center;
  gap: 8px;
}
.stats-opening-main strong {
  max-width: 112px;
  overflow: hidden;
  color: var(--cyan);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.9rem;
  text-align: right;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.stats-opening-main span {
  min-width: 0;
  color: var(--white);
  font-size: 0.92rem;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.stats-opening-meta {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.7px;
}
.stats-opening-bar {
  display: flex;
  height: 9px;
  overflow: hidden;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(0, 0, 0, 0.34);
}
.stats-opening-bar span {
  min-width: 0;
}
.stats-opening-win {
  background: rgba(var(--mint-rgb), 0.76);
}
.stats-opening-draw {
  background: rgba(var(--amber-rgb), 0.72);
}
.stats-opening-loss {
  background: rgba(var(--danger-rgb), 0.72);
}
.stats-insight-empty {
  margin: 0;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}

/* Legal documents (privacy policy, etc.) */
.legal-doc {
  max-width: 820px;
  margin: 0 auto;
}
.legal-doc .bio-section-heading { font-size: 1.2rem; }
.legal-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  margin-bottom: 32px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
}
.legal-meta strong { color: var(--gold); }
.legal-list {
  margin: 0 0 16px;
  padding-left: 22px;
  list-style: none;
}
.legal-list li {
  position: relative;
  font-size: 1.02rem;
  line-height: 1.7;
  color: rgba(var(--white-rgb), 0.82);
  margin-bottom: 10px;
}
.legal-list li::before {
  content: "▸";
  position: absolute;
  left: -22px;
  color: var(--gold);
}
.legal-list li strong { color: var(--white); }
.legal-doc a {
  color: var(--cyan);
  text-decoration: underline;
}

/* ---- REST API documentation page ---- */
.apidoc {
  max-width: 880px;
  margin: 0 auto;
}
.apidoc a {
  color: var(--cyan);
  text-decoration: none;
}
.apidoc a:hover { text-decoration: underline; }
.apidoc-inline {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.86em;
  color: var(--gold);
  background: rgba(var(--tint-rgb), 0.06);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 6px;
  white-space: nowrap;
}
/* Space disclosure controls use its existing surface and focus tokens. */
body:not(.site-theme-charcoal) .action-secondary.is-disclosure {
  min-height: 44px;
  padding: 9px 18px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--chrome);
  font: inherit;
  cursor: pointer;
}
body:not(.site-theme-charcoal) .action-secondary.is-disclosure:hover {
  border-color: var(--cyan);
}
body:not(.site-theme-charcoal) .action-secondary.is-disclosure:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
/* Documentation keeps its desktop rail and shares the mobile site drawer. */
.api-docs-page #andromeda-page-shell { max-width: 1280px; }
.api-docs-layout {
  display: grid;
  grid-template-columns: 240px minmax(0, 880px);
  gap: 48px;
  max-width: 1168px;
  margin: 40px auto 0;
}
.api-docs-layout .apidoc { min-width: 0; width: 100%; }
.api-docs-rail { min-width: 0; border-right: 1px solid var(--border); }
#api-docs-menu { position: sticky; top: 24px; max-height: calc(100dvh - 48px); overflow-y: auto; }
.api-docs-header { margin-bottom: 32px; }
.api-docs-lede { margin: 0 0 32px; }
.api-docs-header .page-kicker { margin: 0 0 12px; }
.api-docs-header .page-title { margin: 0; }
.api-docs-layout .bio-section { margin-top: 0; }
.api-docs-group + .api-docs-group { margin-top: 24px; }
/* The shared drawer hosts one page panel at a time, plus the site links. */
[data-drawer-rail][hidden], #site-nav [hidden] { display: none !important; }
.drawer-panel-chooser {
  position: absolute;
  top: 13px;
  right: 18px;
  display: flex;
  max-width: calc(100% - 88px);
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 24px;
  background: var(--surface);
}
.drawer-panel-tab {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 22px;
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.drawer-panel-tab[aria-selected="true"] { background: rgba(var(--cyan-rgb), 0.14); color: var(--cyan); }
.drawer-panel-tab:hover { color: var(--cyan); }
.drawer-panel-tab:focus-visible { outline: 2px solid var(--cyan); outline-offset: -3px; }
.drawer-panel-tab svg { width: 20px; height: 20px; }
.drawer-site-links { display: flex; flex-direction: column; gap: 8px; }
#site-nav [data-drawer-panel] { position: static; max-height: none; overflow: visible; margin: 0; padding: 0; border: 0; }
#site-nav [data-drawer-panel] .doc-toc { border: 0; padding: 0; }
#site-nav [data-drawer-panel] .doc-toc a { min-height: 44px; box-sizing: border-box; }
html[data-device="mobile"] .api-docs-layout:has(.api-docs-rail[hidden]) { grid-template-columns: minmax(0, 1fr); }
.api-docs-skip:not(:focus) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
.api-docs-skip:focus { display: block; margin-bottom: 12px; }
.api-docs-pagination { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 16px; margin-top: 40px; padding-top: 24px; border-top: 1px solid var(--border); }
.api-docs-pagination .prose-body { margin: 0; }
.api-docs-pagination p:has(a[rel="next"]) { margin-left: auto; }
.doc-toc.is-sidebar { border: 0; padding: 0 20px 0 0; }
.doc-toc.is-sidebar ul { display: grid; gap: 2px; list-style: none; margin: 0; padding: 0; }
.doc-toc.is-sidebar .block-label { margin: 0 0 10px; }
.doc-toc.is-sidebar :is(a,button) { display:flex; align-items:center; justify-content:space-between; gap:8px; box-sizing:border-box; width:100%; min-height:44px; padding:10px 12px; border:0; border-left:2px solid transparent; border-radius:0; background:transparent; box-shadow:none; font:inherit; text-align:left; text-decoration:none; color:var(--white); cursor:pointer; }
.doc-toc.is-sidebar :is(a,button):hover, .doc-toc.is-sidebar :is(a,button):focus-visible { color:var(--cyan); background:var(--surface); }
.doc-toc.is-sidebar :is(a,button)[aria-current="page"] { color:var(--cyan); background:rgba(var(--cyan-rgb),0.08); border-left-color:var(--cyan); }
.doc-toc.is-sidebar :is(a,button):focus-visible { outline:2px solid var(--cyan); outline-offset:-2px; }
@media (max-width: 960px) {
  .api-docs-layout { grid-template-columns: minmax(0, 1fr); gap: 24px; margin-top: 24px; }
  .api-docs-rail { border-right: 0; }
  #api-docs-menu { position: static; max-height: none; overflow: visible; }
  .doc-toc.is-sidebar { border-right: 0; border-bottom: 1px solid var(--border); padding: 0 0 20px; }
}
.apidoc-pre {
  margin: 0 0 18px;
  border: 1px solid var(--border);
  border-left: 2px solid var(--tint);
  border-radius: 6px;
  background: var(--void);
  overflow-x: auto;
}
.apidoc-pre pre {
  margin: 0;
  padding: 16px 18px;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.84rem;
  line-height: 1.6;
  color: rgba(var(--white-rgb), 0.9);
  white-space: pre;
  tab-size: 2;
}
.apidoc-label {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--muted);
  /* The air above these labels used to come from the `block-label` role, which
     had no business setting spacing — it also fought /about/'s label rail.
     The surface owns the placement now. */
  margin: 18px 0 8px;
}
.apidoc-note {
  font-size: 0.95rem;
  line-height: 1.7;
  color: rgba(var(--white-rgb), 0.7);
  margin: 4px 0 0;
}
.apidoc-download {
  display: inline-block;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.85rem;
  letter-spacing: 0.5px;
  color: var(--chrome);
  border: 1px solid var(--tint);
  border-radius: 6px;
  padding: 7px 14px;
  text-decoration: none;
  transition: background 0.2s ease, box-shadow 0.2s ease;
}
.apidoc-download:hover {
  background: rgba(var(--tint-rgb), 0.1);
  box-shadow: 0 0 12px var(--cyan-glow);
  text-decoration: none;
}
.apidoc-download .apidoc-inline { color: var(--chrome); }
.apidoc-endpoint {
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--glass);
  padding: 22px 24px;
  margin-bottom: 22px;
}
.apidoc-endpoint-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}
.apidoc-method {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 1px;
  color: var(--void);
  background: var(--cyan);
  border-radius: 4px;
  padding: 3px 9px;
}
/* Verb color follows the Swagger convention every API reader already knows:
   reads are blue, writes are green, deletes are red. */
.apidoc-method-post {
  background: var(--mint);
}
.apidoc-method-delete {
  background: var(--danger);
  color: #ffffff;
}
.apidoc-path {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.96rem;
  color: var(--white);
  word-break: break-all;
}
.apidoc-endpoint-desc {
  font-size: 1rem;
  line-height: 1.65;
  color: rgba(var(--white-rgb), 0.8);
  margin: 0 0 16px;
}
.apidoc-table {
  width: 100%;
  border-collapse: collapse;
  margin: 0 0 18px;
  font-size: 0.92rem;
}
.apidoc-table th,
.apidoc-table td {
  text-align: left;
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
  line-height: 1.55;
}
.apidoc-table th {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--muted);
}
.apidoc-table td { color: rgba(var(--white-rgb), 0.82); }
.apidoc-table tr:last-child td { border-bottom: none; }
/* Keep commands copyable as one logical line and wrap only at word boundaries. */
.api-docs-page .apidoc-pre pre[data-language="shell"] {
  white-space: pre-wrap;
  overflow-wrap: normal;
  word-break: normal;
}
body.site-theme-charcoal.api-docs-page .apidoc .code-inline {
  white-space: nowrap;
  overflow-wrap: normal;
  word-break: normal;
}
.api-docs-page .reference-table-window {
  width: 100%;
  overflow-x: auto;
  margin-bottom: 18px;
}
.api-docs-page .reference-table-window .apidoc-table {
  display: table;
  width: 100%;
  margin-bottom: 0;
}
.api-docs-page .apidoc-path {
  max-width: 100%;
  overflow-x: auto;
  white-space: nowrap;
  word-break: normal;
}
.apidoc-sdks { margin: 0 0 36px; }
.apidoc-sdk-heading { margin: 0 0 10px; text-align: center; color: var(--gold); font-size: 1.5rem; }
.apidoc-sdk-intro { margin: 0 0 24px; text-align: center; line-height: 1.6; color: var(--muted); }
.apidoc-sdk-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; margin-bottom: 18px; }
.apidoc-sdk-card {
  --sdk-accent: var(--gold);
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 22px 18px;
  border: 1px solid var(--border);
  border-top: 3px solid var(--sdk-accent);
  border-radius: 8px;
  background: var(--surface);
}
.apidoc-sdk-card--typescript { --sdk-accent: var(--cyan); }
.apidoc-sdk-card--kotlin { --sdk-accent: var(--name); }
.apidoc-sdk-eyebrow { margin: 0 0 12px; font-size: 0.9rem; letter-spacing: 1px; text-align: center; color: var(--muted); }
.apidoc-sdk-card h3 { margin: 0 0 14px; color: var(--sdk-accent); font-size: 1.22rem; line-height: 1.4; text-align: center; }
.apidoc-sdk-package { margin: 0 0 16px; text-align: center; font-family: 'Share Tech Mono', monospace; font-size: 0.9rem; overflow-x: auto; white-space: nowrap; }
.apidoc-sdk-detail { flex: 1; margin: 0 0 22px; font-size: 0.92rem; line-height: 1.6; }
.apidoc a.apidoc-sdk-link { display: block; padding: 10px 4px; border-top: 1px solid var(--border); color: var(--sdk-accent); text-align: center; font-size: 0.92rem; }
@media (max-width: 760px) {
  .apidoc-sdk-grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .apidoc-endpoint { padding: 18px 16px; }
  .apidoc-pre pre { font-size: 0.78rem; }
}

.footer-links {
  margin-top: 12px;
}
.footer-links-primary {
  margin-top: 10px;
}
.footer-links-source {
  margin-top: 6px;
}
.footer-links a {
  color: var(--chrome);
  text-decoration: none;
  letter-spacing: 1px;
}
.footer-links a:hover {
  text-decoration: underline;
}
.icon-sprite {
  display: none;
}
html.animations-disabled *,
html.animations-disabled *::before,
html.animations-disabled *::after {
  animation: none !important;
  transition: none !important;
  scroll-behavior: auto !important;
}
html.animations-disabled .data-feed span {
  padding-left: 0;
}

/* Honour the OS "reduce motion" preference the same way the account toggle does,
   so visitors who request calm get it without an account. Mirrors the
   animations-disabled kill switch above. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
  .data-feed span {
    padding-left: 0;
  }
}

/* ── PULSE DOTS ── */
.pulse-dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--mint);
  margin-right: 8px;
  vertical-align: middle;
  animation: pulseDot 2s ease-in-out infinite;
}
@keyframes pulseDot {
  0%,100%{box-shadow:0 0 0 0 rgba(var(--mint-rgb),0.5); opacity:1;}
  50%{box-shadow:0 0 0 6px rgba(var(--mint-rgb),0); opacity:0.7;}
}
/* Event bios keep the status dot but not the animation (owner call). */
.pulse-dot.pulse-dot-static { animation: none; }

/* ── FADE UP ── */
@keyframes fadeUp {
  from { opacity:0; transform: translateY(20px); }
  to   { opacity:1; transform: translateY(0); }
}

/* ── ANDROMEDA GALAXY BACKDROP ──
   A procedural sprite drawn ONCE by main.js (set as background-image on
   .galaxy-disc). All motion is GPU CSS transform: the disc spins in its own
   plane, and the parent gently floats. No per-frame JS/canvas work. */
.galaxy-field {
  position: fixed; inset: 0; z-index: 0;
  pointer-events: none; overflow: hidden;
  perspective: 1600px;
  opacity: 1;
  transition: opacity 500ms ease;
}
.galaxy-drift {
  position: absolute;
  top: 4%; left: 50%;
  width: 62vmin; height: 62vmin;
  margin-left: -31vmin;
  transform-style: preserve-3d;
  transform: translate(-24vw, 2vh);
  will-change: transform;
  backface-visibility: hidden;
  animation: galaxyDrift 200s linear infinite;
}
.galaxy-tilt {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: rotateZ(-20deg) rotateX(72deg);
}
.galaxy-disc {
  position: absolute; inset: 0;
  background-repeat: no-repeat; background-position: center; background-size: contain;
  will-change: transform;
  backface-visibility: hidden;
  animation: galaxySpin 34s linear infinite;
}
@keyframes galaxySpin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}
.galaxy-satellites {
  position: absolute; inset: 0;
  pointer-events: none;
  background-repeat: no-repeat;
  background-image:
    radial-gradient(ellipse at center,
      rgba(255,240,212,0.26) 0%, rgba(255,233,196,0.10) 44%, rgba(255,233,196,0) 72%),
    radial-gradient(circle at center,
      rgba(255,252,244,0.52) 0%, rgba(255,226,172,0.28) 26%, rgba(255,226,172,0) 60%);
  background-size: 32% 22%, 8.5% 8.5%;
  background-position: 30% 26%, 56% 61%;
}
@keyframes galaxyDrift {
  0%    { transform: translate(-24vw,  2vh); }
  12.5% { transform: translate(-17vw, -3vh); }
  25%   { transform: translate(  0vw, -5vh); }
  37.5% { transform: translate( 17vw, -3vh); }
  50%   { transform: translate( 24vw,  2vh); }
  62.5% { transform: translate( 17vw,  6vh); }
  75%   { transform: translate(  0vw,  7vh); }
  87.5% { transform: translate(-17vw,  6vh); }
  100%  { transform: translate(-24vw,  2vh); }
}
/* ── ANIMATED DATA FEED ── */
.data-feed {
  font-family: 'Share Tech Mono', monospace;
  font-size: 9px;
  color: rgba(var(--cyan-rgb),0.4);
  letter-spacing: 2px;
  text-align: center;
  margin-bottom: 28px;
  overflow: hidden;
  white-space: nowrap;
  /* Full-bleed: break out of the centered .page column so the feed spans the
     whole viewport and the text travels from the true right edge to the true
     left edge. Root/body overflow-x is clipped, so this cannot reintroduce the
     horizontal drift. */
  width: 100vw;
  max-width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
}
.data-feed span {
  display: inline-block;
  min-width: max-content;
  padding-left: 100%;
  animation: feedScroll 20s linear infinite;
  will-change: transform;
}
@keyframes feedScroll {
  0% { transform: translateX(0); }
  100% { transform: translateX(-100%); }
}

/* ── DATA-SURFACE WIDTH ──
   "Theme the frame, calm the canvas": working/data surfaces (game search and
   the study/annotated game lists) carry wide scannable tables, so the bordered
   results frame breaks out of the narrow centered column and re-centers in the
   viewport. body/html have overflow-x: clip, so the off-screen layout overflow
   from the centering transform is clipped instead of triggering a scrollbar.
   Search controls and prose stay narrow within their own constraints. */
/* The results break out, not the panel. The panel used to carry this width,
   so submitting a query grew it from 764px to 1600px and re-laid the page out
   around the form instead of putting an answer under it (owner images 10 → 11,
   "blowing up"). The form now holds its position in all three states. */
.stats-game-search-page #games-results-card.has-table,
.games-listing-page #games-results-card {
  width: min(1600px, calc(100vw - 36px));
  margin-left: 50%;
  margin-right: 0;
  transform: translateX(-50%);
}
/* #games-results-card is a .card, which lifts on :hover via transform; keep the
   breakout centering so the wide table does not snap back to the column. */
.games-listing-page #games-results-card:hover {
  transform: translateX(-50%);
}
.study-archive-nav {
  max-width: 760px;
  margin: -12px auto 28px;
  padding: 0 20px;
  display: flex;
  justify-content: center;
}
/* No width override on the search card and no empty-state modifier. The panel
   is one width in every state now, so game search and stats lookup are the
   same object at the same size — which was the point of treating the three
   stats surfaces as one family. */

/* ── GAMES TABLE ── */
.games-table-container {
  overflow-x: auto;
  margin-top: 20px;
}
.games-table {
  width: 100%;
  border-collapse: collapse;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.85rem;
}
.games-table th {
  text-align: left;
  padding: 15px;
  color: var(--chrome);
  border-bottom: 2px solid var(--tint);
  font-family: 'Orbitron', sans-serif;
  letter-spacing: 2px;
  font-size: 0.75rem;
  /* Casing is the header's to decide, not the template's. The four surfaces
     that share this table used to type it by hand and disagreed: the MasterDB
     header read "Date, Players, Result, Moves, OPENINGS, Event" while the same
     component on the player game list shouted all six. The templates now say
     the words in ordinary case and this rule shouts them, so no surface can
     drift again. */
  text-transform: uppercase;
  background: rgba(var(--tint-rgb), 0.05);
  text-shadow: 0 0 10px var(--cyan-glow);
}
.games-sort-link {
  color: inherit;
  text-decoration: none;
  border: 0;
  background: transparent;
  font: inherit;
  letter-spacing: inherit;
  /* The `font` shorthand carries no casing and the UA stylesheet sets
     `text-transform: none` on button, so this one heading did not hear
     `.games-table th` shouting and the sortable column read "Date ▲" beside
     PLAYERS, RESULT and MOVES. It wears whatever casing its header decides. */
  text-transform: inherit;
  padding: 0;
  cursor: pointer;
}
.games-sort-link:hover {
  color: var(--white);
}
/* Live game-search input (game lists + annotated books). Class-based so the
   active site theme can restyle it — an inline style would beat every theme
   rule. */
.games-search-input {
  flex: 1;
  padding: 12px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.3);
  color: var(--cyan);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  outline: none;
}
/* Player pairing cell in game tables (game lists, books, MasterDB). */
.game-row-players {
  font-family: 'Orbitron', sans-serif;
  font-size: 0.8rem;
}
.game-row-players .game-row-name {
  color: var(--cyan);
}
.game-row-players .game-row-vs {
  margin: 0 5px;
  color: var(--muted);
}
.games-result-filters {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin: -10px 0 30px;
  flex-wrap: wrap;
}
.games-filter-btn {
  display: inline-block;
  min-width: 0;
  padding: 12px 30px;
  color: var(--chrome);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.9rem;
  letter-spacing: 2px;
  cursor: pointer;
  border-color: var(--tint);
}
.games-filter-btn:hover {
  color: var(--cyan);
}
.games-filter-btn.active {
  color: var(--white);
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.08);
  box-shadow: 0 0 24px rgba(var(--tint-rgb),0.14), inset 0 0 24px rgba(var(--tint-rgb),0.05);
}
.study-search-form {
  align-items: stretch;
}
.study-search-modes {
  display: flex;
  border: 1px solid var(--border);
  background: rgba(0,0,0,0.24);
}
.study-search-mode {
  flex: 1;
  min-width: 0;
  min-height: 44px;
  display: grid;
  place-items: center;
  padding: 0 14px;
  color: var(--muted);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.68rem;
  letter-spacing: 2px;
  cursor: pointer;
  border-right: 1px solid var(--border);
}
.study-search-mode:last-child {
  border-right: 0;
}
.study-search-mode:focus-within {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
}
.study-search-mode input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.study-search-mode.active {
  color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.08);
  box-shadow: inset 0 0 22px rgba(var(--tint-rgb),0.08);
}
.games-pagination {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  margin: 20px 0 0;
  font-family: 'Share Tech Mono', monospace;
}
.games-pagination.games-pagination-cluster {
  display: flex;
  width: 100%;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
}
.games-page-side {
  display: flex;
  gap: 8px;
}
.games-page-side.right {
  justify-content: flex-end;
}
.games-page-link {
  display: inline-block;
  padding: 8px 14px;
  color: var(--chrome);
  text-decoration: none;
  font-size: 0.72rem;
  letter-spacing: 1.5px;
  border-color: var(--tint);
}
.games-page-link.icon {
  width: 40px;
  height: 34px;
  display: grid;
  place-items: center;
  padding: 0;
  font-size: 1.05rem;
  letter-spacing: 0;
  line-height: 1;
}
.games-page-link.icon svg {
  width: 18px;
  height: 18px;
}
.games-page-link.icon.primary {
  border-color: rgba(var(--tint-rgb), 0.7);
  box-shadow: 0 0 18px rgba(var(--tint-rgb), 0.08), inset 0 0 16px rgba(var(--tint-rgb), 0.04);
}
.games-page-link.icon:hover {
  color: var(--white);
}
.games-page-status {
  color: var(--muted);
  letter-spacing: 2px;
  font-size: 0.76rem;
}
.games-table td {
  padding: 15px;
  border-bottom: 1px solid var(--border);
  color: var(--white);
  transition: background 0.2s;
  vertical-align: middle;
}
.games-table tr:hover td {
  background: rgba(var(--tint-rgb), 0.03);
}
.games-table .games-result-cell {
  text-align: center;
}
.games-table .games-result-value {
  display: inline-block;
  min-width: 3ch;
  text-align: center;
}
.games-table .result-win { color: var(--cyan); font-weight: bold; }
.games-table .result-loss { color: var(--danger); font-weight: bold; }
.games-table .result-draw { color: var(--gold); font-weight: bold; }

/* Homes for what used to be inline `style=` attributes on the game tables.
   An inline style outranks every theme layer, which is why these three
   columns were immune to the charcoal type scale and stayed dim and small
   while everything around them moved. The colours here are unchanged, so the
   Space theme renders exactly as before; charcoal reaches them through the
   `data-cell` role, which outranks these by specificity. */
/* Stroked, never filled. Both paths of this glyph are open arcs; without an
   explicit `fill: none` the browser closes and fills them, which is how the
   opening explorer's reset control ended up as a black blob while the same
   markup on a board page rendered correctly. */
.rotation-control-icon {
  display: inline-block;
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: square;
  stroke-linejoin: miter;
  vertical-align: middle;
  pointer-events: none;
}

.games-moves-cell {
  text-align: center;
}
/* Openings stay gold everywhere by owner call — the one column where gold is
   still doing a job. */
.games-opening-value {
  color: var(--gold);
}
.games-empty-cell {
  padding: 40px;
  text-align: center;
  color: var(--muted);
}

/* The 26px used to separate the form from results inside the same panel.
   Results are a sibling below the panel now, so it is just a tail of empty
   panel under the input. */
.stats-game-search-card {
  margin-bottom: 0;
}

.stats-game-search-form {
  display: grid;
  gap: 10px;
}

.stats-search-help {
  position: absolute;
  right: 8px;
  top: 50%;
  transform: translateY(-50%);
}

.stats-search-help summary {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 1px solid rgba(var(--tint-rgb), 0.38);
  background: rgba(0, 0, 0, 0.2);
  color: var(--muted);
  cursor: pointer;
  font-family: 'Orbitron', sans-serif;
  font-size: 0.72rem;
  line-height: 1;
  list-style: none;
  user-select: none;
}
.stats-search-help summary svg {
  width: 18px;
  height: 18px;
}

.stats-search-help summary::-webkit-details-marker {
  display: none;
}

.stats-search-help[open] summary {
  border-color: var(--gold);
  color: var(--gold);
  box-shadow: 0 0 16px rgba(var(--gold-rgb), 0.16);
}

.stats-search-help-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 20;
  width: min(430px, calc(100vw - 48px));
  padding: 14px 16px;
  border: 1px solid rgba(var(--tint-rgb), 0.45);
  background: rgba(var(--ink-rgb), 0.96);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.42), 0 0 26px rgba(var(--tint-rgb), 0.12);
}

.stats-search-help-panel dl {
  display: grid;
  grid-template-columns: minmax(150px, auto) minmax(0, 1fr);
  gap: 8px 14px;
  margin: 0;
}

.stats-search-help-panel dt,
.stats-search-help-panel dd {
  margin: 0;
}

.stats-search-help-panel code {
  color: var(--gold);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.82rem;
  white-space: nowrap;
}

.stats-search-help-panel dd {
  color: var(--muted);
  font-size: 0.82rem;
  line-height: 1.35;
}

.stats-game-search-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: stretch;
}

.stats-game-query-field {
  min-width: 0;
  position: relative;
}

.stats-game-query-field .site-search-input {
  padding-right: 46px;
}

.stats-game-search-row input {
  min-height: 42px;
  width: 100%;
  min-width: 0;
  border: 1px solid rgba(var(--tint-rgb), 0.35);
  border-radius: 0;
  background: rgba(0, 0, 0, 0.28);
  color: var(--white);
  padding: 0 12px;
  font: 0.95rem 'Inter', sans-serif;
  outline: none;
}

.stats-game-search-row input:focus {
  border-color: var(--cyan);
  box-shadow: 0 0 18px rgba(var(--tint-rgb), 0.12);
}

.stats-game-search-hint {
  margin: 2px 0 0;
  color: var(--muted);
  font-size: 0.8rem;
  line-height: 1.5;
}
.stats-game-search-hint code {
  color: var(--data-secondary);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
}

.stats-search-limit {
  margin: 16px 0 0;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  text-align: center;
}

.stats-empty-results {
  margin-top: 20px;
  padding: 34px 18px;
  border-top: 1px solid rgba(var(--tint-rgb), 0.28);
  border-bottom: 1px solid rgba(var(--tint-rgb), 0.18);
  background: rgba(var(--panel-rgb), 0.24);
  text-align: center;
}

.stats-empty-results .stats-search-limit {
  line-height: 1.5;
}

.stats-game-results.has-table {
  border: 1px solid rgba(var(--tint-rgb), 0.3);
  background: rgba(var(--ink-rgb), 0.82);
  box-shadow: 0 0 34px rgba(var(--tint-rgb), 0.1), inset 0 0 20px rgba(var(--tint-rgb), 0.04);
  padding: 22px;
}
.stats-game-results-header {
  padding: 0 15px;
  text-align: center;
}
.stats-game-results-subject,
.stats-game-results-qualifier {
  margin: 0;
}
.stats-game-results-qualifier {
  margin-top: 6px;
}
/* Without a table there is nothing for the rule to separate — the empty-state
   block draws its own, and two hairlines 20px apart with nothing between them
   read as a broken band. */
.stats-game-results:not(.has-table) {
  border-top: 0;
  padding-top: 0;
  /* And it lines up with the panel it answers, rather than running wider than
     the control that produced it. */
  width: min(920px, calc(100vw - 36px));
  margin-left: auto;
  margin-right: auto;
}

.study-player-card,
.profile-row,
.collection-card,
.bio-vital,
.bio-number,
.bio-quote,
.bio-section,
.bio-archive-card,
.htb-proof-card,
.htb-completion-card {
  content-visibility: auto;
  contain-intrinsic-size: auto 96px;
}

.profile-panel .profile-row,
.profile-collections .collection-card {
  content-visibility: visible;
  contain-intrinsic-size: auto;
}

.bio-section {
  contain-intrinsic-size: auto 320px;
  scroll-margin-top: 96px;
}

.view-btn {
  display: inline-block;
  padding: 6px 12px;
  border: 1px solid var(--tint);
  color: var(--chrome);
  text-decoration: none;
  font-size: 0.7rem;
  transition: all 0.3s;
  border-radius: 2px;
}
.view-btn:hover {
  background: var(--cyan);
  color: var(--void);
  box-shadow: 0 0 15px var(--cyan-glow);
}

/* ── EVENT SERIES INDEX ── */
.event-index-section {
  width: min(1100px, 100%);
  margin-left: auto;
  margin-right: auto;
}
.event-search-shell {
  margin-bottom: 28px;
  padding: 18px;
}
.event-search-shell form {
  display: flex;
}
.event-search-shell input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  background: rgba(0, 0, 0, 0.3);
  color: var(--chrome);
  font: 0.78rem 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  outline: none;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.event-search-shell input:focus {
  border-color: var(--cyan);
  box-shadow: 0 0 18px rgba(var(--tint-rgb), 0.13);
}
/* Three tracks so the heading sits centred on the page and the count keeps the
   right edge — the same shape as the era bucket headers on /players/, because
   it is the same object. As a flex row the title block was pinned left while
   its own rules made the title look centred inside it, so the label above sat
   off to one side of a heading that was visibly centred (owner, 2026-08-05:
   "titles like this should be centered"). */
.event-index-heading {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: end;
  gap: 24px;
  margin: 0 0 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(var(--tint-rgb), 0.2);
  text-align: center;
}
.event-index-heading > div {
  grid-column: 2;
}
.event-index-heading > span {
  grid-column: 3;
  justify-self: end;
}
.event-index-heading h2 {
  margin: 5px 0 0;
  color: var(--white);
  font: 1.15rem 'Orbitron', sans-serif;
  letter-spacing: 2px;
}
.event-index-heading > span {
  color: var(--muted);
  font: 0.7rem 'Share Tech Mono', monospace;
  letter-spacing: 1px;
  white-space: nowrap;
}
/* Two columns only while two columns fit, the same rule the /players/ grid
   uses: a hard `repeat(2, 1fr)` held the pair down to phone width and squeezed
   every long event name into three lines. At 1050px this still resolves to the
   two ~517px cards the desktop already had. */
.event-series-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
  gap: 16px;
}

/* One card, two columns: body and control rail. It takes the /players/ card's
   anatomy minus the portrait column — a player has a face, a series and an
   event do not, and a fixed slot holding a year instead was the whole defect
   (owner, 2026-08-05: "years dont belong in a potrait slot, there should be no
   potrait slots for these they dont have portraits"). */
.event-series-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 18px;
  padding: 18px 20px;
  color: var(--white);
  text-decoration: none;
}
.event-series-card:hover {
  border-color: rgba(var(--tint-rgb), 0.58);
  background: rgba(var(--tint-rgb), 0.055);
  transform: translateY(-2px);
}
/* A card carrying a description is tall enough that centring pushes the name
   down into the middle of the block. The body anchors to the top instead,
   while the control rail stays centred the way the /players/ rail is. */
.event-series-card:not(.event-event-card) {
  align-items: start;
}
.event-series-card:not(.event-event-card) .event-card-actions {
  align-self: center;
}
.event-card-body {
  min-width: 0;
}
.event-card-topline {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px 12px;
  color: var(--muted);
  font: 0.66rem 'Share Tech Mono', monospace;
  letter-spacing: 0.8px;
}
.event-card-topline span:first-child {
  color: var(--gold);
}

/* A series lineage, printed as a figure at the head of the figure line. This is
   where the span went when the year column was removed: an event's name already
   carries its year, but "World Chess Championships" does not carry 1886–2023,
   so the one card that would have lost information keeps it as data. Tabular so
   the spans line up down the column of cards. */
.event-span-figure {
  font-variant-numeric: tabular-nums;
}
.event-series-card h3 {
  margin: 5px 0 0;
  color: var(--cyan);
  font: 1.05rem 'Orbitron', sans-serif;
  letter-spacing: 1.5px;
  /* Long event names ("USSR Championship Semifinal — Rostov on Don 1941,
     Group 1") wrap rather than push the card wider. */
  overflow-wrap: anywhere;
}
.event-series-card p {
  margin: 7px 0 0;
  color: var(--muted);
  font: 0.92rem/1.55 'Rajdhani', sans-serif;
}
.event-card-figures {
  margin-top: 8px;
  color: var(--chrome);
  font: 0.66rem 'Share Tech Mono', monospace;
  letter-spacing: 0.8px;
}
.event-card-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.event-card-actions .study-arrow-icon {
  transition: transform 0.2s ease;
}
.event-series-card:hover .event-card-actions .study-arrow-icon {
  transform: translateX(3px);
}
.event-series-card-misc {
  border-color: rgba(var(--gold-rgb), 0.24);
}
.event-index-card {
  content-visibility: visible;
}

/* The event card is the series card at list density: it carries no
   description, so it tightens. Everything else — type, colour, marks, the
   rail — comes from the shared component, which is the point. */
.event-event-card {
  gap: 16px;
  padding: 14px 18px;
}
.event-event-card .event-search-series {
  margin-top: 0;
}
.event-search-empty {
  padding: 40px;
  color: var(--muted);
  text-align: center;
}
.event-series-header .header-name {
  overflow-wrap: anywhere;
}
.event-series-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 16px;
  color: var(--chrome);
  text-decoration: none;
}
.event-series-back:hover {
  color: var(--gold);
}

/* ── STUDY PLAYERS ── */
.study-player-section {
  max-width: 980px;
  margin-left: auto;
  margin-right: auto;
}
.study-player-search-form {
  width: min(620px, 100%);
  margin: 0 auto 28px;
}
.study-player-search-form .games-search-input {
  display: block;
  width: 100%;
  min-width: 0;
}
.player-starters {
  max-width: 980px;
  margin: 0 auto 32px;
}
.player-starters-summary {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) 20px;
  align-items: center;
  column-gap: 14px;
  padding: 10px 0;
  cursor: pointer;
  list-style: none;
  text-align: center;
}
.player-starters-summary::-webkit-details-marker {
  display: none;
}
.player-starters-summary:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 4px;
}
.player-starters-heading {
  grid-column: 2;
  display: flex;
  flex-direction: column;
  align-items: stretch;
}
.player-starters-kicker {
  display: block;
  margin-top: 4px;
}
.player-starters-heading .section-title {
  margin: 0;
}
.player-starters-heading .section-title,
.study-player-bucket-header .section-title {
  --player-section-title-gap: 12px;
  width: 100%;
  gap: var(--player-section-title-gap);
}
.player-starters-heading .section-title::before,
.player-starters-heading .section-title::after,
.study-player-bucket-header .section-title::before,
.study-player-bucket-header .section-title::after {
  content: none;
}
.player-starters-heading .section-title-label,
.study-player-bucket-header .section-title-label {
  position: relative;
  display: inline-block;
  white-space: nowrap;
}
.player-starters-heading .section-title-label > .mark,
.study-player-bucket-header .section-title-label > .mark {
  position: absolute;
  top: 50%;
  right: calc(100% + var(--player-section-title-gap));
  transform: translateY(-50%);
}
.player-starters-chevron {
  grid-column: 3;
  width: 20px;
  height: 20px;
  flex: 0 0 auto;
  transition: transform 160ms ease;
}
.player-starters[open] .player-starters-chevron {
  transform: rotate(180deg);
}
.player-starter-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 2px 28px;
  margin: 0;
  padding: 8px 0 12px;
  list-style: none;
}
.player-starter-row {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  align-items: center;
  gap: 10px;
  height: 100%;
  padding: 6px 0;
  border: 0;
  outline: 0;
  background: transparent;
  box-shadow: none;
  text-decoration: none;
}
.player-starter-row:focus-visible {
  outline: 0;
  box-shadow: none;
}
.player-starter-row:focus-visible .player-starter-portrait {
  box-shadow: 0 0 0 2px var(--cyan);
}
.player-starter-row .player-starter-portrait {
  width: 48px;
  height: 48px;
  padding: 2px;
  transition: filter 140ms ease, box-shadow 140ms ease;
}
.player-starter-row .player-starter-name {
  transition: color 140ms ease;
}
body a.player-starter-row:is(:hover, :focus-visible) .player-starter-name,
body.site-theme-charcoal a.player-starter-row:is(:hover, :focus-visible) .player-starter-name {
  color: var(--cyan);
}
.player-starter-row:is(:hover, :focus-visible) .player-starter-portrait {
  filter: brightness(1.18) contrast(1.04);
}
.player-starter-copy,
.player-starter-name,
.player-starter-reason {
  display: block;
  min-width: 0;
}
.player-starter-reason {
  margin-top: 2px;
  overflow-wrap: anywhere;
}
@media (max-width: 719px) {
  .player-starter-list {
    grid-template-columns: minmax(0, 1fr);
  }
}
.study-player-empty-state {
  padding: 40px;
  text-align: center;
}
.study-player-bucket-section {
  margin-top: 24px;
  scroll-margin-top: 64px;
}
.study-player-bucket-section:first-child {
  margin-top: 0;
}
.study-player-index-section {
  scroll-margin-top: 64px;
}
.study-player-bucket-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: end;
  gap: 14px;
  margin-bottom: 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgba(var(--tint-rgb), 0.18);
}
.study-player-bucket-header h2 {
  margin: 0;
  color: var(--gold);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.82rem;
  letter-spacing: 2px;
  text-align: center;
  grid-column: 1 / -1;
}
/* The empty outer tracks remain balanced around the full-width title. The
   count that used to occupy one side was a second printing of a number the era
   chips already show. */
.study-player-grid {
  display: grid;
  gap: 14px;
}
#event-archive .study-player-card {
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
}
.study-player-card {
  position: relative;
  display: grid;
  grid-template-columns: 82px 1fr auto;
  align-items: center;
  gap: 22px;
  padding: 20px 24px;
  color: var(--white);
  text-decoration: none;
}
.study-player-crown {
  position: absolute;
  z-index: 2;
  top: 10px;
  left: 10px;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.study-player-crown svg {
  display: block;
}
/* The card's two links. The portrait opens the biography, the text opens the
   games; neither wears an underline, because the card is the affordance. */
a.study-player-portrait,
a.study-player-info {
  text-decoration: none;
  color: inherit;
}
a.study-player-info {
  display: block;
  min-width: 0;
}

/* Framed like a small mounted portrait: border, dark matting gap, and a
   hairline around the photo itself. */
.study-player-portrait {
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  padding: 3px;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--tint);
  color: var(--chrome);
  font-size: 1.3rem;
  overflow: hidden;
  box-shadow: inset 0 0 18px rgba(var(--tint-rgb), 0.08);
}
.study-player-portrait img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center 28%;
  filter: saturate(0.92) contrast(1.08);
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.6);
}
.study-player-portrait > svg,
.player-starter-portrait > svg {
  width: 42%;
  height: 42%;
}
.study-player-name {
  color: var(--cyan);
  font-family: 'Orbitron', sans-serif;
  font-size: 1rem;
  letter-spacing: 2px;
}
.event-search-series {
  margin-top: 7px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.7rem;
  letter-spacing: 1px;
}
.event-search-series a {
  color: var(--gold);
  text-decoration: none;
}
.event-search-series a:hover {
  color: var(--cyan);
}
.study-player-bioline {
  margin-top: 5px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.6px;
}
.study-player-meta {
  margin-top: 6px;
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.82rem;
  letter-spacing: 1px;
}
/* A year range is one fact. Left to wrap it split as "1749 —" / "1795", which
   reads as two numbers rather than a span. */
.study-player-years {
  white-space: nowrap;
}
.study-player-notable-link {
  display: inline-block;
  margin-top: 8px;
  color: var(--gold);
  text-decoration: none;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  letter-spacing: 1px;
}
.study-player-notable-link:hover {
  color: var(--cyan);
}
.study-player-actions {
  display: flex;
  justify-content: flex-end;
  gap: 12px;
}
.study-player-action {
  width: 52px;
  height: 48px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(var(--tint-rgb), 0.35);
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 1.08rem;
  text-decoration: none;
  transition: all 0.2s ease;
}
.study-player-action svg {
  width: 18px;
  height: 18px;
}
.study-player-action:hover {
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.09);
  box-shadow: 0 0 14px rgba(var(--tint-rgb), 0.2);
}
.study-player-index-action {
  width: auto;
  min-width: 74px;
  padding: 0 13px;
  font-size: 0.68rem;
}
.study-player-action.active,
.bio-star-action.active {
  border-color: rgba(var(--mint-rgb), 0.5);
  color: var(--mint);
  background: rgba(var(--mint-rgb), 0.08);
}
.study-player-bookmark-form {
  display: flex;
  margin: 0;
}
.study-player-bookmark-form .study-player-action {
  cursor: pointer;
  background-color: transparent;
}
.study-player-arrow {
  font-size: 1.45rem;
}
.study-arrow-icon {
  display: block;
  flex: 0 0 auto;
}
@media (min-width: 721px) {
  .study-player-index-section {
    max-width: 1100px;
  }
  /* Two columns only when two columns actually fit. A hard `repeat(2, 1fr)`
     held the pair all the way down to 721px, where each card got a 104px text
     column: every name broke across two or three lines and the archive years
     dropped under the game count — the same failure the phone layout was just
     fixed for, at tablet width (measured: the widest figure line is 275px, and
     a 500px column leaves it 303px). Above ~1030px this resolves to the same
     two 519px cards as before, so the desktop the owner approved is untouched. */
  .study-player-index-grid {
    grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
    align-items: stretch;
  }
  .study-player-index-grid .study-player-card {
    grid-template-columns: 58px minmax(0, 1fr) auto;
    gap: 12px;
    padding: 16px;
  }
  .study-player-index-grid .study-player-portrait {
    width: 56px;
    height: 56px;
  }
  .study-player-index-grid .study-player-name {
    min-width: 0;
    font-size: 0.88rem;
    line-height: 1.25;
    letter-spacing: 1px;
    overflow-wrap: anywhere;
  }
  .study-player-index-grid .study-player-meta {
    font-size: 0.78rem;
    letter-spacing: 0.6px;
  }
  /* No ellipsis. These cards stretch to their row, so clamping the epithet to
     one line bought nothing and cost the second half of every long one
     ("THE PRIDE AND SORRO…"). Truncation is a layout failure: the card grows
     instead. */
  .study-player-index-grid .study-player-bioline {
    font-size: 0.68rem;
    overflow-wrap: anywhere;
  }
  .study-player-index-grid .study-player-actions {
    gap: 6px;
  }
  .study-player-index-grid .study-player-action {
    width: 38px;
    height: 38px;
  }
}
.annotated-book-card {
  grid-template-columns: 82px minmax(0, 1fr) auto;
}
.annotated-book-cover {
  width: 62px;
  height: 82px;
  align-self: center;
  background: rgba(0, 0, 0, 0.28);
  border-color: rgba(var(--gold-rgb), 0.58);
  color: var(--gold);
  box-shadow: inset 0 0 18px rgba(var(--gold-rgb), 0.08), 0 0 18px rgba(var(--tint-rgb), 0.08);
}
.annotated-book-cover img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center;
  filter: saturate(0.96) contrast(1.04);
}
.annotated-source-nav {
  max-width: 760px;
  margin: -12px auto 28px;
  padding: 0 20px;
  display: flex;
  justify-content: center;
}
.annotated-back-link {
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 0 15px;
  border: 1px solid rgba(var(--tint-rgb), 0.42);
  background: rgba(var(--tint-rgb), 0.06);
  color: var(--chrome);
  box-shadow: 0 0 18px rgba(var(--tint-rgb), 0.08), inset 0 0 18px rgba(var(--tint-rgb), 0.04);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  text-decoration: none;
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.annotated-back-link:hover {
  color: var(--white);
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.12);
  box-shadow: 0 0 24px rgba(var(--tint-rgb), 0.22), inset 0 0 22px rgba(var(--tint-rgb), 0.08);
}
.study-player-about-card {
  display: grid;
  grid-template-columns: 112px 1fr auto;
  align-items: center;
  gap: 24px;
  padding: 28px;
}
.study-player-about-portrait {
  width: 96px;
  height: 96px;
}

/* ── HACK THE BOX DOSSIER ── */
.htb-header { margin-bottom: 42px; }
.htb-title {
  background: linear-gradient(135deg, #ffffff 0%, #9fef00 55%, var(--cyan) 100%);
  -webkit-background-clip: text;
  background-clip: text;
}
.htb-overview-grid {
  max-width: 828px;
  margin: 0 auto 28px;
  animation: fadeUp 1s 0.2s ease both;
}
.htb-identity-card,
.htb-proof-card,
.htb-note-section {
  padding: 24px;
}
.htb-identity-row {
  display: flex;
  align-items: center;
  gap: 18px;
  margin: 10px 0 22px;
}
.htb-emblem {
  width: 74px;
  height: 74px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid rgba(159,239,0,0.45);
  background: rgba(159,239,0,0.05);
  box-shadow: 0 0 24px rgba(159,239,0,0.12);
}
.htb-emblem img {
  width: 46px;
  height: 46px;
  object-fit: contain;
}
.htb-kicker {
  font-family: 'Share Tech Mono', monospace;
  color: var(--muted);
  letter-spacing: 2px;
  text-transform: uppercase;
  font-size: 10px;
}
.htb-handle {
  font-family: 'Orbitron', monospace;
  color: #9fef00;
  font-size: clamp(1.2rem, 3vw, 1.6rem);
  font-weight: 700;
}
.htb-meta {
  color: var(--muted);
  margin-top: 4px;
}
.htb-stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 12px;
  margin-bottom: 18px;
}
.htb-stat {
  padding: 14px;
  border: 1px solid rgba(159,239,0,0.18);
  background: rgba(159,239,0,0.04);
}
.htb-stat span,
.htb-machine-grid span {
  display: block;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 10px;
  letter-spacing: 2px;
  text-transform: uppercase;
}
.htb-stat strong {
  display: block;
  margin-top: 6px;
  font-family: 'Orbitron', monospace;
  font-size: 1.35rem;
  color: #9fef00;
}
.htb-machine-row {
  display: flex;
  align-items: start;
  justify-content: space-between;
  gap: 16px;
}
.htb-proof-pill {
  padding: 7px 10px;
  color: #9fef00;
  border: 1px solid rgba(159,239,0,0.24);
  font-family: 'Share Tech Mono', monospace;
  font-size: 11px;
  letter-spacing: 2px;
}
.htb-machine-name {
  margin-top: 10px;
  font-family: 'Orbitron', monospace;
  font-size: clamp(1.35rem, 3vw, 1.8rem);
  font-weight: 700;
}
.htb-machine-status {
  color: #9fef00;
  letter-spacing: 5px;
  font-family: 'Share Tech Mono', monospace;
  margin: 4px 0 18px;
}
.htb-machine-grid {
  display: grid;
  gap: 12px;
  margin-bottom: 20px;
}
.htb-machine-grid-compact {
  grid-template-columns: repeat(2, 1fr);
  margin-bottom: 16px;
}
.htb-proof-card-compact {
  align-self: start;
}
.htb-machine-grid strong {
  display: block;
  margin-top: 4px;
  font-family: 'Orbitron', monospace;
  color: var(--white);
}
.htb-inline-link {
  color: #9fef00;
  text-decoration: none;
  font-family: 'Share Tech Mono', monospace;
  letter-spacing: 2px;
  font-size: 11px;
}
.htb-inline-link:hover { color: var(--white); }
.htb-card-action {
  text-align: right;
}
.htb-badges-section {
  margin-bottom: 28px;
  animation: fadeUp 1s 0.35s ease both;
}
.htb-completions-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
}
.htb-completion-card {
  padding: 20px;
}
.htb-empty-card {
  padding: 20px;
  color: var(--muted);
}
@media(max-width:760px) {
  .htb-completions-grid { grid-template-columns: 1fr; }
  .htb-stat-grid { grid-template-columns: repeat(2, 1fr); }
  .htb-machine-grid-compact { grid-template-columns: 1fr; }
}

/* ── STUDY BIOGRAPHY ── */
.bio {
  position: relative;
  max-width: 860px;
  margin: 0 auto;
  animation: fadeUp 1s 0.2s ease both;
}

.bio-top-actions {
  position: absolute;
  top: 0;
  right: 0;
  z-index: 2;
  display: flex;
  gap: 8px;
}
.event-about > .bio-index-back {
  position: absolute;
  top: 0;
  left: 0;
  right: auto;
  z-index: 2;
}
.bio-star-form {
  margin: 0;
}
.bio-index-back,
.bio-star-action {
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border: 1px solid rgba(var(--tint-rgb), 0.42);
  background: rgba(var(--ink-rgb), 0.72);
  color: var(--chrome);
  font-size: 1.3rem;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  box-shadow: inset 0 0 18px rgba(var(--tint-rgb), 0.04);
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease,
              box-shadow 0.25s ease, transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.bio-star-action svg {
  width: 18px;
  height: 18px;
}
.bio-index-back:hover,
.bio-star-action:hover {
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.09);
  box-shadow: 0 0 16px rgba(var(--tint-rgb), 0.2), inset 0 0 18px rgba(var(--tint-rgb), 0.06);
}
.bio-index-back:active,
.bio-star-action:active {
  transform: scale(0.96);
}

.bio-hero {
  display: grid;
  grid-template-columns: 168px 1fr;
  gap: 32px;
  align-items: center;
  margin-bottom: 44px;
}
.bio-hero-text {
  min-width: 0;
  padding-right: 112px;
}
.bio-hero-portrait {
  width: 168px;
  height: 168px;
  display: grid;
  place-items: center;
  border: 1px solid var(--tint);
  color: var(--chrome);
  font-size: 2.4rem;
  overflow: hidden;
  box-shadow: inset 0 0 26px rgba(var(--tint-rgb), 0.1), 0 0 26px rgba(var(--tint-rgb), 0.08);
}
.bio-hero-portrait img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center 28%;
  filter: saturate(0.95) contrast(1.06);
}
.bio-hero-portrait > svg {
  width: 42%;
  height: 42%;
}
.bio-epithet {
  color: var(--gold);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.82rem;
  letter-spacing: 5px;
  text-shadow: 0 0 14px var(--gold-glow);
  margin-bottom: 10px;
}
.event-hero-tagline {
  margin: 10px 0 0;
}
.bio-name {
  font-family: 'Orbitron', sans-serif;
  font-size: 2.5rem;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: 1px;
  background: linear-gradient(135deg, #ffffff 0%, var(--cyan) 55%, var(--gold) 110%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.bio-lifespan {
  margin-top: 8px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.86rem;
  letter-spacing: 3px;
}
.bio-crown {
  margin-top: 14px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.84rem;
  letter-spacing: 1.5px;
}
.bio-hero-actions {
  margin-top: 22px;
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: 12px;
}
.bio-btn {
  display: inline-flex;
  align-items: center;
  box-sizing: border-box;
  min-height: 44px;
  gap: 8px;
  padding: 11px 18px;
  border: 1px solid rgba(var(--tint-rgb), 0.35);
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.76rem;
  letter-spacing: 2px;
  text-decoration: none;
  transition: all 0.2s ease;
}
.bio-btn:hover {
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.09);
  box-shadow: 0 0 16px rgba(var(--tint-rgb), 0.2);
}
.bio-btn-primary {
  border-color: var(--gold);
  color: var(--gold);
}
.bio-btn-primary:hover {
  background: rgba(var(--gold-rgb), 0.08);
  box-shadow: 0 0 16px var(--gold-glow);
}

.bio-lede {
  font-size: 1.22rem;
  line-height: 1.7;
  color: var(--white);
  font-weight: 300;
  border-left: 2px solid var(--gold);
  padding-left: 22px;
  margin-bottom: 48px;
}
.bio-lede em { color: var(--gold); font-style: italic; }

/* auto-fit + a capped track, not `repeat(N, 1fr)`. A fixed track count leaves
   the leftovers of the last row packed against the left edge with a phantom
   empty cell beside them, which reads as a missing tile rather than as a short
   row (owner, 2026-08-05: "when there is 3 like that, it should be centered,
   and not look like one is missing"). auto-fit collapses the unused tracks and
   `justify-content` centres what remains, so a full row is unchanged and a
   short row is centred. The cap keeps a two-tile row from stretching into two
   billboards. */
.bio-vitals {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 275px));
  justify-content: center;
  gap: 14px;
  margin-bottom: 52px;
}
.bio-vital {
  padding: 16px 18px;
}
.bio-vital-label {
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.66rem;
  letter-spacing: 2px;
  text-transform: uppercase;
}
.bio-vital-value {
  margin-top: 7px;
  color: var(--white);
  font-family: 'Rajdhani', sans-serif;
  font-size: 0.98rem;
  font-weight: 600;
  letter-spacing: 0.3px;
}

.bio-section {
  margin-bottom: 44px;
}
.bio-section-heading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-family: 'Orbitron', sans-serif;
  font-size: 1.18rem;
  font-weight: 600;
  letter-spacing: 1px;
  color: var(--chrome);
  margin-bottom: 20px;
  text-align: center;
}
body.api-docs-page .bio-section-heading {
  justify-content: flex-start;
  text-align: left;
}
.bio-section-mark {
  color: var(--gold);
  font-size: 0.9rem;
}
.bio-para {
  font-size: 1.05rem;
  line-height: 1.78;
  color: rgba(var(--white-rgb), 0.82);
  margin-bottom: 16px;
}
.bio-para:last-child { margin-bottom: 0; }
.bio-para em { color: var(--cyan); font-style: italic; }

/* Same short-row rule as `.bio-vitals` above. */
.bio-numbers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 200px));
  justify-content: center;
  gap: 14px;
  margin-bottom: 52px;
}
.bio-number {
  padding: 22px 16px;
  text-align: center;
}
.bio-number-value {
  font-family: 'Orbitron', sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--gold);
  text-shadow: 0 0 16px var(--gold-glow);
  line-height: 1.1;
}
.bio-number-label {
  margin-top: 10px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.66rem;
  letter-spacing: 1px;
  line-height: 1.4;
}

.bio-quotes {
  display: grid;
  gap: 16px;
  margin-bottom: 52px;
}
.bio-quote {
  padding: 26px 28px;
}
.bio-quote blockquote {
  font-size: 1.12rem;
  line-height: 1.6;
  font-weight: 300;
  font-style: italic;
  color: var(--white);
}
.bio-quote figcaption {
  margin-top: 14px;
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.76rem;
  letter-spacing: 2px;
}
.bio-quote-by {
  border-left: 2px solid var(--gold);
}
.bio-quote-by blockquote { color: var(--gold); }
.bio-quote-by figcaption { color: var(--gold); }

.bio-archive {
  margin-bottom: 52px;
}
.bio-archive-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
}
.notable-game-list {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}
.notable-game-item {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
}
.notable-game-row {
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) max-content;
  grid-template-areas:
    "date pairing result"
    ". meta meta"
    ". annotation annotation";
  column-gap: 18px;
  row-gap: 7px;
  position: relative;
  width: 100%;
  box-sizing: border-box;
  padding: 20px 16px;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
  transition: background-color 160ms ease;
}
.notable-game-item.notable-game-row:last-child {
  border-bottom: 0;
}
.notable-game-row:is(:hover, :focus-within) {
  background: rgba(var(--tint-rgb), 0.03);
}
.notable-game-row .notable-game-pairing .entity-name,
body.site-theme-charcoal .notable-game-row .notable-game-pairing .entity-name {
  color: var(--cyan);
}
.notable-game-primary-link {
  position: absolute;
  inset: 0;
  z-index: 1;
}
.notable-game-primary-link:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: -2px;
}
.notable-game-row > span {
  position: relative;
  z-index: 2;
  pointer-events: none;
}
.notable-game-row:is(:hover, :focus-within) .notable-game-pairing .entity-name,
body.site-theme-charcoal .notable-game-row:is(:hover, :focus-within) .notable-game-pairing .entity-name {
  color: var(--white);
}
.notable-game-pairing {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
}
.notable-game-pairing {
  grid-area: pairing;
  gap: 0 8px;
}
.notable-game-pairing .entity-name {
  white-space: nowrap;
}
.notable-game-date {
  grid-area: date;
  align-self: baseline;
}
.notable-game-result {
  grid-area: result;
  align-self: baseline;
  min-width: 3ch;
  text-align: center;
}
.notable-game-meta {
  grid-area: meta;
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr) minmax(0, 1fr);
  align-items: baseline;
  gap: 8px 16px;
  min-width: 0;
}
.notable-game-move-field,
.notable-game-opening,
.notable-game-event {
  min-width: 0;
  overflow-wrap: anywhere;
}
.notable-game-moves-label {
  color: var(--muted);
}
.notable-game-row .notable-game-meta .notable-game-opening,
body.site-theme-charcoal .notable-game-row .notable-game-meta .notable-game-opening {
  color: var(--gold);
}
.notable-game-event-link {
  z-index: 3;
  min-height: 0;
  pointer-events: auto;
}
.notable-game-row .notable-game-meta a.notable-game-event-link,
body.site-theme-charcoal .notable-game-row .notable-game-meta a.notable-game-event-link {
  color: var(--cyan);
}
.notable-game-row .notable-game-meta a.notable-game-event-link:is(:hover, :focus-visible),
body.site-theme-charcoal .notable-game-row .notable-game-meta a.notable-game-event-link:is(:hover, :focus-visible) {
  color: var(--white);
}
.notable-game-annotation {
  grid-area: annotation;
  display: block;
  margin: 7px 0 0;
}
@media (max-width: 640px) {
  .notable-game-row {
    grid-template-columns: minmax(0, 1fr) max-content;
    grid-template-areas:
      "date result"
      "pairing pairing"
      "meta meta"
      "annotation annotation";
    padding-inline: 10px;
  }
  .notable-game-meta {
    grid-template-columns: minmax(0, 1fr);
    gap: 5px;
  }
}
/* A column so the arrow can be pushed to the bottom of the card. The cards in
   a row are already equal height, but the arrow followed the description, so a
   two-line description dropped its arrow a line below its neighbours' and the
   row read as three unaligned marks. */
.bio-archive-card {
  display: flex;
  flex-direction: column;
  padding: 20px;
  text-decoration: none;
  position: relative;
}
.bio-archive-title {
  color: var(--chrome);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.92rem;
  letter-spacing: 0.5px;
  line-height: 1.3;
}
.bio-archive-sub {
  margin-top: 8px;
  color: var(--muted);
  font-family: 'Rajdhani', sans-serif;
  font-size: 0.92rem;
  letter-spacing: 0.3px;
}
.bio-archive-arrow {
  margin-top: auto;
  padding-top: 14px;
  color: var(--gold);
  font-size: 1.2rem;
  line-height: 1;
}

.bio-cta {
  text-align: center;
  margin: 8px 0 48px;
}

.bio-sources {
  border-top: 1px solid var(--border);
  padding-top: 24px;
}
.bio-sources-label {
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 3px;
  margin-bottom: 12px;
}
.bio-sources ul {
  list-style: none;
  display: grid;
  gap: 8px;
}
.bio-sources a {
  color: rgba(var(--cyan-rgb), 0.7);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  text-decoration: none;
  letter-spacing: 0.5px;
}
.bio-sources a:hover { color: var(--cyan); text-decoration: underline; }

/* ── EVENT ABOUT: CROSS TABLE / STANDINGS ── */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link.visually-hidden.site-nav-link:not(:focus-visible) {
  width: 1px;
  height: 1px;
  min-width: 0;
  min-height: 0;
  padding: 0;
  margin: -1px;
  border: 0;
  background: transparent;
  box-shadow: none;
  text-shadow: none;
}

.skip-link:focus-visible {
  position: fixed;
  top: 18px;
  left: 18px;
  z-index: 1002;
  width: auto;
  height: auto;
  margin: 0;
  overflow: visible;
  clip: auto;
  white-space: nowrap;
}

#chessground-node[tabindex="0"]:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: 3px;
}

body.oe-mobile .oe-sheet-grip {
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  color: inherit;
}

.event-hero-media img {
  object-position: center 42%;
}
/* Without a real photograph there is no portrait object to frame. Give the
   event identity the full hero width and reserve equal space on both sides so
   the title remains optically centred beside the index control. */
.event-hero--text-only {
  grid-template-columns: minmax(0, 1fr);
}
.event-hero--text-only .bio-hero-text {
  padding: 0 64px;
  text-align: center;
}
.event-hero--text-only .bio-hero-actions {
  justify-content: center;
}
.event-hero-credit {
  margin: -28px 0 40px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.74rem;
  line-height: 1.5;
  letter-spacing: 0.3px;
}
.event-hero-credit .event-photo-credit { color: rgba(var(--white-rgb), 0.38); }

.event-result-banner {
  display: flex;
  align-items: baseline;
  gap: 18px;
  flex-wrap: wrap;
  padding: 18px 22px;
  margin-bottom: 18px;
  border-left: 2px solid var(--gold);
}
.event-result-score {
  font-family: 'Orbitron', sans-serif;
  font-size: 1.9rem;
  font-weight: 700;
  color: var(--gold);
  text-shadow: 0 0 16px var(--gold-glow);
  letter-spacing: 1px;
}
.event-result-detail {
  color: var(--data-secondary);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.82rem;
  letter-spacing: 1px;
}

.event-crosstable { margin-bottom: 52px; }
.event-subheading {
  margin: 34px 0 16px;
  color: var(--chrome);
  font-family: 'Orbitron', sans-serif;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 1px;
}
.event-table-note {
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.76rem;
  line-height: 1.6;
  margin-bottom: 16px;
}
.event-table-legend {
  margin-top: 12px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 0.5px;
}
.event-table-legend .event-cell-win,
.event-table-legend .event-cell-draw,
.event-table-legend .event-cell-loss {
  padding: 0 4px;
  font-weight: 700;
}

.event-grid-scroll {
  overflow-x: auto;
  border: 1px solid var(--border);
  background: rgba(var(--tint-rgb), 0.02);
}
.event-grid-scroll + .event-grid-scroll { margin-top: 12px; }

.event-match-grid,
.event-standings,
.event-grid-table {
  border-collapse: collapse;
  width: 100%;
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.82rem;
  color: var(--white);
}
.event-match-grid th,
.event-match-grid td,
.event-grid-table th,
.event-grid-table td {
  text-align: center;
  padding: 7px 9px;
  border: 1px solid var(--border);
  white-space: nowrap;
}
.event-match-grid thead th,
.event-grid-table thead th {
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 0.5px;
}
.event-match-grid thead a { color: var(--chrome); text-decoration: none; }
.event-match-grid thead a:hover { text-decoration: underline; }
.event-grid-player,
.event-grid-rowname {
  text-align: left;
  color: var(--white);
  font-family: 'Rajdhani', sans-serif;
  font-weight: 600;
  letter-spacing: 0.3px;
}
.event-player-link {
  color: inherit;
  text-decoration: none;
}
.event-player-link:hover {
  color: var(--cyan);
  text-decoration: underline;
}
.game-event-link {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  color: var(--cyan);
  text-decoration: none;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.game-event-link:hover,
.game-event-link:focus-visible {
  color: var(--white);
  text-decoration: underline;
}
.game-event-link:focus-visible {
  outline: 1px solid var(--cyan);
  outline-offset: 3px;
}
.event-grid-total {
  color: var(--gold);
  font-weight: 700;
  background: rgba(var(--gold-rgb), 0.05);
}
.event-cell-win { color: var(--gold); }
.event-cell-draw { color: var(--data-secondary); }
.event-cell-loss { color: var(--muted); }
.event-cell-none { color: var(--muted); }

/* Standings table */
.event-standings th {
  text-align: left;
  color: var(--muted);
  font-weight: 400;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-size: 0.68rem;
}
.event-standings td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  border-left: 0;
  border-right: 0;
  border-top: 0;
  white-space: nowrap;
}
.event-standings tbody tr:hover { background: rgba(var(--tint-rgb), 0.04); }
.event-standings-rank {
  color: var(--gold);
  font-weight: 700;
  width: 3.4em;
}
.event-standings-name {
  text-align: left;
  color: var(--white);
  font-family: 'Rajdhani', sans-serif;
  font-size: 0.98rem;
  font-weight: 600;
  letter-spacing: 0.3px;
  width: 100%;
}
.event-standings-score { color: var(--gold); font-weight: 700; }
.event-standings-outof { color: var(--muted); font-weight: 400; }
.event-standings-record { color: var(--data-secondary); }
.event-standings-link a { color: rgba(var(--cyan-rgb), 0.7); text-decoration: none; }
.event-standings-link a:hover { color: var(--cyan); text-decoration: underline; }

/* N×N cross-table grid */
.event-grid-namehead { text-align: left; }
.event-grid-rownum { color: var(--gold); font-weight: 700; }
.event-grid-self { color: rgba(var(--white-rgb), 0.25); background: rgba(var(--tint-rgb), 0.05); }
.event-grid-cell { color: var(--data-secondary); letter-spacing: 1px; }
.event-grid-empty { color: var(--muted); }
.event-grid-lost { color: rgba(var(--white-rgb), 0.28); background: rgba(var(--danger-rgb), 0.06); }

/* Incomplete-archive note (events whose source preserves only some games) */
.event-preservation-note {
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.5;
  border-left: 2px solid rgba(var(--danger-rgb), 0.4);
  padding: 0.35rem 0 0.35rem 0.9rem;
  margin: 0.75rem 0 1.25rem;
}
.event-grid-lost-key { color: rgba(var(--white-rgb), 0.45); font-weight: 700; }

/* Photographs */
.event-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
  margin-bottom: 52px;
}
.event-photo { padding: 0; overflow: hidden; }
.event-photo img {
  width: 100%;
  display: block;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  filter: saturate(0.96) contrast(1.04);
}
.event-photo figcaption {
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.event-photo-caption {
  color: var(--white);
  font-family: 'Rajdhani', sans-serif;
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.35;
}
.event-photo-credit {
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.66rem;
  letter-spacing: 0.5px;
}

/* Restore the independently anchored desktop placement that shipped when Apps
   and Donate became top-level destinations (05071eff, 2026-08-23). The wrapper
   remains only as the common positioning root; it does not stretch either bar
   or redistribute the empty space between them. */
@media(min-width: 1280px) {
  html[data-device="desktop"] .header-nav-row {
    display: block;
  }
  html[data-device="desktop"] .header-nav-row > .site-nav {
    position: absolute;
    top: 0;
    left: 0;
    width: max-content;
    min-width: auto;
    max-width: none;
    flex: none;
  }
}

/* Desktop never becomes the mobile drawer. Below the old reference bar's fit
   boundary, reduce every control uniformly and keep the intact row available
   through horizontal scrolling. */
@media(max-width: 1279px) {
  html[data-device="desktop"] .header-nav-row {
    --header-nav-min-gap: 8px;
    align-items: flex-start;
  }
  html[data-device="desktop"] .header-nav-row > .site-nav {
    flex: 1 1 auto;
    gap: 4px;
  }
  html[data-device="desktop"] .site-nav-link {
    min-height: 30px;
    padding-inline: 9px;
    font-size: 0.68rem;
    letter-spacing: 1.2px;
  }
  html[data-device="desktop"] .site-nav-link::before {
    margin-right: 6px;
  }
}

@media(max-width: 1100px) {
  html[data-device="desktop"] .header-nav-row {
    left: 0;
    right: auto;
    width: max-content;
    min-width: 100%;
    padding: 0 16px;
    box-sizing: border-box;
    justify-content: space-between;
  }
  html[data-device="desktop"] .header-nav-row > .account-nav {
    flex: 0 0 max-content;
    max-width: none;
  }
  html[data-device="desktop"] .header-nav-row > .site-nav {
    flex: 0 0 max-content;
    width: max-content;
  }
}

html[data-device="mobile"] .header-nav-row {
  position: static;
  display: block;
}
html[data-device="mobile"] .header-nav-row > .account-nav {
  position: absolute;
  top: 12px;
  right: 18px;
  left: auto;
  justify-content: end;
  max-width: calc(100vw - 80px);
}
html[data-device="mobile"] .site-nav {
  position: fixed;
  top: 0;
  left: 0;
  right: auto;
  bottom: 0;
  z-index: 1004;
  width: min(82vw, 360px);
  padding: 72px 18px 24px;
  align-items: stretch;
  justify-content: start;
  flex-direction: column;
  gap: 10px;
  background: rgba(var(--ink-rgb), 0.98);
  border-right: 1px solid rgba(var(--tint-rgb), 0.34);
  box-shadow: 18px 0 45px rgba(0, 0, 0, 0.45), 0 0 28px rgba(var(--tint-rgb), 0.14);
  overflow-y: auto;
  transform: translateX(-104%);
  transition: none;
}
html[data-device="mobile"] body.mobile-nav-open .site-nav {
  transform: translateX(0);
}
html[data-device="mobile"] body.mobile-nav-open {
  overflow: hidden;
}
html[data-device="mobile"] body.mobile-nav-open::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 1000;
  background: rgba(0, 0, 0, 0.52);
}
html[data-device="mobile"] .mobile-nav-toggle {
  position: absolute;
  top: 12px;
  left: 16px;
  z-index: 1003;
  width: 44px;
  height: 38px;
  display: grid;
  place-content: center;
  gap: 5px;
  border: 1px solid rgba(var(--tint-rgb), 0.38);
  background: rgba(var(--void-rgb), 0.82);
  color: var(--chrome);
}
html[data-device="mobile"] .mobile-nav-toggle span {
  display: block;
  width: 23px;
  height: 2px;
  background: currentColor;
  box-shadow: 0 0 8px rgba(var(--tint-rgb), 0.45);
}
html[data-device="mobile"] .mobile-nav-close {
  position: absolute;
  top: 14px;
  left: 18px;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  color: var(--muted);
  font-size: 2.2rem;
  line-height: 1;
  cursor: pointer;
}
html[data-device="mobile"] .mobile-nav-close svg {
  width: 24px;
  height: 24px;
}
html[data-device="mobile"] .site-nav-link {
  width: 100%;
  min-height: 42px;
  justify-content: start;
  padding: 0 12px;
  font-size: var(--site-nav-drawer-label-size);
  letter-spacing: 1.4px;
}
html[data-device="mobile"] .site-nav-dropdown::after,
html[data-device="mobile"] .site-nav-dropdown:hover::after,
html[data-device="mobile"] .site-nav-dropdown:focus-within::after {
  display: none;
}
html[data-device="mobile"] .site-nav-dropdown:hover .site-nav-menu,
html[data-device="mobile"] .site-nav-dropdown:focus-within .site-nav-menu {
  display: none;
}
html[data-device="mobile"] .site-nav-menu {
  position: static;
  width: 100%;
  min-width: 0;
  margin-top: 6px;
  display: none;
  transform: none;
  background: rgba(0, 0, 0, 0.18);
  box-shadow: none;
}
html[data-device="mobile"] .site-nav-menu-item {
  min-height: 44px;
}
html[data-device="mobile"] .site-nav-dropdown.is-open .site-nav-menu,
html[data-device="mobile"] .site-nav-dropdown.is-open:hover .site-nav-menu,
html[data-device="mobile"] .site-nav-dropdown.is-open:focus-within .site-nav-menu {
  display: flex;
}

/* ── MOBILE LAYOUT ── */
@media(max-width: 720px) {
  body {
    cursor: auto;
  }

  .hero-explore {
    width: min(100%, 420px);
    padding: 0 16px;
    box-sizing: border-box;
  }
  .hero-spacer {
    margin: 16px 0 24px;
    height: 48px;
  }
  .hero-secondary-links {
    grid-template-columns: 1fr;
  }
  .home-daily {
    width: min(100%, 420px);
  }
  .stats-panel {
    padding: 16px;
  }
  .stats-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .stats-insight-columns {
    grid-template-columns: 1fr;
  }
  body.stats-page:not(.stats-game-search-page) .stats-panel {
    width: 100%;
    box-sizing: border-box;
    padding: 14px;
  }
  body.stats-page:not(.stats-game-search-page) .stats-result,
  body.stats-page:not(.stats-game-search-page) .stats-result-heading,
  body.stats-page:not(.stats-game-search-page) .stats-grid div,
  body.stats-page:not(.stats-game-search-page) .stats-insight-column {
    min-width: 0;
  }
  body.stats-page:not(.stats-game-search-page) .stats-result-heading h2 {
    overflow-wrap: anywhere;
  }
  body.stats-page:not(.stats-game-search-page) .stats-grid {
    gap: 6px;
  }
  body.stats-page:not(.stats-game-search-page) .stats-grid div {
    min-height: 46px;
    gap: 1px;
    padding: 6px 7px;
  }
  body.stats-page:not(.stats-game-search-page) .stats-grid span {
    font-size: 0.58rem;
    letter-spacing: 0.6px;
  }
  body.stats-page:not(.stats-game-search-page) .stats-grid strong {
    font-size: 1.05rem;
  }
  body.stats-page:not(.stats-game-search-page) .stats-insights {
    margin-top: 18px;
    padding-top: 16px;
  }

  /* Phones only. The shell drops its side gutter so panels, tables and cards
     reach the true screen edge — owner: "355 of 375 ... should be 375 of 375".
     Desktop keeps its centred column; this change was scoped to mobile. */
  .page {
    width: 100%;
    max-width: none;
    padding: 138px 0 48px;
  }
  /* Bare-text children would otherwise start at x = 0. They keep the 14px the
     shell used to give them; panels are excluded on purpose, because their own
     border is what should touch the edge. */
  .page > .header,
  .page > .hero,
  .page > p,
  .page > h1,
  .page > h2 {
    padding-left: 14px;
    padding-right: 14px;
  }
  /* The stats family and the games results card each wrote the same inset a
     second time, so taking it off the shell alone leaves them short. */
  .stats-header,
  .stats-panel,
  .stats-game-search-page #games-results-card.has-table,
  .games-listing-page #games-results-card {
    width: 100%;
    margin-left: 0;
    transform: none;
  }
  .stats-game-results.has-table {
    padding: 22px 0;
  }
  .stats-game-results-header {
    padding: 0 10px;
  }
  .stats-game-results.has-table .games-table-container {
    width: calc(100% + 2px);
    margin-left: -1px;
    margin-right: -1px;
  }
  .games-listing-page #games-results-card:hover {
    transform: none;
  }

  .profile-grid,
  .collection-grid {
    grid-template-columns: 1fr;
  }

  .profile-wide-panel {
    grid-column: auto;
  }

  .profile-panel-heading,
  .bookmark-toolbar {
    grid-template-columns: 1fr;
  }

  .profile-import-action,
  .profile-secondary-action,
  .profile-manage-link {
    width: 100%;
  }

  .collection-heading {
    grid-template-columns: 1fr;
  }

  .collection-create,
  .collection-create-form {
    width: 100%;
  }

  .collection-create {
    justify-self: stretch;
  }

  .collection-create-toggle {
    margin-left: auto;
  }

  .collection-create-form {
    position: static;
    margin-top: 10px;
  }

  .collection-form {
    grid-template-columns: 1fr;
  }

  /* Inert. account.css loads after this sheet and sets the same properties at
     the same specificity, so these three never take effect — measured at
     390px: the options are `display: flex`, the actions row is two content
     tracks, the label is 123px. Edit the live rules in account.css instead. */
  .imported-game-actions {
    grid-template-columns: 1fr;
  }

  .imported-game-source-options {
    display: grid;
    grid-template-columns: 1fr;
  }

  .imported-game-source-options label {
    width: 100%;
  }

  .bookmark-remove-form button {
    min-height: 42px;
  }

  .corner {
    width: 34px;
    height: 34px;
  }
  .corner::before { height: 18px; }
  .corner::after { width: 18px; }
  .corner-tl { top: 10px; left: 10px; }
  .corner-tr { top: 10px; right: 10px; }
  .corner-bl { bottom: 10px; left: 10px; }
  .corner-br { bottom: 10px; right: 10px; }

  .header {
    margin-bottom: 38px;
  }
  .header-label,
  .header-sub {
    letter-spacing: 3px;
  }
  .header-name {
    font-size: 2.4rem;
    letter-spacing: 0;
    overflow-wrap: anywhere;
  }
  .header-divider {
    width: 150px;
    margin: 22px auto;
  }
  .header-tagline {
    line-height: 1.45;
  }

  .data-feed {
    margin-bottom: 30px;
  }

  .ratings-section,
  .profiles-section,
  .socials-section,
  .htb-badges-section {
    margin-bottom: 38px;
  }
  .event-search-shell {
    margin-bottom: 22px;
    padding: 12px;
  }
  .event-search-shell input {
    min-height: 44px;
    padding: 10px;
    font-size: 0.7rem;
    letter-spacing: 0.45px;
  }
  .event-index-heading {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    align-items: center;
    gap: 12px;
  }
  .event-index-heading > div,
  .event-index-heading > span {
    grid-column: 1;
    justify-self: center;
  }
  .event-index-heading h2 {
    font-size: 0.96rem;
    letter-spacing: 1.5px;
  }
  .event-series-grid {
    grid-template-columns: 1fr;
    gap: 12px;
  }
  /* Phone shows what desktop shows, scaled — plaque, body and rail stay in
     their three columns rather than restacking into a different card. */
  .event-series-card,
  .event-event-card {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 12px;
    padding: 14px;
  }
  .event-series-card h3 {
    font-size: 0.92rem;
    line-height: 1.3;
  }
  .event-series-card p {
    font-size: 0.88rem;
  }
  .event-card-topline,
  .event-card-figures {
    gap: 2px 10px;
    font-size: 0.61rem;
    letter-spacing: 0.35px;
  }
  .event-card-topline span,
  .event-card-figures span {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  .event-series-header .header-name {
    font-size: 1.55rem;
  }
  .ratings-grid,
  .profiles-grid,
  .socials-grid,
  .htb-completions-grid {
    grid-template-columns: 1fr;
  }

  .rating-card {
    padding: 22px 18px;
  }
  .rating-value {
    font-size: 2.35rem;
    letter-spacing: 0;
  }
  .profile-link,
  .social-link {
    padding: 15px 16px;
    gap: 12px;
  }
  .profile-handle,
  .social-name,
  .social-handle {
    overflow-wrap: anywhere;
  }

  .games-result-filters {
    gap: 8px;
    margin-bottom: 20px;
  }
  .games-filter-btn {
    flex: 1 1 96px;
    padding: 10px 8px;
    font-size: 0.74rem;
    letter-spacing: 1px;
    text-align: center;
  }
  #games-search-input {
    width: 100%;
  }
  /* Anchor the popup to the field on phones; the narrow help target's right
     edge leaves too little room for the examples on its left. */
  .stats-search-help {
    position: static;
    transform: none;
  }
  .stats-search-help summary {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
  }
  .stats-search-help-panel {
    top: calc(100% + 8px);
    left: 0;
    right: auto;
    width: min(320px, calc(100vw - 70px));
  }
  .stats-search-help-panel dl {
    grid-template-columns: 1fr;
    gap: 5px;
  }
  .stats-search-help-panel dd {
    margin-bottom: 8px;
  }
  .study-search-modes {
    margin-bottom: 10px;
  }
  /* The six-column table keeps its sideways-scrolling window on phones. It was
     restacked into a card per game in 00ce207d, and the owner's verdict on the
     result was that the list "no longer works" and had been "200% better"
     before it was touched (2026-08-05). Reverted to the scrolling table; the
     phone layout of this list is B3's to rebuild, not a retouch's to improvise. */
  .games-table {
    min-width: 680px;
    font-size: 0.78rem;
  }
  .games-table th,
  .games-table td {
    padding: 12px 10px;
  }
  .games-table .game-event-link {
    min-height: 44px;
    margin: -8px -4px;
    padding: 0 4px;
  }
  .games-pagination {
    grid-template-columns: 1fr;
    text-align: center;
  }
  .games-page-side,
  .games-page-side.right {
    justify-content: center;
  }
  .study-player-bucket-header {
    grid-template-columns: 1fr;
    justify-items: center;
    gap: 4px;
    text-align: center;
  }
  .study-player-bucket-header h2 {
    grid-column: 1;
    justify-self: center;
  }
  .study-player-card {
    grid-template-columns: 58px 1fr;
    padding: 16px;
  }
  .study-player-portrait {
    width: 52px;
    height: 52px;
  }
  .annotated-book-card {
    grid-template-columns: 64px 1fr;
  }
  .annotated-book-cover {
    width: 52px;
    height: 72px;
  }
  .study-player-actions {
    grid-column: 1 / -1;
    justify-content: flex-start;
  }
  #event-archive .study-player-actions {
    grid-column: auto;
    justify-content: flex-end;
  }
  .study-player-action {
    width: 54px;
    height: 44px;
  }
  .study-player-index-action {
    width: auto;
    min-width: 82px;
  }
  /* One card per row on a phone. Two columns left a 102px text column inside a
     196px card: names broke across two lines, every epithet ellipsised, the
     figure line ran to three, and the card ended up taller than it was wide
     with nothing in it readable. Full width gives the text column roughly
     300px, which fits the name, the epithet, and the figure line each on its
     own line — and the type can go back up to a legible size instead of the
     0.6rem it was shrunk to in order to survive the narrow track. */
  #player-archive .study-player-index-grid {
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }
  /* One compact row: portrait, the three text lines, and the bookmark star.
     The "i" and "→" controls are hidden here — with a portrait and three
     buttons the text column came to under 190px, which is narrower than the
     names it had to hold. The portrait and the text are links in their own
     right, so nothing is lost: the face opens the biography and the text opens
     the games (owner, 2026-08-05). */
  #player-archive .study-player-action-about,
  #player-archive .study-player-action-games {
    display: none;
  }
  #player-archive .study-player-card {
    position: relative;
    grid-template-columns: 76px minmax(0, 1fr);
    grid-template-rows: auto;
    align-items: center;
    gap: 14px;
    min-width: 0;
    padding: 14px;
  }
  #player-archive .study-player-info {
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
  }
  #player-archive .study-player-portrait {
    grid-column: 1;
    grid-row: 1;
    width: 76px;
    height: 76px;
    align-self: center;
  }
  /* No type here. The name, the epithet and the figure line are roles, and a
     surface that restates their size or tracking is the layered-CSS bug this
     pass exists to remove — it also silently reintroduced the old micro-type
     voice on phones (owner, 2026-08-05: "they all went back to the wrong color
     and fonts"). Only spacing and wrapping, which the surface does own. */
  #player-archive .study-player-bioline,
  #player-archive .study-player-meta {
    margin-top: 4px;
  }
  #player-archive .study-player-bioline {
    overflow-wrap: anywhere;
  }
  /* "CURATED" is the one word on this line that carries no information here —
     the whole page is the curated archive — and it is the difference between
     the years fitting beside the count and dropping below it. Measured at
     390px: the info column is 264px, the widest figure line is 275px with the
     word and 200px without (owner, 2026-08-05: "the dates shouldnt be on a new
     line as they are right now"). */
  #player-archive .figure-unit-qualifier {
    display: none;
  }
  /* The star leaves the row and pins to the top corner. In the row it cost the
     text column ~54px across the full height of the card, which is what pushed
     the years onto their own line; in the corner it costs only the two lines
     it actually sits beside, and the width it gives back is what lets the
     portrait grow at the same time (owner: "the player images are too small").
     The name and the epithet reserve that corner, so nothing runs under it
     (owner, 2026-08-05: "star clips words on a few too"). The figure line is
     the widest of the three and sits below the star, so it keeps the whole
     column — which is the only way the longest one fits at 340px. */
  #player-archive .study-player-actions {
    position: absolute;
    top: 8px;
    right: 8px;
    grid-column: auto;
    grid-row: auto;
    justify-content: flex-end;
    gap: 5px;
  }
  #player-archive .study-player-name,
  #player-archive .study-player-bioline {
    padding-right: 44px;
  }
  #player-archive .study-player-action {
    width: 40px;
    height: 40px;
    flex: 0 0 40px;
    font-size: 1rem;
  }
  .study-player-about-card {
    grid-template-columns: 58px 1fr;
    padding: 18px;
  }
  .study-player-about-portrait {
    width: 52px;
    height: 52px;
  }
  .study-player-about-card .study-player-action {
    grid-column: 1 / -1;
  }

  .bio-hero {
    grid-template-columns: 1fr;
    gap: 22px;
    text-align: center;
    margin-bottom: 36px;
  }
  .bio-hero-portrait {
    width: 132px;
    height: 132px;
    margin: 0 auto;
  }
  .bio-hero-text { padding-right: 0; }
  .event-hero--text-only .bio-hero-text { padding: 0; }
  .bio-name { font-size: 2rem; overflow-wrap: anywhere; }
  .bio-crown { text-align: left; }
  .bio-hero-actions { justify-content: center; }
  .bio-top-actions {
    position: static;
    justify-content: flex-start;
    margin-bottom: 18px;
  }
  .event-about > .bio-index-back {
    position: static;
    margin: 0 auto 18px 0;
  }
  .study-player-about-page .bio-hero-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }
  .study-player-about-page .bio-hero-actions .bio-btn {
    width: 100%;
    justify-content: center;
  }
  .study-player-about-page .bio-hero-actions .bio-btn-primary {
    grid-column: 1 / -1;
  }
  .study-player-about-page .bio-player-profile-actions.has-notable-games .bio-btn-primary {
    grid-column: auto;
  }
  .study-player-about-page .bio-player-profile-actions.has-notable-games .bio-btn {
    min-width: 0;
    gap: 4px;
    padding: 9px 8px;
    font-size: 0.68rem;
    letter-spacing: 0.55px;
    white-space: nowrap;
  }
  .bio-lede {
    font-size: 1.1rem;
    padding-left: 16px;
    margin-bottom: 38px;
  }
  /* Two up on phones, and still centred when the last row is short. */
  .bio-vitals { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
  .bio-numbers { grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
  .bio-archive-grid { grid-template-columns: 1fr; }
  .bio-para { font-size: 1rem; }

  .htb-identity-card,
  .htb-proof-card,
  .htb-note-section {
    padding: 18px;
  }
  .htb-identity-row,
  .htb-machine-row {
    align-items: flex-start;
    flex-direction: column;
  }
  .htb-stat-grid {
    grid-template-columns: 1fr;
  }
  .htb-card-action {
    text-align: left;
  }
}

@media(max-width: 420px) {
  /* The gutter tightens with the screen, as the shell's own padding used to.
     It is the text that pulls in here, not the panels. */
  .page > .header,
  .page > .hero,
  .page > p,
  .page > h1,
  .page > h2 {
    padding-left: 10px;
    padding-right: 10px;
  }
  .header-name {
    font-size: 1.75rem;
    line-height: 1.18;
  }
  .section-title {
    gap: 8px;
    letter-spacing: 3px;
  }
  .player-starters-heading .section-title,
  .study-player-bucket-header .section-title {
    --player-section-title-gap: 8px;
  }
  /* Still one row per player with one star beside it — only the portrait, the
     gaps, and the type tighten. */
  #player-archive .study-player-card {
    grid-template-columns: 68px minmax(0, 1fr);
    gap: 12px;
    padding: 12px;
  }
  #player-archive .study-player-portrait {
    width: 68px;
    height: 68px;
  }
  #player-archive .study-player-actions {
    top: 8px;
    right: 8px;
  }
  .profile-icon,
  .social-icon {
    width: 34px;
    height: 34px;
  }
  .profile-arrow {
    display: none;
  }
}

@media(max-width: 340px) {
  /* Portrait, text and star hold their row all the way down — there is only
     one control left to fit. */
  #player-archive .study-player-card {
    grid-template-columns: 60px minmax(0, 1fr);
    gap: 10px;
    padding: 10px;
  }
  #player-archive .study-player-portrait {
    width: 60px;
    height: 60px;
  }
  #player-archive .study-player-action {
    width: 36px;
    height: 36px;
    flex-basis: 36px;
  }
  #player-archive .study-player-name,
  #player-archive .study-player-bioline {
    padding-right: 40px;
  }
}

/* ════════════════════════════════════════════════════════════════════
   ENHANCED MOTION LAYER (2026-05-25)
   Richer graphics within the existing void/cyberpunk palette. Every rule
   here is a CSS animation/transition, so it is automatically neutralised
   by `html.animations-disabled *` and by the prefers-reduced-motion block
   above. JS-driven layers (starfield extras, scroll reveal, cursor glow)
   self-gate in main.js. The game viewer (body.game-board-page) opts out of
   the heavier JS layers but keeps this shared styling.
   ════════════════════════════════════════════════════════════════════ */

/* ── SCROLL REVEAL ──
   Only active once main.js confirms motion is enabled and adds `reveal-on`
   to <html>; without that class targets render normally (no-JS / disabled
   visitors always see content). */
html.reveal-on [data-reveal] {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity 0.7s cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
  /* Intentionally NO will-change here: these can be many (20-40+ cards/items)
     and a persistent compositor layer per element exhausts GPU memory over
     time (observed as a tab crash/auto-reload on Windows/Chrome). */
}
html.reveal-on [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* ── CURSOR-REACTIVE CARD GLOW ──
   A soft radial highlight that follows the pointer across glass cards.
   Excludes .rating-card (which already owns its ::after accent bar). */
.card:not(.rating-card)::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  border-radius: inherit;
  opacity: 0;
  transition: opacity 0.35s ease;
  background: radial-gradient(
    220px circle at var(--gx, 50%) var(--gy, 50%),
    rgba(var(--tint-rgb), 0.11),
    rgba(var(--tint-rgb), 0.04) 38%,
    transparent 62%
  );
}
.card:not(.rating-card):hover::after {
  opacity: 1;
}

/* ── HOVER LIFT + PRESS FEEDBACK ──
   Slightly stronger, springier interactions on the shared interactive
   elements, plus tactile press states. */
.card:hover {
  transform: translateY(-3px);
}
.hero-action,
.bio-btn,
.view-btn,
.study-player-action,
.games-filter-btn {
  transition: color 0.2s ease, border-color 0.2s ease, background 0.2s ease,
              box-shadow 0.25s ease, transform 0.18s cubic-bezier(0.22, 0.61, 0.36, 1);
}
.hero-action:active,
.bio-btn:active,
.view-btn:active,
.study-player-action:active,
.games-filter-btn:active {
  transform: scale(0.96);
}
.study-player-card:hover .study-player-portrait img {
  transform: scale(1.05);
}
.study-player-portrait img {
  transition: transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ── FOCUS-VISIBLE GLOW RING ── keyboard users get the same cyberpunk accent */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
.card:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--cyan), 0 0 18px rgba(var(--tint-rgb), 0.35);
}

/* Native <select> dropdown lists are painted with OS colours (white on
   Firefox/Linux and Windows/Chrome), which can render as unreadable
   white-on-white against the dark theme. Force readable dark options for every
   dropdown on the site. */
select option,
select optgroup {
  background-color: rgb(var(--slate-rgb));
  color: var(--white);
}

/* ── DIVIDER / SECTION-MARK SHIMMER ── quiet life in the static rules */
.header-divider {
  background: linear-gradient(90deg, transparent, var(--tint), transparent);
  background-size: 200% 100%;
  animation: dividerShimmer 6s ease-in-out infinite;
}
@keyframes dividerShimmer {
  0%, 100% { background-position: 0% 0; opacity: 0.7; }
  50%      { background-position: 100% 0; opacity: 1; }
}
.bio-section-mark {
  display: inline-block;
  animation: markPulse 4s ease-in-out infinite;
}
@keyframes markPulse {
  0%, 100% { opacity: 0.55; text-shadow: 0 0 4px rgba(var(--cyan-rgb), 0.2); }
  50%      { opacity: 1;    text-shadow: 0 0 14px rgba(var(--cyan-rgb), 0.6); }
}

/* ── Account dropdown: Sound flyout (theme picker + docked volume) ── */
/* Width comes off the labels, not the 300px the sibling board/piece pickers
   need for their swatch grids — a list of one-word sound names in a 300px
   panel is a column of text with a hand's width of nothing beside it. */
.account-submenu-panel.sound-panel {
    width: max-content;
    min-width: 196px;
    max-width: min(280px, calc(100vw - 28px));
    padding: 8px;
}
.sound-flyout { display: flex; gap: 10px; align-items: stretch; }
/* The rail stands on end beside the list it controls (owner, 2026-08-05:
   "sound slider should be verticle"). It takes the list's height rather than
   setting its own, so the panel is still sized by its rows. */
.sound-volume-range {
    writing-mode: vertical-lr;
    direction: rtl;
    flex: 0 0 auto;
    width: 22px;
    min-height: 0;
    accent-color: var(--cyan);
    cursor: pointer;
}
.sound-set-list { display: flex; flex-direction: column; }
/* Scoped under .sound-set-list so these rows beat the generic boxed
   .account-nav button treatment (which turns them into inline-grid boxes
   that stack the check/label/state spans vertically). */
.sound-set-list .sound-set-item {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: 8px;
    width: 100%;
    /* Ten rows at 7px of padding read as one striped block. Given a real
       target height each row is its own thing to hit, which is what the hover
       fill was already promising and the geometry was denying. */
    min-height: 32px;
    padding: 6px 10px;
    background: transparent;
    border: 0;
    color: var(--muted);
    font: inherit;
    font-size: 0.8rem;
    letter-spacing: normal;
    text-transform: none;
    text-align: left;
    cursor: pointer;
    border-radius: 4px;
}
.sound-set-list .sound-set-item:hover {
    background: rgba(255, 255, 255, 0.06);
    color: var(--white);
    border-color: transparent;
    box-shadow: none;
}
.sound-set-list .sound-set-item .sound-set-check { width: 14px; opacity: 0; color: var(--cyan); }
/* Selected row speaks the site-wide selection language: blue accent bar and
   tinted fill, white label — never its own one-off color. */
.sound-set-list .sound-set-item.is-selected {
    background: rgba(var(--cyan-rgb), 0.16);
    color: var(--white);
    box-shadow: inset 2px 0 0 var(--cyan);
}
.sound-set-list .sound-set-item.is-selected .sound-set-check { opacity: 1; }
.sound-set-list .sound-set-item .sound-set-label { flex: 1; }
.sound-set-list .sound-set-item .account-menu-state { font-size: 0.85em; opacity: 0.8; }
.sound-set-list .sound-speech-toggle { margin-top: 4px; border-top: 1px solid rgba(255,255,255,0.08); border-radius: 0 0 4px 4px; }

/* ════════════════════════════════════════════════════════════════════
   ACCOUNT SHELL — left rail plus left-anchored content.
   One rail carries section navigation for both My Library and Settings; the
   current ownership and routing rules live in docs/memory/accounts.md.
   ════════════════════════════════════════════════════════════════════ */

/* Two columns and nothing else. Every earlier version of this reserved the
   full display height and drew the content column as a surface — first a
   filled bordered panel, then a hairline down its left edge. Both were the
   same mistake: a section holding one notebook rendered as a title in the top
   eighth of an empty rectangle 900px tall, and the outline made the emptiness
   more visible rather than less (owner: "your removing the boxes but keeping
   the overall problem"). A page ends where its content ends. The rail reads
   against the content because it is quiet small type beside loud large type,
   which is what actually separates them. */
.account-shell {
  display: grid;
  grid-template-columns: 224px minmax(0, 1fr);
  align-items: start;
  column-gap: 46px;
}

/* The rail is the only navigation on these pages: named destinations, no
   counts, and no surface of its own. It sits directly on the page background,
   and its left padding is zero so the active item's accent bar lands on the
   page's own 78px inset — the same left edge the site chrome uses — instead of
   being indented inside a box. The right padding is the breathing room before
   the content surface begins. */
.account-rail {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 30px 0 26px;
}
.account-rail-title {
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--chrome);
  padding: 0 12px 14px;
}
.account-rail-item {
  display: block;
  width: 100%;
  text-align: left;
  font-family: 'Rajdhani', sans-serif;
  font-size: 0.98rem;
  letter-spacing: 0.4px;
  text-decoration: none;
  color: var(--muted);
  padding: 9px 12px;
  border: 0;
  border-left: 2px solid transparent;
  background: transparent;
  cursor: pointer;
  transition: color 0.18s ease, background 0.18s ease, border-color 0.18s ease;
}
.account-rail-item:hover {
  color: var(--white);
  background: rgba(var(--tint-rgb), 0.06);
}
.account-rail-item.is-active,
.account-rail-item[aria-selected="true"] {
  color: var(--cyan);
  border-left-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.09);
}
.account-rail-item-danger.is-active,
.account-rail-item-danger[aria-selected="true"] {
  color: var(--danger);
  border-left-color: var(--danger);
  background: rgba(var(--danger-rgb), 0.09);
}
.account-rail-item-danger:hover {
  color: var(--danger);
  background: rgba(var(--danger-rgb), 0.07);
}
/* The content column is the surface. It fills the remaining width, stretches to
   the shell's full height, and its left edge is what the rail reads against.

   That left edge is now a hairline rather than a filled bordered panel. Filling
   it drew a rectangle around a list that was already a list, and on a section
   holding one row the box became 900px of empty tint with the content stranded
   in the top eighth of it — the owner's reading of the whole feature: "its
   literally nothing except boxes". The separator survives because the shell
   stretches both columns to the display height, so the rule runs the full
   height on its own without a fill behind it. */
.account-content {
  min-width: 0;
  padding: 26px 0 90px;
}
.account-content-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px 20px;
  margin-bottom: 22px;
  padding-bottom: 16px;
  border-bottom: 1px solid rgba(var(--tint-rgb), 0.16);
}
.account-content-title {
  font-family: 'Orbitron', sans-serif;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem);
  letter-spacing: 1px;
  color: var(--white);
  line-height: 1.15;
}
.account-content-lead {
  flex: 1 1 100%;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.86rem;
  letter-spacing: 0.5px;
}
/* `.account-content-action` is gone. A page-head action is a secondary action
   and now says so: the two surfaces that had their own outlined variant of it
   wear `action-secondary`, which is the same control the rest of the library
   already used (owner, 2026-08-06: "the new better looking button can replace
   the old one, in the old location"). */
/* The account area is a working surface, not a poster page, so it drops the
   1100px reading cap. The 78px side inset is the site chrome's own column —
   `.site-nav` is pinned to `left: 78px` — so the rail's outer edge lands under
   the first nav button instead of floating on a width nothing else uses.

   No sticky-footer treatment here. The shell already fills the display, so
   pinning the footer into view would only shorten the shell and put the panel's
   dangling bottom edge back on screen. The footer belongs below the fold. */
.account-shell-page .page {
  max-width: none;
  padding-left: 78px;
  padding-right: 78px;
}

/* The shell owns its own top spacing; the page's poster padding would push the
   rail a third of the way down the viewport. Scoped above 720px so it cannot
   undercut the taller clearance the mobile nav needs — the site nav is out of
   flow, so too little padding here puts the rail underneath it. */
@media (min-width: 721px) {
  .account-shell-page .page {
    padding-top: 72px;
  }
}

/* Below the chrome's own inset there is no 78px column to align to. */
@media (max-width: 1100px) {
  .account-shell-page .page {
    padding-left: 24px;
    padding-right: 24px;
  }
}

/* On a phone the account area follows the same rule as the rest of the site:
   the shell reaches both screen edges (owner: "355 of 375 ... should be 375 of
   375"). A 24px gutter here cost the library 48px of a 375px screen and clipped
   its own section labels — "MY NOTEBOOKS" started off the left edge — while the
   listing rows ran past the right. The rows carry their own small inset, so
   text still does not sit on the glass. */
@media (max-width: 720px) {
  .account-shell-page .page {
    padding-left: 0;
    padding-right: 0;
  }
  .account-shell-page .account-content,
  .account-shell-page .account-back-row {
    padding-left: 14px;
    padding-right: 14px;
  }
}

/* ── ACCOUNT AREA ON A PHONE ────────────────────────────────────────────────
   A rail is a column, and a column costs nothing vertically on a desktop.
   Restacked on a phone it becomes navigation you scroll past on every page —
   192px on Library, 280px on Settings, before any content. The two halves get
   different answers because they are different shapes:

   - My Library is five separate, unbounded listings. The rail goes away and the
     landing carries the destinations, with a back row on each section.
   - Settings is five short panels on one page already driven by a tablist. The
     rail stays, as one sticky scrollable strip, so switching stays free.

   Neither one stacks a nav band on top of a title band on top of content. */
@media (max-width: 860px) {
  .account-shell {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
  }
  .account-content {
    padding: 0 0 60px;
  }

  /* Library: the landing rows are the menu, so the rail is pure duplication. */
  .account-shell-page:not(.account-settings-page) .account-rail {
    display: none;
  }

  /* Settings: one row, scrolled sideways, pinned under the site header so it
     never leaves. `nowrap` is what keeps it a strip instead of a block — with
     wrapping it grows back into the 280px band this replaced. */
  .account-settings-page .account-rail {
    position: sticky;
    top: 0;
    z-index: 3;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 4px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    padding: 0;
    border-right: 0;
    border-bottom: 1px solid var(--border);
    background: var(--void);
  }
  .account-settings-page .account-rail::-webkit-scrollbar {
    display: none;
  }
  .account-settings-page .account-rail-title {
    display: none;
  }
  /* The strip is sticky, so anything the content puts at its own top slides
     under it — the panel's own title was cut in half by the tab that selected
     it. Clearing the strip's own height is the whole fix. */
  .account-settings-page .account-content {
    padding-top: 18px;
  }
  .account-settings-page .settings-section-tabs {
    display: flex;
    flex-wrap: nowrap;
    gap: 4px;
  }
  .account-settings-page .account-rail-item {
    flex: 0 0 auto;
    width: auto;
    min-height: 44px;
    padding: 0 14px;
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    border-left: 0;
    border-bottom: 2px solid transparent;
    scroll-snap-align: start;
  }
  .account-settings-page .account-rail-item.is-active,
  .account-settings-page .account-rail-item[aria-selected="true"] {
    border-left-color: transparent;
    border-bottom-color: var(--cyan);
  }
  .account-settings-page .account-rail-item-danger.is-active,
  .account-settings-page .account-rail-item-danger[aria-selected="true"] {
    border-bottom-color: var(--danger);
  }
}

/* The back row is the heading and the navigation in one element, so a section
   page has a single band above its content rather than two. Phone only: above
   860px the rail is visible and this would duplicate it. */
.account-back-row {
  display: none;
}
@media (max-width: 860px) {
  .account-back-row {
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    margin-bottom: 4px;
    color: var(--chrome);
    font-family: 'Share Tech Mono', monospace;
    font-size: 0.78rem;
    letter-spacing: 1.6px;
    text-transform: uppercase;
    text-decoration: none;
  }
  .account-back-arrow {
    font-size: 1.15rem;
    line-height: 1;
  }
}

/* `.library-section-*` is gone. The landing's destinations were a bordered
   56px pill with its own font stack, shown only below 860px — a sixth item
   component for the same kind of object every other section of the library
   lists. The landing renders the shared row now, at every width, and the
   count carries a noun so the number means something on its own. */

/* The site header bottoms out at 50px on a phone; the shared page reserved 138.
   Scoped to the account area so it does not change every other page. */
@media (max-width: 720px) {
  .account-shell-page .page {
    padding-top: 72px;
  }
  /* The pill is a fixed overlay pinned to the top, and on a phone that puts it
     on the first row of the shell: measured, the pill spans 62..104 and the
     /settings/ tab rail 72..116, so the rail's labels sit behind it. Moving
     the pill to the bottom is the placement the owner ruled out, so the shell
     moves instead — by exactly the pill's height, and only while the pill is
     there. `main.js` removes the node on dismiss, so `:has()` puts the shell
     straight back. */
  body.account-shell-page:has(.email-verify-notice) .page {
    padding-top: 114px;
  }
}

/* A small overlay pinned to the bottom centre, out of flow on purpose. In flow
   this pushed the entire account shell down by its own height on every page in
   the area — the reminder moved the thing it was reminding you about. Fixed,
   it sits over the page and moves nothing.

   The orange is now confined to the state chip, which is the only part of the
   notice that means something; the shell around it is ordinary panel chrome.
   Dismissal is per view — `main.js` removes the node and nothing records it,
   so the prompt returns on the next account page render for as long as the
   address is unverified. */
/* Top of the viewport, not the bottom (owner, 2026-08-05: "on top not directly
   on bottom"): pinned to the bottom it landed on the footer wordmark, so the
   one line the reader needed sat on top of the site's signature. 62px clears
   the nav row — `.site-nav` and the account chip are absolute at top:18px and
   about 34px tall, so anything above this overlaps them at scroll-top. */
/* Absolute, not fixed: out of flow so it still moves nothing, but anchored to
   the page rather than to the glass, so it scrolls away with the top of the
   page it belongs to. Fixed, it rode the viewport down the whole document and
   sat over the footer (owner, 2026-08-06: "the email verification pop up
   sticks to the screen too" — the same objection as the viewer's menus). */
.email-verify-notice {
  position: absolute;
  left: 50%;
  top: 62px;
  transform: translateX(-50%);
  z-index: 1250;
  display: flex;
  align-items: center;
  gap: 6px;
  max-width: min(440px, calc(100vw - 24px));
  padding: 4px 5px 4px 12px;
  /* Barely an edge. A full-strength border drew the pill as an object on the
     page; at this alpha it only separates the blur from what is behind it
     (owner, 2026-08-05: "thats not a transparent gentle reminder"). */
  border: 1px solid rgba(255, 255, 255, 0.09);
  border-radius: 999px;
  /* A toast, not a panel (owner, 2026-08-05: "it could even be a smaller
     slightly transparant little pop up like on most sites"). The tint comes
     from whichever theme is mounted rather than a literal, so the Space theme
     keeps its own ground; the blur is what carries legibility at this alpha,
     which is why it is heavier than the transparency alone would need. */
  background: rgba(var(--surface-rgb), 0.62);
  backdrop-filter: blur(16px) saturate(1.2);
  -webkit-backdrop-filter: blur(16px) saturate(1.2);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28);
}
/* The whole caution signal, in one 6px dot. It replaced an outlined amber chip:
   the colour is the same information, and the chip was a box around it. */
.email-verify-dot {
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--amber);
  box-shadow: 0 0 6px rgba(var(--amber-rgb), 0.55);
}
/* Base typography here is the Space theme's copy of the roles above. Every
   declaration is a single class, so the charcoal roles — two classes plus an
   element — win outright and this never fights them. */
.email-verify-state {
  color: var(--chrome);
  font-size: 0.78rem;
  white-space: nowrap;
}
.email-verify-notice form {
  margin: 0;
}
.email-verify-resend {
  border: 0;
  background: none;
  color: var(--white);
  padding: 4px 8px;
  font-size: 0.78rem;
  cursor: pointer;
  white-space: nowrap;
}
.email-verify-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  flex: 0 0 auto;
  border: 0;
  background: none;
  color: var(--muted);
  cursor: pointer;
}
.email-verify-dismiss:hover {
  color: var(--white);
}

/* Settings content fills the shell's content column. The former 980px/660px
   caps are gone: the rail already bounds the measure, and stacking caps inside
   a centered page is what left the panel floating mid-viewport. Dense settings
   forms cap themselves where a long input line would otherwise hurt. */
.account-settings-panel {
  display: grid;
  gap: 18px;
  max-width: 860px;
}

/* Settings sections are rail items, styled by .account-rail-item. These tabs
   switch panels client-side, so the container only stacks them. Kept as a real
   flex box rather than display:contents so role="tablist" stays in the
   accessibility tree. */
.settings-section-tabs {
  display: flex;
  flex-direction: column;
  gap: 2px;
  width: 100%;
}
@media (max-width: 860px) {
  .settings-section-tabs {
    flex-direction: row;
    flex-wrap: wrap;
    gap: 6px;
  }
}

/* Each section's controls. The grid gap matches the panel's own spacing so a
   switched-in panel looks identical to the old single-column layout. */
.settings-tabpanel {
  display: grid;
  gap: 18px;
}
.settings-tabpanel[hidden] {
  display: none;
}
.profile-settings-form .settings-tabpanel + .settings-tabpanel {
  margin-top: 0;
}

/* Email/password live behind a disclosure button rather than sitting open as a
   wall of inputs. The <summary> is styled as a ghost button with a chevron. */
.settings-disclosure {
  border-top: 1px solid rgba(var(--tint-rgb), 0.12);
  padding-top: 14px;
}
/* Unless it opens the group. The rule separates the disclosure from whatever
   is above it inside the group — an email row, a heading — and with nothing
   above it, it lands right under the head's own rule and reads as a second
   line separating nothing (owner, 2026-08-06: "now their is an extra line
   again"). */
.settings-group > .settings-disclosure:first-child {
  border-top: 0;
  padding-top: 0;
}
.settings-disclosure-summary {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  width: auto;
  padding: 9px 16px;
  border: 1px solid rgba(var(--tint-rgb), 0.32);
  border-radius: 6px;
  background: rgba(var(--tint-rgb), 0.06);
  color: var(--chrome);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.78rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  cursor: pointer;
  list-style: none;
}
.settings-disclosure-summary::-webkit-details-marker {
  display: none;
}
.settings-disclosure-summary::after {
  content: '+';
  margin-left: auto;
  font-size: 1rem;
  line-height: 1;
}
.settings-disclosure[open] > .settings-disclosure-summary::after {
  content: '\2212'; /* minus */
}
.settings-disclosure-summary:hover {
  color: var(--white);
  border-color: var(--cyan);
  background: rgba(var(--tint-rgb), 0.14);
}
.settings-disclosure[open] > .settings-disclosure-summary {
  margin-bottom: 0;
}

/* Change email, change password and create token open as overlays, not as
   forms unfolding under their own button (owner, 2026-08-06: "change email,
   and pass make these weird pop unders, make them overlays instead", "same for
   api token"). Opened in place, each one pushed everything below it down the
   length of the form, so the settings panel rearranged itself around the
   control the reader had just pressed.

   Same mechanism as the notebook overlay: the scrim is drawn by the summary,
   so a click anywhere outside the panel lands on the control that opened it
   and closes the disclosure — no script, and Escape still works because it is
   still a `<details>`. */
.settings-disclosure[open] > .settings-disclosure-summary::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1300;
  background: rgba(0, 0, 0, 0.62);
}
.settings-disclosure[open] > form {
  position: fixed;
  z-index: 1301;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: min(460px, calc(100vw - 32px));
  max-height: calc(100svh - 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0;
  padding: 20px;
  border: 1px solid var(--border, rgba(255, 255, 255, 0.14));
  border-radius: 4px;
  background: var(--surface, #1e2124);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
}

/* A settings section is a heading and the controls under it. It used to be a
   tinted rounded rectangle with a 2px-tracked micro-caps label inside — five
   of them stacked down a page whose own container was another box. The
   section is spacing and a hairline now; the heading carries the type.
   `entry-title` sets the type, so nothing here does. */
.settings-group {
  display: grid;
  gap: 12px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
}
/* The group directly under the panel's own title block keeps no rule of its
   own: the head already draws one, and a group hairline 40px below it is a
   second line separating nothing (owner, 2026-08-06: "for settings on each
   page there are 2 extra lines under each title").

   Matched off the head, not by position. `:first-of-type` was meant to do this
   and never could — the title block is a <div> as well and it comes first, so
   the "first div" in a panel is the head itself and the group after it kept
   its border on all eight panels. */
.account-content-head + .settings-group,
.account-content-head + form > .settings-group:first-of-type {
  padding-top: 0;
  border-top: 0;
}
.settings-group-title {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 9px;
  text-align: center;
  width: 100%;
}

/* Save sits with the form (right-aligned), not as a full-width banner. */
.settings-actions {
  display: flex;
  justify-content: flex-end;
}
.settings-actions .auth-submit {
  width: auto;
}

.viewer-keybindings-actions {
  display: flex;
  justify-content: flex-end;
}
.viewer-keybindings-table-wrap {
  max-width: 100%;
  overflow-x: auto;
}
.viewer-keybindings-table {
  width: 100%;
  border-collapse: collapse;
}
.viewer-keybindings-table th,
.viewer-keybindings-table td {
  padding: 12px 10px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: top;
}
.viewer-keybindings-table .setting-name {
  min-width: 170px;
}
.viewer-keybinding-slot {
  min-width: 96px;
}
.viewer-keybinding-values .action-secondary,
.viewer-keybinding-change .action-secondary,
.viewer-keybinding-values kbd {
  margin: 0 6px 6px 0;
}
.viewer-keybinding-slot.is-capturing {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
.viewer-keybinding-change .setting-help,
.viewer-keybinding-error {
  display: block;
  margin-top: 6px;
}
.viewer-keybinding-error:empty {
  display: none;
}
@media (max-width: 720px) {
  .viewer-keybindings-table {
    min-width: 760px;
  }
}
.account-identity-settings,
.account-password-settings {
  display: grid;
  gap: 14px;
}
/* Flex rather than a three-track grid: the status chip is a chip, and as a
   grid item on a phone's single column it stretched into a full-width amber
   bar reading UNVERIFIED — a chip is sized by its word or it is a banner. */
.account-identity-summary {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
  font-family: 'Share Tech Mono', monospace;
}
.account-identity-summary strong {
  margin-right: auto;
}
.account-identity-summary span {
  color: var(--muted);
  font-size: 0.76rem;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.account-identity-summary strong {
  min-width: 0;
  color: var(--white);
  font-size: 0.86rem;
  font-weight: 400;
  overflow-wrap: anywhere;
}
.account-identity-status {
  border: 1px solid rgba(var(--tint-rgb), 0.26);
  border-radius: 999px;
  padding: 4px 8px;
  font-size: 0.68rem;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.account-identity-status.is-verified {
  border-color: rgba(var(--mint-rgb), 0.35);
  color: var(--mint);
}
.account-identity-status.is-unverified {
  border-color: rgba(var(--amber-rgb), 0.38);
  color: var(--amber);
}
.account-action-form {
  display: grid;
  gap: 12px;
}
.account-action-form .auth-submit {
  justify-self: end;
  width: auto;
}
.account-delete-copy {
  margin: 4px 0 0;
  color: var(--white);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  line-height: 1.55;
}
/* The submit here wears `action-danger`, so this places it and nothing more:
   a surface that recolours its own button is how a site ends up with four
   reds. */
.account-delete-form {
  margin-top: 4px;
}

.two-factor-settings {
  display: grid;
  gap: 14px;
}
.two-factor-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  letter-spacing: 1px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(var(--tint-rgb), 0.12);
}
.two-factor-summary strong {
  color: var(--cyan);
  font-weight: 400;
  text-transform: uppercase;
}
.two-factor-setup {
  display: grid;
  grid-template-columns: minmax(128px, 180px) 1fr;
  gap: 16px;
  align-items: center;
}
.two-factor-qr {
  width: min(180px, 100%);
  aspect-ratio: 1;
  border: 1px solid rgba(var(--tint-rgb), 0.24);
  border-radius: 6px;
  background: #fff;
  padding: 8px;
}
.two-factor-secret input {
  font-family: 'Share Tech Mono', monospace;
}
.two-factor-action-form {
  display: grid;
  gap: 12px;
}
.two-factor-action-form .auth-submit {
  justify-self: end;
  width: auto;
}
.two-factor-copy {
  margin: 0;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
}
.two-factor-recovery {
  border: 1px solid rgba(var(--amber-rgb), 0.22);
  border-radius: 6px;
  background: rgba(var(--amber-rgb), 0.06);
  padding: 12px;
}
.two-factor-recovery-title {
  color: var(--amber);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.two-factor-recovery-warning {
  margin: 0 0 12px;
  color: var(--white);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  line-height: 1.55;
}
.two-factor-recovery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 8px;
}
.two-factor-recovery code {
  color: var(--white);
  background: rgba(0, 0, 0, 0.26);
  border: 1px solid rgba(var(--amber-rgb), 0.18);
  border-radius: 4px;
  padding: 8px;
  text-align: center;
}
.two-factor-download {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  margin-top: 12px;
  padding: 10px 16px;
  border: 1px solid var(--tint);
  color: var(--chrome);
  text-decoration: none;
  font-family: 'Orbitron', sans-serif;
  font-size: 0.8rem;
  letter-spacing: 1px;
  background: rgba(var(--tint-rgb), 0.08);
}
.two-factor-download:hover {
  color: var(--white);
  background: rgba(var(--tint-rgb), 0.18);
}

.api-token-settings {
  display: grid;
  gap: 14px;
}
.api-token-create-form {
  grid-template-columns: minmax(0, 1fr) minmax(168px, 0.34fr);
  align-items: end;
  gap: 14px;
}
.api-token-create-form .api-token-scope-fieldset,
.api-token-create-form .api-token-password-field,
.api-token-create-form .auth-submit {
  grid-column: 1 / -1;
}
.api-token-created {
  border: 1px solid rgba(var(--amber-rgb), 0.22);
  border-radius: 6px;
  background: rgba(var(--amber-rgb), 0.06);
  padding: 12px;
}
.api-token-created-title {
  color: var(--amber);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 2px;
  text-transform: uppercase;
  margin-bottom: 10px;
}
.api-token-created input {
  font-family: 'Share Tech Mono', monospace;
}
.api-token-warning,
.api-token-empty {
  margin: 10px 0 0;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  line-height: 1.55;
}
.api-token-scope-fieldset {
  display: grid;
  gap: 8px;
  margin: 0;
  padding: 0;
  border: 0;
}
.api-token-scope-fieldset legend {
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
  letter-spacing: 1px;
  text-transform: uppercase;
  margin-bottom: 6px;
}
.api-token-scope-options {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.api-token-scope-options > div {
  min-width: 0;
}
.api-token-scope-options label {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 38px;
  border: 1px solid rgba(var(--tint-rgb), 0.18);
  border-radius: 4px;
  background: rgba(var(--tint-rgb), 0.035);
  padding: 8px 10px;
  color: var(--white);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.8rem;
  letter-spacing: 0.8px;
}
.api-token-scope-options input[type="checkbox"] {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin: 0;
  appearance: none;
  border: 1px solid rgba(var(--tint-rgb), 0.62);
  background: rgba(0, 0, 0, 0.45);
  cursor: pointer;
}
.api-token-scope-options input[type="checkbox"]:checked {
  background: var(--cyan);
  border-color: var(--cyan);
  box-shadow: 0 0 12px rgba(var(--tint-rgb), 0.42);
}
.api-token-scope-options input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 1px var(--cyan), 0 0 14px rgba(var(--tint-rgb), 0.26);
}
.api-token-scope-options label:has(input[type="checkbox"]:checked) {
  border-color: rgba(var(--tint-rgb), 0.38);
  background: rgba(var(--tint-rgb), 0.08);
  color: var(--cyan);
}
.api-token-list {
  display: grid;
  gap: 12px;
}
.api-token-item {
  display: grid;
  gap: 10px;
  padding: 12px;
  border: 1px solid rgba(var(--tint-rgb), 0.14);
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.18);
}
.api-token-main {
  display: grid;
  gap: 4px;
}
.api-token-main strong {
  min-width: 0;
  color: var(--white);
  font-family: 'Orbitron', sans-serif;
  font-size: 0.84rem;
  font-weight: 400;
  overflow-wrap: anywhere;
}
.api-token-main code {
  color: var(--cyan);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.78rem;
  overflow-wrap: anywhere;
}
.api-token-meta {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  color: var(--muted);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.72rem;
}
.api-token-scopes {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.api-token-scopes span {
  border: 1px solid rgba(var(--tint-rgb), 0.26);
  border-radius: 999px;
  color: var(--chrome);
  font-family: 'Share Tech Mono', monospace;
  font-size: 0.68rem;
  letter-spacing: 1px;
  padding: 4px 8px;
  text-transform: uppercase;
}
.api-token-revoke-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: end;
  padding-top: 10px;
  border-top: 1px solid rgba(var(--tint-rgb), 0.12);
}
.api-token-revoke-form .auth-submit {
  width: auto;
}

@media(max-width:720px) {
  .settings-disclosure-summary {
    width: 100%;
  }
  /* The pill stays pinned to the top at every width. It briefly docked to the
     bottom on phones to keep it off the /settings/ tab rail, but the owner
     ruled that placement out on sight (2026-08-05, "on top not directly on
     bottom", then "on mobile this is at the bottom of the screen instead of
     the top"). Only the pill's own metrics change here; `top` is inherited
     from the base rule, and the rail is cleared by the pill's own height
     rather than by moving it. */
  .email-verify-notice {
    gap: 8px;
    max-width: calc(100vw - 16px);
    padding: 6px 6px 6px 10px;
  }
  .account-identity-summary {
    grid-template-columns: 1fr;
  }
  .account-action-form .auth-submit {
    justify-self: stretch;
    width: 100%;
  }
  .two-factor-setup {
    grid-template-columns: 1fr;
  }
  .two-factor-action-form .auth-submit {
    justify-self: stretch;
    width: 100%;
  }
  .two-factor-download {
    width: 100%;
  }
  .api-token-meta,
  .api-token-revoke-form {
    grid-template-columns: 1fr;
  }
  .api-token-create-form {
    grid-template-columns: 1fr;
  }
  .api-token-revoke-form .auth-submit {
    width: 100%;
  }
}

/* Field identifiers inherit the reference table's reading style. */
.api-docs-page .apidoc .apidoc-table code,
body.site-theme-charcoal.api-docs-page .apidoc .apidoc-table code {
  font: inherit;
  color: inherit;
  padding: 0;
  background: none;
  box-shadow: none;
}
