/* Self-hosted Latin subsets. Sources and OFL licences: ../fonts/README.md */
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(../fonts/ibm-plex-mono-400-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:600;font-display:swap;src:url(../fonts/ibm-plex-mono-600-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Lexend';font-style:normal;font-weight:400 700;font-display:swap;src:url(../fonts/lexend-400-700-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:'Saira Condensed';font-style:normal;font-weight:700;font-display:swap;src:url(../fonts/saira-condensed-700-latin.woff2) format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

/* =====================================================================
   TypeRacing theme
   Light classroom shell around a dark race stage.
   Recurring motif: the keyboard key (logo, buttons, thumbnail fallback).
   ===================================================================== */

:root{
  /* shell: classroom daylight */
  --paper:#F1F3F6;
  --card:#FFFFFF;
  --ink:#14161B;
  --ink-soft:#3B4250;
  --muted:#667085;
  --line:#DBE0E7;
  --line-strong:#C3CAD4;

  /* brand */
  --bus:#FFC61A;          /* school-bus yellow: primary action, logo key */
  --bus-edge:#C99700;
  --kerb:#D93A30;         /* kerb red: NEW flag */
  --lane:#2F6FDB;         /* focus ring, link hover */

  /* stage: the dark race world */
  --asphalt:#14161C;
  --asphalt-2:#1C1F27;
  --asphalt-line:#2E333E;
  --stage-text:#EAECF2;
  --stage-muted:#8A91A5;

  --f-display:"Saira Condensed","Arial Narrow",Impact,sans-serif;
  --f-ui:"Lexend",system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
  --f-mono:"IBM Plex Mono",ui-monospace,Consolas,monospace;

  --wrap:1240px;
  --gutter:16px;
  --radius:10px;
}
@media (min-width:700px){ :root{ --gutter:24px; } }

*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; }
body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font:400 16px/1.55 var(--f-ui);
  -webkit-font-smoothing:antialiased;
}
a{ color:inherit; }
img{ max-width:100%; height:auto; display:block; }
button,input{ font:inherit; color:inherit; }
:focus-visible{ outline:3px solid var(--lane); outline-offset:2px; }
.wrap{ max-width:var(--wrap); margin:0 auto; padding-inline:var(--gutter); }
.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* ---------------------------------------------------------------- key */
/* A keyboard key. The bump is the raised line found on F and J. */
.key{
  position:relative;
  display:inline-grid; place-items:center;
  min-width:36px; height:36px; padding:0 8px;
  font:600 18px/1 var(--f-mono);
  color:var(--ink);
  background:linear-gradient(#FFFFFF,#EEF1F5);
  border:1px solid var(--line-strong);
  border-radius:7px;
  box-shadow:0 3px 0 var(--line-strong);
}
.key-bump::after{
  content:""; position:absolute; left:50%; bottom:5px;
  width:10px; height:2px; margin-left:-5px;
  border-radius:2px; background:currentColor; opacity:.5;
}
.key-bus{ background:linear-gradient(#FFD34D,var(--bus)); border-color:var(--bus-edge); box-shadow:0 3px 0 var(--bus-edge); }
kbd{
  font:500 .85em/1 var(--f-mono);
  padding:2px 6px 3px;
  border:1px solid var(--line-strong); border-radius:4px;
  box-shadow:0 2px 0 var(--line-strong);
  background:var(--card);
}

/* ---------------------------------------------------------------- button */
/* Buttons press down like a key. */
.btn{
  display:inline-flex; align-items:center; gap:10px;
  padding:12px 22px;
  font:600 16px/1 var(--f-ui);
  text-decoration:none;
  color:var(--ink);
  background:var(--bus);
  border:0; border-radius:9px;
  box-shadow:0 4px 0 var(--bus-edge);
  cursor:pointer;
  transition:transform .06s ease, box-shadow .06s ease;
}
.btn:hover{ background:#FFCE3A; }
.btn:active{ transform:translateY(3px); box-shadow:0 1px 0 var(--bus-edge); }
.btn svg{ width:14px; height:14px; }

/* ---------------------------------------------------------------- header */
.site-head{
  position:sticky; top:0; z-index:20;
  background:var(--card);
  border-bottom:1px solid var(--line);
}
.head-row{ display:flex; align-items:center; gap:20px; min-height:64px; }
.brand{ display:flex; align-items:center; gap:10px; text-decoration:none; flex:none; }
.brand .key{ min-width:38px; height:38px; font-size:20px; }
.brand-name{
  font:700 26px/1 var(--f-display);
  text-transform:uppercase; letter-spacing:.01em;
}
.brand-logo{ height:40px; width:auto; }

.main-nav{ display:flex; gap:2px; }
.main-nav a{
  display:block; padding:10px 12px; border-radius:8px;
  font:500 15px/1 var(--f-ui); white-space:nowrap;
  color:var(--ink-soft); text-decoration:none;
}
.main-nav a:hover{ background:var(--paper); color:var(--ink); }
.main-nav a[aria-current="page"]{ color:var(--ink); box-shadow:inset 0 -3px 0 var(--bus); border-radius:8px 8px 0 0; }

.head-search{ margin-left:auto; position:relative; }
.head-search input{
  width:260px; height:40px; padding:0 12px 0 38px;
  font-size:15px;
  background:var(--paper);
  border:1px solid var(--line); border-radius:9px;
}
.head-search input::placeholder{ color:var(--muted); }
.head-search input:focus{ background:var(--card); border-color:var(--line-strong); }
.head-search svg{
  position:absolute; left:12px; top:20px; width:16px; height:16px; margin-top:-8px;
  color:var(--muted); pointer-events:none;
}

/* Search suggestions — markup from ajax/search-suggest.php, opened by site.js. */
.search-pop{
  position:absolute; top:calc(100% + 6px); right:0; z-index:30;
  width:max(100%, 380px); max-width:calc(100vw - var(--gutter) * 2);
  max-height:min(70vh, 460px); overflow-y:auto; padding:6px;
  background:var(--card); border:1px solid var(--line-strong); border-radius:12px;
  box-shadow:0 12px 32px rgba(20,22,27,.16);
}
.sugg-group + .sugg-group{ margin-top:6px; padding-top:6px; border-top:1px solid var(--line); }
.sugg-label{ display:block; padding:6px 10px 4px; font:600 12px/1 var(--f-ui); letter-spacing:.04em; text-transform:uppercase; color:var(--muted); }
.sugg-item{
  display:flex; align-items:center; gap:10px; padding:7px 10px; border-radius:8px;
  font-size:15px; color:var(--ink); text-decoration:none;
}
.sugg-item:hover, .sugg-item[aria-selected="true"]{ background:var(--paper); }
.sugg-item > span{ flex:1 1 auto; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sugg-item mark{ background:none; color:inherit; font-weight:700; }
.sugg-item em{ flex:none; font-style:normal; font-size:12px; color:var(--muted); }
.sugg-thumb{
  flex:none; display:grid; place-items:center; min-width:34px; height:30px; padding:0 5px;
  font:700 12px/1 var(--f-mono); font-style:normal; white-space:nowrap; color:#14161B;
  background:var(--c1); border:1px solid var(--c2); border-radius:6px; box-shadow:0 2px 0 var(--c2);
}
.sugg-all{ justify-content:center; margin-top:4px; font-weight:600; color:var(--lane); }
.sugg-empty{ margin:0; padding:14px 12px; color:var(--muted); font-size:14px; }

/* Below 1024px brand + nav + search no longer fit one row (they overflowed the page
   at 900-990px). With JS (html.js, set in header.php) the header stays one row:
   brand, search, menu button; the nav folds into a panel that site.js opens with
   .is-open, and on phones the search box folds in too, behind a search button.
   Without JS the nav drops to its own scrolling row instead. */
.head-btn{ display:none; }
/* 1024–1179px: six menu items + a 260px search box overflow the row by ~90px (21/09, when
   Leaderboard joined the menu). Tighter links and a narrower box keep one row. */
@media (min-width:1024px) and (max-width:1179px){
  .head-row{ gap:14px; }
  .main-nav a{ padding-inline:8px; }
  .head-search input{ width:200px; }
}
@media (max-width:1023px){
  .head-row{ flex-wrap:wrap; gap:10px 14px; padding-block:10px 0; }
  .head-search{ flex:1 1 160px; min-width:0; }
  .head-search input{ width:100%; }
  .main-nav{
    order:3; width:calc(100% + var(--gutter) * 2);
    margin-inline:calc(var(--gutter) * -1); padding:0 calc(var(--gutter) - 12px) 2px;
    overflow-x:auto; scrollbar-width:none;
  }
  .main-nav::-webkit-scrollbar{ display:none; }

  .js .head-row{ gap:0 10px; padding-block:10px; }
  .js .head-search{ order:1; margin-left:auto; max-width:420px; }
  .js .head-btn{
    order:2; flex:none; display:grid; place-items:center;
    width:42px; height:42px; padding:0;
    color:var(--ink); background:var(--paper);
    border:1px solid var(--line); border-radius:9px; cursor:pointer;
  }
  .js .head-btn:hover, .js .head-btn[aria-expanded="true"]{ background:var(--card); border-color:var(--line-strong); }
  .js .head-btn svg{ width:20px; height:20px; }
  .js .head-btn-search{ display:none; }
  .head-btn-menu .i-close, .is-open .head-btn-menu .i-open{ display:none; }
  .is-open .head-btn-menu .i-close{ display:block; }

  .js .main-nav{ display:none; }
  .js .site-head.is-open .main-nav{
    order:4; display:flex; flex-direction:column; gap:0;
    margin:10px calc(var(--gutter) * -1) -10px; padding:4px 0 8px;
    overflow:visible; border-top:1px solid var(--line);
  }
  .js .site-head.is-open .main-nav a{ padding:14px var(--gutter); font-size:16px; border-radius:0; }
  .js .site-head.is-open .main-nav a[aria-current="page"]{ box-shadow:inset 4px 0 0 var(--bus); }
}
@media (max-width:599px){
  .js .head-btn-search{ display:grid; order:1; margin-left:auto; }
  .js .head-search{ display:none; }
  .js .site-head.is-open .head-search{ display:block; order:3; flex:1 1 100%; max-width:none; margin:10px 0 0; }
}
@media (max-width:420px){
  .brand-name{ font-size:22px; }
  .brand-logo{ height:34px; }
}

/* ---------------------------------------------------------------- page */
.page{ padding-bottom:8px; }

/* ---------------------------------------------------------------- race stage */
.stage-cta{
  margin-top:20px;
  display:grid; grid-template-columns:minmax(0,1fr);
  background:var(--asphalt); color:var(--stage-text);
  border-radius:14px; overflow:hidden;
}
@media (min-width:860px){
  .stage-cta{ grid-template-columns:minmax(0,5fr) minmax(0,7fr); }
}
.stage-copy{
  display:flex; flex-direction:column; justify-content:center; gap:14px;
  padding:28px var(--gutter) 26px;
}
@media (min-width:860px){ .stage-copy{ padding:32px 32px 30px; } }
.stage-eyebrow{
  font:500 12px/1 var(--f-mono); letter-spacing:.14em; text-transform:uppercase;
  color:var(--stage-muted);
}
.stage-title{
  margin:0;
  font:700 clamp(32px,4.2vw,46px)/.95 var(--f-display);
  text-transform:uppercase; letter-spacing:.005em;
  text-wrap:balance;
}
.stage-title em{ font-style:normal; color:var(--bus); }
.stage-sub{ margin:0; max-width:42ch; color:#C3C8D4; }
.stage-actions{ display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:4px; }
.stage-facts{
  display:flex; flex-wrap:wrap; gap:6px 16px; margin:0; padding:0; list-style:none;
  font:500 13px/1.2 var(--f-mono); color:var(--stage-muted);
}
.stage-facts li::before{ content:"/ "; color:var(--asphalt-line); }
.stage-facts li:first-child::before{ content:none; }
/* Filled from localStorage by site.js; stays hidden until the first race. */
.stage-best{ margin:0; font:500 13px/1.2 var(--f-mono); color:var(--stage-muted); letter-spacing:.04em; }
.stage-best b{ font:700 22px/1 var(--f-display); color:var(--bus); letter-spacing:0; margin:0 2px; }

/* Five lanes with pixel cars. Sprites are 64x64 cells on 192x128 sheets,
   drawn at 1x, never smoothed, rotated a quarter turn so the nose points
   down the track (docs/GAME-CONCEPT.md section 4.2). */
.mini-track{
  position:relative;
  display:grid; grid-template-rows:repeat(5,44px); align-content:center;
  padding:14px 0;
  background:#101217;
  border-top:1px solid var(--asphalt-line);
}
@media (min-width:860px){ .mini-track{ border-top:0; border-left:1px solid var(--asphalt-line); } }
.mini-track::before{
  /* kerbs top and bottom */
  content:""; position:absolute; inset:0;
  background:
    repeating-linear-gradient(90deg,#C63B31 0 12px,#E6E6E6 12px 24px) top/100% 4px no-repeat,
    repeating-linear-gradient(90deg,#C63B31 0 12px,#E6E6E6 12px 24px) bottom/100% 4px no-repeat;
  pointer-events:none;
}
.mini-track::after{
  /* chequered finish */
  content:""; position:absolute; top:4px; bottom:4px; right:0; width:12px;
  background:conic-gradient(#F4F4F4 25%,#15171C 0 50%,#F4F4F4 0 75%,#15171C 0) 0 0/12px 12px;
}
.lane{ position:relative; border-top:2px dashed #262A33; }
.lane:first-child{ border-top-color:transparent; }
.car{
  position:absolute; top:50%; left:var(--x,10%);
  width:64px; height:64px; margin:-32px 0 0 -32px;
  background-repeat:no-repeat;
  image-rendering:pixelated;
  transform:rotate(90deg);
}
/* Label trails the player's car. Kept outside the rotated sprite so it reads upright. */
.car-tag{
  position:absolute; top:50%; left:var(--x,10%);
  transform:translate(calc(-100% - 34px),-50%);
  font:600 11px/1 var(--f-mono); letter-spacing:.08em; color:var(--bus);
}

/* ---------------------------------------------------------------- section */
.section{ padding-top:32px; }
.section-head{ display:flex; align-items:baseline; flex-wrap:wrap; gap:6px 12px; margin-bottom:14px; }
.section-title{
  margin:0;
  font:700 30px/1 var(--f-display);
  text-transform:uppercase; letter-spacing:.005em;
}
/* A qualifier beside a title ("last 7 days"). Never a count — counts were dropped 19/09. */
.section-note{ font:500 13px/1 var(--f-mono); color:var(--muted); }
.section-link{
  margin-left:auto;
  font:600 14px/1 var(--f-ui); color:var(--ink-soft); text-decoration:none;
}
.section-link:hover{ color:var(--lane); }

/* ---------------------------------------------------------------- game grid */
.game-grid{
  list-style:none; margin:0; padding:0;
  display:grid; gap:14px;
  grid-template-columns:repeat(2,minmax(0,1fr));
}
@media (min-width:480px){ .game-grid{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (min-width:700px){ .game-grid{ grid-template-columns:repeat(4,minmax(0,1fr)); gap:16px; } }
@media (min-width:940px){ .game-grid{ grid-template-columns:repeat(5,minmax(0,1fr)); } }
@media (min-width:1120px){ .game-grid{ grid-template-columns:repeat(6,minmax(0,1fr)); } }
.game-grid > li{ min-width:0; }
.grid-empty{
  margin:0; padding:28px; text-align:center;
  color:var(--muted); background:var(--card);
  border:1px dashed var(--line-strong); border-radius:var(--radius);
}

/* ---------------------------------------------------------------- card */
.card{
  display:flex; flex-direction:column; height:100%;
  color:var(--ink); text-decoration:none;
  background:var(--card);
  border:1px solid var(--line); border-radius:var(--radius);
  overflow:hidden;
  transition:transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.card:hover{
  transform:translateY(-3px);
  border-color:var(--line-strong);
  box-shadow:0 10px 22px -12px rgba(20,22,27,.45);
}
.thumb{
  position:relative; display:grid; place-items:center;
  aspect-ratio:1/1; overflow:hidden;
  background:var(--asphalt-2);
}
.thumb img{ width:100%; height:100%; object-fit:cover; }
.thumb::after{
  /* skill colour stripe */
  content:""; position:absolute; left:0; right:0; bottom:0; height:4px; background:var(--c1);
}
/* No image yet: a key on a strip of track, lettered with the game's initial. */
.thumb-track{
  background:
    linear-gradient(#262A33,#262A33) center 30%/100% 2px no-repeat,
    linear-gradient(#262A33,#262A33) center 70%/100% 2px no-repeat,
    var(--asphalt-2);
}
.thumb-track .key{
  width:42%; min-width:0; height:auto; aspect-ratio:1/1; padding:0;
  font-size:clamp(26px,3.6vw,40px);
  border-color:var(--c2);
  box-shadow:0 5px 0 var(--c2);
  border-radius:12%;
}
.flag{
  position:absolute; top:8px; left:8px; z-index:1;
  padding:4px 6px 3px; border-radius:4px;
  font:600 11px/1 var(--f-mono); letter-spacing:.06em;
}
.flag.new{ background:var(--kerb); color:#FFFFFF; }
.flag.hot{ background:var(--bus); color:var(--ink); }
.card-body{ display:flex; flex-direction:column; gap:4px; padding:10px 12px 12px; }
.card-title{
  font:600 15px/1.25 var(--f-ui);
  display:-webkit-box; -webkit-line-clamp:2; -webkit-box-orient:vertical; overflow:hidden;
}
.card-meta{ display:flex; align-items:flex-start; gap:6px; font:400 13px/1.3 var(--f-ui); color:var(--muted); }
.card-meta .dot{ margin-top:4px; }
.nw{ white-space:nowrap; }
.card-meta .dot{ flex:none; width:8px; height:8px; border-radius:2px; background:var(--c1); }

/* ---------------------------------------------------------------- rail */
/* One row of cards that scrolls sideways. Card width follows the grid's
   column count; below desktop a slice of the next card shows, so the row
   reads as scrollable without a visible scrollbar. */
.railwrap{ position:relative; container:rail / inline-size; --rail-gap:14px; --rail-n:2.3; --rail-k:2; }
/* Fallback for browsers without container queries: count by window width. */
@media (min-width:480px){ .railwrap{ --rail-n:3.3; --rail-k:3; } }
@media (min-width:700px){ .railwrap{ --rail-gap:16px; --rail-n:4.3; --rail-k:4; } }
@media (min-width:940px){ .railwrap{ --rail-n:5; --rail-k:4; } }
@media (min-width:1120px){ .railwrap{ --rail-n:6; --rail-k:5; } }
/* Count by the row's own width. A row beside a sidebar (the game page) is much
   narrower than the window: counted by the window it got six cards of ~130px,
   names on two lines and "Words · Grades 2–6" broken in two. Cards stay ~145–210px. */
@container rail (max-width:519px){ .rail{ --rail-gap:14px; --rail-n:2.3; --rail-k:2; } }
@container rail (min-width:520px){ .rail{ --rail-gap:14px; --rail-n:3.3; --rail-k:3; } }
@container rail (min-width:740px){ .rail{ --rail-gap:16px; --rail-n:4.3; --rail-k:4; } }
@container rail (min-width:930px){ .rail{ --rail-gap:16px; --rail-n:5; --rail-k:4; } }
@container rail (min-width:1100px){ .rail{ --rail-gap:16px; --rail-n:6; --rail-k:5; } }
.rail{
  list-style:none; margin:-4px 0 -14px; padding:4px 0 14px;
  display:flex; gap:var(--rail-gap);
  overflow-x:auto; overscroll-behavior-x:contain;
  scroll-snap-type:x mandatory; scrollbar-width:none;
}
.rail::-webkit-scrollbar{ display:none; }
/* The side that has more cards fades out (site.js › rails sets the classes), so a
   prev/next button sits on a faded edge instead of on top of a sharp card. */
.rail{ --fade-l:0px; --fade-r:0px; }
.rail.can-prev{ --fade-l:44px; }
.rail.can-next{ --fade-r:44px; }
.rail.can-prev, .rail.can-next{
  -webkit-mask-image:linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
          mask-image:linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
}
.rail > li{
  flex:0 0 calc((100% - var(--rail-gap) * var(--rail-k)) / var(--rail-n));
  min-width:0; scroll-snap-align:start;
}
.rail-nav{
  position:absolute; top:calc(50% - 30px); z-index:2;
  display:grid; place-items:center;
  width:40px; height:40px; padding:0;
  color:var(--ink); background:var(--card);
  border:1px solid var(--line-strong); border-radius:50%;
  box-shadow:0 3px 0 var(--line-strong);
  cursor:pointer;
}
.rail-nav svg{ width:10px; height:16px; }
.rail-nav.prev{ left:-12px; }
.rail-nav.next{ right:-12px; }
.rail-nav:hover{ background:var(--bus); border-color:var(--bus-edge); box-shadow:0 3px 0 var(--bus-edge); }
.rail-nav[hidden]{ display:none; }
@media (hover:none){ .rail-nav{ display:none; } }

/* ---------------------------------------------------------------- top list */
/* Ranked like a race result: P1 to P10, filling the left column first. */
.top-list{ list-style:none; margin:0; padding:0; display:grid; gap:8px 16px; }
@media (min-width:760px){
  .top-list{ grid-template-columns:repeat(2,minmax(0,1fr)); grid-template-rows:repeat(5,auto); grid-auto-flow:column; }
}
.top-item{
  display:flex; align-items:center; gap:12px;
  height:100%; padding:8px 14px 8px 10px;
  color:var(--ink); text-decoration:none;
  background:var(--card); border:1px solid var(--line); border-radius:var(--radius);
}
.top-item:hover{ border-color:var(--line-strong); box-shadow:0 6px 16px -10px rgba(20,22,27,.45); }
.top-rank{
  flex:none; width:40px; text-align:right;
  font:700 26px/1 var(--f-display); font-variant-numeric:tabular-nums;
}
.top-rank span[aria-hidden]{ font:600 13px/1 var(--f-mono); color:var(--muted); margin-right:1px; vertical-align:4px; }
.top-thumb{
  position:relative; flex:none; display:grid; place-items:center;
  width:48px; height:48px; border-radius:8px; overflow:hidden;
  background:var(--asphalt-2);
}
.top-thumb img{ width:100%; height:100%; object-fit:cover; }
.top-thumb::after{ content:""; position:absolute; left:0; right:0; bottom:0; height:3px; background:var(--c1); }
.top-thumb .key{
  width:58%; min-width:0; height:auto; aspect-ratio:1/1; padding:0;
  font-size:14px; border-radius:5px; border-color:var(--c2); box-shadow:0 2px 0 var(--c2);
}
.top-text{ display:flex; flex-direction:column; gap:2px; min-width:0; }
.top-text b{ font:600 15px/1.25 var(--f-ui); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.top-text em{ font:400 13px/1.3 var(--f-ui); font-style:normal; color:var(--muted); }
.top-plays{
  margin-left:auto; flex:none; text-align:right;
  font:600 14px/1.1 var(--f-mono); font-variant-numeric:tabular-nums; color:var(--ink-soft);
}
.top-plays span{ display:block; font-weight:400; font-size:12px; color:var(--muted); }

/* ---------------------------------------------------------------- top racers */
/* Leaderboard rows share the P-rank of the top list, without thumbnails. */
.racer-list{ list-style:none; margin:0; padding:0; display:grid; gap:8px 16px; }
@media (min-width:760px){
  .racer-list{ grid-template-columns:repeat(2,minmax(0,1fr)); grid-template-rows:repeat(5,auto); grid-auto-flow:column; }
}
.racer-row{
  display:flex; align-items:center; gap:12px; min-height:52px; padding:8px 14px 8px 10px;
  background:var(--card); border:1px solid var(--line); border-radius:var(--radius);
}
.racer-list li:first-child{ border-color:var(--bus-edge); box-shadow:inset 4px 0 0 var(--bus); }
.racer-name{ min-width:0; font:600 15px/1.25 var(--f-ui); overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.racer-wpm{
  margin-left:auto; flex:none;
  font:700 22px/1 var(--f-display); font-variant-numeric:tabular-nums;
}
.racer-wpm span{ font:500 12px/1 var(--f-mono); color:var(--muted); }

/* ---------------------------------------------------------------- /leaderboard */
/* Same row look as .racer-row, but a real table (rank / racer / speed) with 50 lines. */
.board-actions{ display:flex; flex-wrap:wrap; align-items:center; gap:10px 16px; }
.board-count{ font:500 14px/1.3 var(--f-mono); color:var(--muted); }
.board-me{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 12px;
  max-width:640px; margin:16px 0 0; padding:12px 16px;
  background:var(--card); border:1px solid var(--bus-edge); border-radius:var(--radius);
  box-shadow:inset 4px 0 0 var(--bus);
}
.board-me[hidden]{ display:none; }
.board-me-label{ font:600 12px/1 var(--f-mono); text-transform:uppercase; letter-spacing:.06em; color:var(--muted); }
.board{ width:100%; max-width:760px; border-collapse:separate; border-spacing:0 8px; margin-top:-8px; }
.board thead th{ white-space:nowrap;
  padding:0 14px; text-align:left;
  font:600 12px/1 var(--f-mono); text-transform:uppercase; letter-spacing:.06em; color:var(--muted);
}
.board thead th:last-child{ text-align:right; }
.board tbody td, .board tbody th{
  padding:10px 14px; text-align:left; vertical-align:middle;
  background:var(--card); border-block:1px solid var(--line);
}
.board tbody td:first-child{ width:72px; border-left:1px solid var(--line); border-radius:var(--radius) 0 0 var(--radius); }
.board tbody td:last-child{ border-right:1px solid var(--line); border-radius:0 var(--radius) var(--radius) 0; text-align:right; white-space:nowrap; }
.board .top-rank{ width:auto; text-align:left; }
.board .racer-name{ max-width:0; width:100%; }
.board tr.is-podium .top-rank{ color:var(--bus-edge); }
.board tbody tr:first-child td:first-child{ box-shadow:inset 4px 0 0 var(--bus); }
.board tbody tr:first-child td, .board tbody tr:first-child th{ border-color:var(--bus-edge); }
.board tr.is-me td, .board tr.is-me th{ background:#FFF7DB; border-color:var(--bus-edge); }
@media (max-width:480px){
  .board tbody td, .board tbody th{ padding:8px 10px; }
  .board tbody td:first-child{ width:56px; }
  .board .top-rank{ font-size:22px; }
}
.board-how{ max-width:70ch; }

/* ---------------------------------------------------------------- recently played */
/* Placeholder cards hold the row's height until /recent-games.ajax answers
   (layout/section_recents.php), so nothing below jumps. */
.recents[hidden]{ display:none; }
.card.is-skeleton{ pointer-events:none; }
.card.is-skeleton .thumb{ background:var(--line); }
.card.is-skeleton .thumb::after{ display:none; }
.card.is-skeleton .card-title, .card.is-skeleton .card-meta{ border-radius:4px; background:var(--paper); color:transparent; }
.card.is-skeleton .card-meta{ width:60%; }
.recents-note, .list-lede{ margin:-6px 0 16px; max-width:70ch; color:var(--muted); font-size:15px; }
/* A button dressed as .section-link (font and colour come from that class). */
.recents-clear{ padding:0; background:none; border:0; cursor:pointer; }
.recents-clear[hidden]{ display:none; }

/* ---------------------------------------------------------------- ad slots */
/* Heights reserved at the largest creative per breakpoint (docs/PLAN.md 6.5),
   so pasting real ad code later shifts nothing below it. The dashed
   placeholder only renders on dev hosts (layout/section_ad.php). */
.ad-row{ padding-top:32px; }
.adslot, .adslot-live{ display:grid; place-items:center; }
.adslot{
  align-content:center; gap:4px; text-align:center;
  color:var(--muted); font:500 12px/1.3 var(--f-mono); letter-spacing:.04em;
  border:1px dashed var(--line-strong); border-radius:var(--radius);
}
.adslot b{ font-weight:600; text-transform:uppercase; }
.ad-billboard{ min-height:108px; }
.ad-rect{ min-height:258px; }
@media (min-width:760px){ .ad-billboard{ min-height:98px; } .ad-rect{ min-height:288px; } }
@media (min-width:1120px){ .ad-billboard{ min-height:258px; } }

/* ---------------------------------------------------------------- home prose + faq */
.home-prose{ display:grid; gap:12px 56px; grid-template-columns:minmax(0,1fr); padding-top:56px; }
@media (min-width:940px){
  .home-prose{ grid-template-columns:minmax(0,7fr) minmax(0,5fr); align-items:start; }
}
.home-prose .page-title{ margin-top:0; }
.home-prose .prose{ padding-top:0; }
.home-prose .prose ul, .home-prose .prose ol{ padding-left:1.2em; }
.home-faq .section-title{ font-size:26px; margin-bottom:10px; }
.faq details{ border-bottom:1px solid var(--line); }
.faq details:first-child{ border-top:1px solid var(--line); }
.faq summary{
  display:flex; justify-content:space-between; align-items:baseline; gap:16px;
  padding:14px 2px; cursor:pointer; list-style:none;
  font:600 16px/1.35 var(--f-ui);
}
.faq summary::-webkit-details-marker{ display:none; }
.faq summary::after{ content:"+"; flex:none; font:600 18px/1 var(--f-mono); color:var(--muted); }
.faq details[open] summary::after{ content:"\2212"; }
.faq summary:hover{ color:var(--lane); }
.faq-a{ padding:0 2px 16px; color:var(--ink-soft); }
.faq-a a{ color:var(--lane); }

/* ---------------------------------------------------------------- notice (404 etc.) */
.notice{ padding-block:72px 40px; text-align:center; }
.notice .key{ min-width:64px; height:64px; font-size:28px; margin-bottom:18px; }
.notice h1{ margin:0 0 8px; font:700 44px/1 var(--f-display); text-transform:uppercase; }
.notice p{ margin:0 auto 24px; max-width:44ch; color:var(--muted); }

/* ---------------------------------------------------------------- inner pages */
.crumbs{
  display:flex; flex-wrap:wrap; align-items:center; gap:6px;
  padding-top:18px; font-size:13px; color:var(--muted);
}
.crumbs a{ color:var(--ink-soft); text-decoration:none; }
.crumbs a:hover{ color:var(--lane); text-decoration:underline; }
.page-title{
  margin:10px 0 12px;
  font:700 clamp(36px,5vw,54px)/.95 var(--f-display);
  text-transform:uppercase; letter-spacing:.005em; text-wrap:balance;
}
.lede{ margin:0 0 16px; max-width:48ch; font-size:18px; line-height:1.5; color:var(--ink-soft); }
.status-pill{
  display:inline-block; padding:6px 9px 5px; border-radius:5px;
  font:600 12px/1 var(--f-mono); letter-spacing:.08em; text-transform:uppercase;
  background:var(--ink); color:var(--bus);
}
.chips{ list-style:none; margin:0 0 22px; padding:0; display:flex; flex-wrap:wrap; gap:8px; }
.chips li{
  display:inline-flex; align-items:center; gap:7px;
  padding:6px 12px; border-radius:999px;
  font-size:14px; background:var(--card); border:1px solid var(--line);
}
.chips .dot{ width:8px; height:8px; border-radius:2px; background:var(--c1); }
.soon-box{
  display:flex; flex-wrap:wrap; align-items:center; gap:14px 22px;
  padding:16px 18px; border-radius:var(--radius);
  background:#FFF7DA; border:1px solid #F1DC94;
}
.soon-box p{ margin:0; max-width:46ch; }

.game-hero{ display:grid; gap:24px; padding-top:16px; grid-template-columns:minmax(0,1fr); }
@media (min-width:760px){
  .game-hero{ grid-template-columns:minmax(0,5fr) minmax(0,7fr); align-items:center; gap:36px; }
}
.game-hero-art{ max-width:440px; border-radius:14px; overflow:hidden; }
.game-hero-art .thumb-track .key{ font-size:clamp(40px,7vw,72px); }

.prose{ max-width:70ch; padding-block:8px 16px; }
.prose p, .prose li{ color:var(--ink-soft); }
.prose h2{ margin:28px 0 8px; font:700 26px/1.1 var(--f-display); text-transform:uppercase; }

/* ---------------------------------------------------------------- hubs (P5) */
/* A hub tile: a coloured key with a short glyph, the hub name and its game count.
   --c1/--c2 come from \helper\hub::look(). Homepage (skills, grades) and group pages. */
.hub-tiles{
  list-style:none; margin:0; padding:0;
  display:grid; gap:10px; grid-template-columns:repeat(2,minmax(0,1fr));
}
@media (min-width:560px){ .hub-tiles{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (min-width:860px){ .hub-tiles{ grid-template-columns:repeat(5,minmax(0,1fr)); gap:14px; } }
.hub-tiles-big{ grid-template-columns:repeat(2,minmax(0,1fr)); }
@media (min-width:560px){ .hub-tiles-big{ grid-template-columns:repeat(3,minmax(0,1fr)); } }
@media (min-width:1000px){ .hub-tiles-big{ grid-template-columns:repeat(6,minmax(0,1fr)); } }
.hub-tile{
  display:grid; grid-template-columns:auto minmax(0,1fr);
  align-items:center; gap:2px 12px; height:100%;
  padding:12px 14px; border-radius:var(--radius);
  background:var(--card); border:1px solid var(--line); border-bottom:3px solid var(--c1);
  color:var(--ink); text-decoration:none;
  transition:transform .12s ease, border-color .12s ease;
}
.hub-tile:hover{ transform:translateY(-2px); border-color:var(--c2); }
.hub-tile:focus-visible{ outline:2px solid var(--lane); outline-offset:2px; }
.hub-tile .key{
  min-width:48px; height:42px; padding:0 8px; font-size:15px;
  background:var(--c1); border-color:var(--c2); box-shadow:0 3px 0 var(--c2); color:#14161B;
}
.hub-name{ font:600 15px/1.2 var(--f-ui); overflow-wrap:break-word; }
/* Two tiles a row on a phone leave ~85px for the name: "Punctuation" broke as "Punctuatio / n". */
@media (max-width:559px){
  .hub-tile{ gap:2px 8px; padding:10px; }
  .hub-tile .key{ min-width:36px; height:34px; padding:0 5px; font-size:12px; }
  .hub-name{ font-size:14px; hyphens:auto; }
}
.hub-tiles-big .hub-tile{ grid-template-columns:minmax(0,1fr); grid-template-rows:auto; justify-items:start; gap:8px; padding:16px; }
.hub-tiles-big .hub-tile .key{ grid-row:auto; min-width:64px; height:52px; font-size:20px; }
.hub-tiles-big .hub-name{ font:700 22px/1 var(--f-display); text-transform:uppercase; }

/* One-row scrollers with a hidden scrollbar (the skill chips, the header nav when
   narrow). site.js marks the side that has more to see: it fades out and, in a
   .strip box, gets an arrow button for mouse users. */
[data-strip]{ --fade-l:0px; --fade-r:0px; }
[data-strip].can-prev{ --fade-l:48px; }
[data-strip].can-next{ --fade-r:48px; }
[data-strip].can-prev, [data-strip].can-next{
  -webkit-mask-image:linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
          mask-image:linear-gradient(to right, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
}
[data-strip].is-dragging, [data-strip].is-dragging a{ cursor:grabbing; user-select:none; }
.strip{ position:relative; }
.strip-nav{
  position:absolute; top:14px; bottom:0; z-index:2; margin-block:auto;
  display:grid; place-items:center;
  width:32px; height:32px; padding:0;
  color:var(--ink); background:var(--card);
  border:1px solid var(--line-strong); border-radius:50%;
  box-shadow:0 2px 0 var(--line-strong); cursor:pointer;
}
.strip-nav svg{ width:8px; height:13px; }
.strip-nav.prev{ left:0; }
.strip-nav.next{ right:0; }
.strip-nav:hover{ background:var(--bus); border-color:var(--bus-edge); box-shadow:0 2px 0 var(--bus-edge); }
.strip-nav[hidden]{ display:none; }
@media (hover:none){ .strip-nav{ display:none; } }

/* Skill chips on the homepage: one row that scrolls when narrow. Kept a little
   tighter than the other chips so the skill hubs fit a full-width row. */
.hub-chips{ list-style:none; margin:0; padding:14px 0 0; display:flex; gap:6px; overflow-x:auto; scrollbar-width:none; }
.hub-chips::-webkit-scrollbar{ display:none; }
.hub-chips li{ flex:none; }
.hub-chips a, .game-hubs a, .relhubs a{
  display:inline-flex; align-items:center; gap:7px;
  padding:7px 12px; border-radius:999px;
  font-size:14px; color:var(--ink); text-decoration:none;
  background:var(--card); border:1px solid var(--line);
}
.hub-chips a:hover, .game-hubs a:hover, .relhubs a:hover{ border-color:var(--c2, var(--line-strong)); color:var(--lane); }
.hub-chips i, .game-hubs i, .relhubs i{ width:8px; height:8px; border-radius:2px; background:var(--c1); }
.game-hubs, .relhubs{ list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:8px; }
.hub-chips a{ padding-inline:11px; }
/* Tag chips (game page, "More tags"): a # instead of the colour square of a hub chip. */
.tag-chips a{ gap:3px; }
.tag-hash{ font:600 14px/1 var(--f-mono); color:var(--muted); }
.game-hubs + .tag-chips{ margin-top:8px; }
.tag-intro{ max-width:70ch; padding:0; }
.tag-intro p{ font-size:17px; }

/* Hub page */
.hub-head{ padding-top:6px; }
.hub-head .page-title{ margin-bottom:10px; }
.hub-head .lede{ max-width:62ch; font-size:17px; }
.hub-bar{ display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px; margin:0 0 14px; }
.hub-bar .section-title{ margin:0; }
.hub-bar label{ margin-left:auto; display:inline-flex; align-items:center; gap:8px; font-size:14px; color:var(--muted); }
.hub-bar select{
  padding:7px 30px 7px 10px; border:1px solid var(--line-strong); border-radius:8px;
  font:500 14px/1.2 var(--f-ui); color:var(--ink); background:var(--card);
}
/* Paged grids (layout/game_list.php): dimmed while site.js loads the next page in place. */
.game-list.is-loading{ opacity:.5; pointer-events:none; transition:opacity .15s ease; }
.pager{ display:flex; flex-wrap:wrap; justify-content:center; gap:6px; margin:22px 0 0; }
.pager a, .pager span{
  display:inline-grid; place-items:center; min-width:40px; height:40px; padding:0 12px;
  border:1px solid var(--line); border-radius:8px; background:var(--card);
  font:600 14px/1 var(--f-mono); color:var(--ink); text-decoration:none;
}
.pager a:hover{ border-color:var(--lane); color:var(--lane); }
.pager [aria-current]{ background:var(--ink); border-color:var(--ink); color:var(--bus); }
.hub-desc{ padding-top:24px; }

/* ---------------------------------------------------------------- footer */
.site-foot{ margin-top:56px; background:var(--card); border-top:1px solid var(--line); }
.foot-grid{
  display:grid; gap:28px 24px; padding-block:36px 28px;
  grid-template-columns:repeat(2,minmax(0,1fr));
}
.foot-brand{ grid-column:1 / -1; }
@media (min-width:860px){
  .foot-grid{ grid-template-columns:minmax(0,2fr) repeat(var(--cols,3),minmax(0,1fr)); }
  .foot-brand{ grid-column:auto; }
}
.foot-brand p{ margin:12px 0 0; max-width:38ch; color:var(--muted); font-size:14px; }
.foot-col h2{
  margin:0 0 12px;
  font:700 17px/1 var(--f-display); text-transform:uppercase; letter-spacing:.04em;
}
.foot-col ul{ list-style:none; margin:0; padding:0; display:grid; gap:9px; }
.foot-col a{ font-size:14px; color:var(--ink-soft); text-decoration:none; }
.foot-col a:hover{ color:var(--lane); text-decoration:underline; }
/* A heading with a URL in admin → Menu is a link; a group can hold several headed blocks. */
.foot-col h2 a{ font-size:inherit; color:var(--ink); }
.foot-col ul + h2{ margin-top:24px; }
.foot-links{ list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:6px 18px; }
.foot-links a{ color:var(--muted); text-decoration:none; }
.foot-links a:hover{ color:var(--lane); text-decoration:underline; }
.foot-bottom{
  display:flex; flex-wrap:wrap; justify-content:space-between; gap:8px 24px;
  padding-block:16px 22px; border-top:1px solid var(--line);
  font-size:13px; color:var(--muted);
}

@media (prefers-reduced-motion:reduce){
  .card,.btn{ transition:none; }
  .card:hover{ transform:none; }
}
