/* PolyBall's own dark palette and components. Since the v3 rebuild this styles one page,
   /polyball/leaderboard/, which keeps the game's look rather than the site's; the project page at
   /polyball/ is on the site shell (/site.css) with the five ring colours scoped into it. Since
   1 Oct 2026 the leaderboard wears that shell's header and status bar too, so /site.css loads first
   and this file keeps everything below them in the game's look.
   Rules of the system:
   - 90% ground + ink. Chroma is earned.
   - Cyan  = something you can press. Nothing else is cyan.
   - Gold  = the monthly cup (prizes, champions, rank 1). Nothing else is gold.
   - The five ring colours appear only as the "ring line" hairline and in the ring itself.
   - Mode colours appear only on mode things. */

@font-face{ font-family:"Chakra Petch"; font-weight:500; font-display:swap; src:url(/fonts/chakra-petch-500.woff2) format("woff2") }
@font-face{ font-family:"Chakra Petch"; font-weight:700; font-display:swap; src:url(/fonts/chakra-petch-700.woff2) format("woff2") }
@font-face{ font-family:"Nunito"; font-weight:200 1000; font-display:swap; src:url(/fonts/nunito-var.woff2) format("woff2") }

/* the shell under this file is light-dark(): pinned dark here, whatever theme another page saved */
:root,:root[data-theme]{ color-scheme:dark }
@supports not (color:light-dark(#000,#fff)){ :root{ --bg:#0A0B0F; --line:#23262E; --ink:#F4F4F0; --mid:#A8ADB8; --mut:#8B919E; --signal:#F5A524 } }
.top{ font-family:var(--sans) }   /* the shell's nav, not the game's Nunito */

:root{
  color-scheme:dark;
  --ground:#08090C; --raised:#0C0D12; --card:#11131A; --line:rgba(255,255,255,.08); --line-2:rgba(255,255,255,.14);
  --ink:#EDEEF2; --ink-2:#B4B9C6; --muted:#7C8396;
  --accent:#5AD1E6; --on-accent:#06222A;
  --gold:#FFC24B; --violet:#B48CFF; --ok:#5BD6A0; --danger:#FF5A5A;
  --r-green:#4BD86B; --r-cyan:#3FD0E0; --r-magenta:#F45CD0; --r-yellow:#FFD23F; --r-red:#FF5A5A;
  --m-classic:#5AD1E6; --m-music:#B06CFF; --m-time:#FFC24B; --m-zen:#5BD6A0; --m-remix:#FF7A9C;
  --ring-line:linear-gradient(90deg,var(--r-green),var(--r-cyan),var(--r-magenta),var(--r-yellow),var(--r-red));

  --display:"Chakra Petch","Noto Sans",system-ui,sans-serif;
  --body:"Nunito","Noto Sans",system-ui,sans-serif;
  /* type scale */
  --t-hero:clamp(2.5rem,6vw,5.25rem);   /* 40 → 84 */
  --t-h2:clamp(1.75rem,3.4vw,2.75rem);  /* 28 → 44 */
  --t-h3:1.375rem;                       /* 22 */
  --t-lead:clamp(1.0625rem,1.4vw,1.25rem);
  --t-body:1.0625rem;                    /* 17 */
  --t-small:.875rem;                     /* 14 */
  --t-eyebrow:.75rem;                    /* 12, caps */
  /* space scale: 4 8 12 16 24 32 48 64 96 128 */
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px; --s8:64px; --s9:96px; --s10:128px;
  --r-card:20px; --r-ctl:14px; --r-pill:999px;
  --ease:cubic-bezier(.2,.7,.2,1);
}

*{ box-sizing:border-box }
html{ scroll-behavior:smooth; -webkit-text-size-adjust:100% }
body{ margin:0; background:var(--ground); color:var(--ink); font:500 var(--t-body)/1.6 var(--body) }
img,svg,video{ display:block; max-width:100% }
img{ height:auto }
a{ color:var(--accent); text-underline-offset:3px }
h1,h2,h3{ font-family:var(--display); font-weight:700; margin:0; text-wrap:balance }
h1{ font-size:var(--t-hero); line-height:1.02; letter-spacing:-.015em }
h2{ font-size:var(--t-h2); line-height:1.1; letter-spacing:-.01em }
h3{ font-size:var(--t-h3); line-height:1.2 }
p{ margin:0; text-wrap:pretty }
section :focus-visible,.pb-foot :focus-visible{ outline:2px solid var(--accent); outline-offset:3px; border-radius:6px }   /* the shell's header and bar keep its amber ring */
.vh{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap }
.skip{ position:absolute; left:-999px } .skip:focus{ left:var(--s4); top:var(--s4); z-index:99; background:var(--accent); color:var(--on-accent); padding:var(--s3) var(--s4); border-radius:var(--r-ctl) }

/* The shell's column, so the page starts on the same left edge as the header and as /polyball/; the
   game's own 1160 px cap stays on what is inside it. */
section .wrap,.pb-foot .wrap{ width:min(100% - 2 * var(--pad),84rem); margin-inline:auto }
section .wrap>*{ max-width:1160px }
.section{ padding-block:clamp(64px,9vw,128px) }
.sec-head{ max-width:640px; margin-bottom:var(--s7) }
.sec-head p.lead{ margin-top:var(--s4) }
.eyebrow{ font:500 var(--t-eyebrow)/1 var(--display); letter-spacing:.16em; text-transform:uppercase; color:var(--muted); margin-bottom:var(--s4) }
.eyebrow.gold{ color:var(--gold) }
.lead{ font-size:var(--t-lead); color:var(--ink-2) }
.small{ font-size:var(--t-small); color:var(--muted) }
.ring-line{ height:2px; border:0; margin:0; background:var(--ring-line); opacity:.9 }

/* ---- mock ribbon ---- */

/* ---- buttons ---- */
.btn{ display:inline-flex; align-items:center; justify-content:center; gap:10px; min-height:52px; padding:0 26px; border-radius:var(--r-pill); border:0; cursor:pointer;
  font:700 1rem/1 var(--display); letter-spacing:.02em; text-decoration:none; transition:transform .18s var(--ease), box-shadow .18s var(--ease), background .18s }
.btn svg{ width:20px; height:20px; flex:none }
.btn-primary{ background:var(--accent); color:var(--on-accent); box-shadow:0 0 0 0 rgba(90,209,230,0), 0 10px 30px -10px rgba(90,209,230,.55) }
.btn-primary:hover{ background:var(--accent); color:var(--on-accent); transform:translateY(-2px); box-shadow:0 0 0 4px rgba(90,209,230,.18), 0 14px 34px -10px rgba(90,209,230,.7) }
.btn-ghost{ background:rgba(255,255,255,.04); color:var(--ink); box-shadow:inset 0 0 0 1px var(--line-2) }
.btn-ghost:hover{ background:rgba(255,255,255,.08) }
.btn-gold{ background:var(--gold); color:#2a1c00 }
.btn-sm{ min-height:44px; padding:0 18px; font-size:.9375rem }
.btn:active{ transform:translateY(0) scale(.98) }

/* ---- cards ---- */
.card{ background:var(--card); border:1px solid var(--line); border-radius:var(--r-card); padding:var(--s5) }
.grid{ display:grid; gap:var(--s4) }
.g3{ grid-template-columns:repeat(3,1fr) } .g4{ grid-template-columns:repeat(4,1fr) }
@media (max-width:900px){ .g3,.g4{ grid-template-columns:repeat(2,1fr) } }
@media (max-width:560px){ .g3,.g4{ grid-template-columns:1fr } }

/* ---- footer ---- */
.pb-foot{ border-top:1px solid var(--line); padding-block:var(--s7); color:var(--muted); font-size:var(--t-small) }
.pb-foot .wrap{ display:flex; flex-wrap:wrap; gap:var(--s4) var(--s6); align-items:center }
.pb-foot nav{ display:flex; flex-wrap:wrap; gap:var(--s2) var(--s5); margin-left:auto }
.pb-foot a{ color:var(--ink-2); padding-block:12px; display:inline-block }

/* =====================================================================
   PLAYER CARD: the shared identity unit. Same five fields drive the site
   and the in-game NamePlate: banner · plate (flair) · font · title · accent.
   All five are IDs from a whitelist, never free CSS from the wire.
   ===================================================================== */
.pcard{ position:relative; isolation:isolate; display:grid; grid-template-columns:auto 1fr auto auto; align-items:center; gap:var(--s4);
  min-height:76px; padding:10px var(--s4) 10px 10px; border-radius:18px; background:var(--card); border:1px solid var(--line); overflow:hidden;
  transition:transform .18s var(--ease), border-color .18s }
.pcard:hover{ transform:translateY(-2px); border-color:var(--line-2) }
.pcard::before{ content:""; position:absolute; inset:0; z-index:-1; background:var(--banner,none); opacity:.55;
  -webkit-mask-image:linear-gradient(90deg,#000 0,rgba(0,0,0,.55) 45%,transparent 85%); mask-image:linear-gradient(90deg,#000 0,rgba(0,0,0,.55) 45%,transparent 85%) }
.pcard .rank{ width:44px; text-align:center; font:700 1.125rem/1 var(--display); color:var(--muted) }
.pcard .who{ min-width:0 }
.pcard .score{ font:700 1.5rem/1 var(--display); font-variant-numeric:tabular-nums; min-width:72px; text-align:right; grid-column:-2 }   /* the last column even when the platform slot is empty */
.pcard .plat{ display:inline-flex; align-items:center; gap:6px; color:var(--muted); font:700 var(--t-eyebrow)/1 var(--display); letter-spacing:.08em; text-transform:uppercase }
/* the glyph carries the whole meaning on a phone (the label is hidden below 560px), so it sits a
   step brighter than its own caption: 9.4:1 on the card instead of the caption's 4.9:1 */
.pcard .plat svg{ width:20px; height:20px; color:var(--ink-2) }
/* rows from a client that never sent a platform render an empty span: collapse it so the
   card looks exactly as it did before the column existed */
.pcard .plat:empty{ display:none }
@media (max-width:560px){ .pcard{ gap:var(--s2); padding-right:var(--s3) } .pcard .plat span{ display:none } .pcard .rank{ width:32px } .pcard .score{ font-size:1.25rem; min-width:56px } }

.plate{ position:relative; display:inline-flex; flex-direction:column; justify-content:center; max-width:100%; min-height:54px; padding:8px 18px; border-radius:14px }
.plate .nm{ font:700 1.25rem/1.15 var(--body); color:var(--ink); white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
.plate .ti{ font:700 .8125rem/1.2 var(--body); color:var(--tone,var(--accent)); margin-top:2px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis }
@media (max-width:560px){ .plate{ padding:6px 12px } .plate .nm{ font-size:1.0625rem } }
/* plate frames (ids match the game's flair ids). The whole card wears its player's plate
   (owner, 2026-10-06: "the highlight must span the full row width, not just the name"), so
   a frame is a set of values the card uses: fill, ring (the card's own 1px border, recoloured),
   and a glow drawn INSIDE (an outer one bled between rows 8px apart). The name keeps what is
   the name's: its font, slant and spacing (nf-*) and the title colour. Fills are 180deg on
   purpose: a vertical gradient survives a 1160px row, a keyword angle would not. */
[data-plate]{ background:var(--plate-scrim,linear-gradient(transparent,transparent)),var(--plate-bg); background-color:var(--card);
  border-color:var(--plate-ring); box-shadow:inset 0 0 0 3.5px var(--plate-glow); --lb-muted:#B8C0CA }
[data-plate]:hover{ border-color:var(--plate-ring) }
[data-plate]::before{ display:none }   /* the plate replaces the banner layer under it */
[data-plate] .rank,[data-plate] .plat{ color:var(--lb-muted) }   /* ~6:1 on the lightest fill, the card's grey was ~3.5:1 */
[data-plate="slate"]  { --plate-bg:linear-gradient(180deg,#262B38,#12141C); --plate-ring:rgba(255,255,255,.9);  --plate-glow:rgba(255,255,255,.06) }
[data-plate="neon"]   { --plate-bg:linear-gradient(180deg,#102E3C,#0A1217); --plate-ring:rgba(90,209,230,.95);  --plate-glow:rgba(90,209,230,.28) }
[data-plate="circuit"]{ --plate-bg:linear-gradient(180deg,#0F2117,#08120D); --plate-ring:rgba(75,216,107,.85);  --plate-glow:rgba(75,216,107,.20) }
[data-plate="frost"]  { --plate-bg:linear-gradient(180deg,#2A3C4D,#0D141C); --plate-ring:rgba(191,232,255,.9);  --plate-glow:rgba(191,232,255,.24) }
[data-plate="gilded"] { --plate-bg:linear-gradient(180deg,#382B0F,#170F05); --plate-ring:rgb(255,214,102);      --plate-glow:rgba(255,214,102,.26) }
[data-plate="ember"]  { --plate-bg:linear-gradient(180deg,#2E120A,#421708); --plate-ring:rgba(255,122,58,.95);  --plate-glow:rgba(255,122,58,.26) }
[data-plate="bloom"]  { --plate-bg:linear-gradient(180deg,#331724,#170A12); --plate-ring:rgba(245,143,168,.9);  --plate-glow:rgba(245,143,168,.24) }
/* void's stars tile at a fixed density in the bands between the edge (ring 1px + glow 3.5px, plus 4)
   and the words, four layers at their own heights and tile widths so no two line up into stitching:
   two dots stretched over a 1160px row read as dust, not as a sky */
[data-plate="void"]   { --plate-bg:radial-gradient(circle at 11px 9px,rgba(255,255,255,.6) 0 1.1px,transparent 1.6px) 0 0/97px 100% repeat-x,
                          radial-gradient(circle at 40px 14px,rgba(255,255,255,.35) 0 .8px,transparent 1.2px) 0 0/61px 100% repeat-x,
                          radial-gradient(circle at 47px calc(100% - 10px),rgba(255,255,255,.45) 0 .9px,transparent 1.4px) 0 0/71px 100% repeat-x,
                          radial-gradient(circle at 23px calc(100% - 15px),rgba(255,255,255,.3) 0 .8px,transparent 1.2px) 0 0/53px 100% repeat-x,
                          linear-gradient(180deg,#171028,#07050E);
                        --plate-ring:rgba(180,140,255,.9); --plate-glow:rgba(180,140,255,.22) }
[data-plate="carbon"] { --plate-bg:repeating-linear-gradient(45deg,rgba(255,255,255,.05) 0 1px,transparent 1px 3.5px),linear-gradient(180deg,#212429,#0F0F14);
                        --plate-ring:rgba(191,199,217,.85); --plate-glow:rgba(191,199,217,.10) }
/* Holo across a whole row was too loud: the fill holds still (one static sweep of hues under a
   dark scrim) and only the ring and the inner glow turn. Never hue-rotate the row itself: it would
   turn the gold score and the cyan title with it. */
@property --plate-h{ syntax:'<angle>'; inherits:true; initial-value:0deg }
[data-plate="holo"]   { --plate-bg:linear-gradient(90deg,hsl(0 50% 60% / .26),hsl(60 50% 60% / .26),hsl(120 50% 60% / .26),hsl(180 50% 60% / .26),hsl(240 50% 60% / .26),hsl(300 50% 60% / .26),hsl(360 50% 60% / .26));
                        --plate-scrim:linear-gradient(rgb(0 0 0 / .35),rgb(0 0 0 / .35));
                        --plate-ring:oklch(.82 .14 var(--plate-h)); --plate-glow:oklch(.82 .14 var(--plate-h) / .22); animation:holo-h 8s linear infinite }
@keyframes holo-h{ to{ --plate-h:360deg } }
/* banners (NEW cosmetic slot) */
.b-aurora { --banner:linear-gradient(100deg,#0e5a6b,#3b2a7a 60%,#7a2a6b) }
.b-sunset { --banner:linear-gradient(100deg,#7a4a0e,#8a2a4a 70%) }
.b-grid   { --banner:repeating-linear-gradient(0deg,rgba(90,209,230,.22) 0 1px,transparent 1px 14px),repeating-linear-gradient(90deg,rgba(90,209,230,.22) 0 1px,transparent 1px 14px),linear-gradient(90deg,#0b2a33,#0b1220) }
.b-waves  { --banner:repeating-radial-gradient(circle at 0 120%,rgba(91,214,160,.28) 0 2px,transparent 2px 16px),linear-gradient(90deg,#0d2a20,#0b1220) }
.b-stripes{ --banner:repeating-linear-gradient(115deg,rgba(244,92,208,.26) 0 10px,transparent 10px 22px),linear-gradient(90deg,#2a0f26,#0b1220) }
.b-champion{ --banner:linear-gradient(100deg,#7a5a0e,#c9962b 35%,#5a3d08 70%) }
/* name fonts (ids match the game's font ids) */
.nf-heavy .nm{ font-weight:900 } .nf-wide .nm{ letter-spacing:.2em; font-size:1.0625rem }
.nf-chakra .nm,.nf-chakra .ti{ font-family:var(--display) } .nf-slant .nm,.nf-slant .ti{ transform:skewX(-12deg); transform-origin:left }
/* accent tones for the title line */
.t-gold{ --tone:var(--gold) } .t-violet{ --tone:var(--violet) } .t-green{ --tone:var(--ok) } .t-red{ --tone:var(--danger) } .t-cyan{ --tone:var(--accent) }

@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto }
  *,*::before,*::after{ animation-duration:.01ms !important; transition-duration:.01ms !important }
}

@media (prefers-reduced-motion:reduce){ [data-plate="holo"]{ animation:none } }
