/* ============================================================
   LIMITLESS LABS · v3 (SS-44 consistency pass on top of v2)
   one edge · one 8px spacing scale · type set by role
   Chakra Petch (headings, numbers) · Inter (text, buttons) ·
   JetBrains Mono (labels)
   ============================================================ */
:root{color-scheme:dark;
  --bg:#04070F; --panel:#0A111E; --panel-2:#101B2E; --ink:#E9F3FD;
  --dim:#98AAC6; --faint:#7285A9; --line:#172341; --line-2:#27395A;
  --p:#2AC0FF; --o:#24D6BA; --win:#37E07E; --gold:#8FF0E6;
  --grad:linear-gradient(100deg,#24D6BA,#2AC0FF 45%,#1E7BE0 76%,#0B3A96);
  --disp:"Chakra Petch",system-ui,sans-serif; --ui:"Inter",system-ui,sans-serif;
  --mono:"JetBrains Mono",ui-monospace,monospace;
  --ease:cubic-bezier(.2,.7,.2,1);

  /* ── SPACING · the only numbers allowed ──────────────────────
     Client (SS-44): one scale in 8px steps, nothing off it. Every
     padding / margin / gap / offset in this file is one of these.
     The scale AUTOSCALES IN STEPS, never fluidly: on big panels the
     whole ladder moves up a notch (see the tiers below), so a 16px
     gap becomes 24px — never 19.4px. */
  --s1:4px; --s2:8px; --s3:16px; --s4:24px; --s5:32px;
  --s6:48px; --s7:64px; --s8:96px; --s9:128px; --s10:160px;

  /* ── role spacing: chosen per breakpoint, always a scale step ──
     --edge    the ONE page edge: logo, h1, every section head, the
               carousel's first card, the footer and the live-bets
               dock all sit on it. Only imagery and hairlines bleed.
     --section vertical rhythm of every section (hero → games → wins…)
     --gap     between cards / columns
     --hgap    section headline → its content */
  --edge-base:16px; --section:32px; --gap:16px; --hgap:24px;
  --edge:var(--edge-base);

  /* legacy names, kept as aliases so nothing can drift off the edge */
  --edge-bar:var(--edge); --gut:var(--edge); --pad:var(--edge);
  --wide:calc(100vw - 2 * var(--edge));
  --cgap:var(--gap); --sec:var(--section);
  --barpy:var(--s2);
  --dockb:var(--s3);
  --navpx:var(--s3); --navpy:var(--s2); --navgap:var(--s2);

  /* ── TYPE · set by role, not by place (client's table) ───────
     fluid roles use the client's own ranges; --dscale is the optical
     correction the font picker sets for the display face. */
  --dscale:1;
  --t-display:calc(clamp(48px,5.6vw,104px) * var(--dscale)); /* hero headline, one per page */
  --t-h2:calc(clamp(40px,4.8vw,80px) * var(--dscale));       /* section headlines */
  --t-h3:calc(clamp(22px,1.7vw,28px) * var(--dscale));       /* card & item titles */
  --t-stat:calc(clamp(28px,2.5vw,40px) * var(--dscale));     /* numbers that matter */
  --t-lead:clamp(17px,1.25vw,20px);                          /* intro paragraph */
  --t-body:15px;                                             /* everything you read */
  --t-small:13px;                                            /* secondary text, nav */
  --t-nav:13px;                                              /* primary navigation */
  --t-btn:12px;                                              /* every button */
  --t-label:11px;                                            /* tags, meta keys, table heads */
  --track-label:.14em; --track-btn:.14em;

  /* ── radii: the corner style stays, the values line up ── */
  --r-sm:8px; --r:12px; --r-lg:16px;
}
/* ── stepped autoscaling ─────────────────────────────────────────
   Width tiers only ever swap a token for another scale step.
   --section is the padding on EVERY section, top and bottom, so the gap
   a reader sees between two sections is twice it. Pulled in three times on
   the client's word (06.10, then twice on 07.10): 64/96/128 → 48/64/96 →
   40/56/80 → the ramp below.
   It is now 32 all the way to 1919, then 40, then 56 — a boundary of
   64 / 80 / 112px. The 640 and 1024 tiers no longer touch it at all: the
   second pass only lowered the 1024 rung, which left 800-1023px sitting on
   48 while 1200px sat on 40, so a tablet had MORE air between sections than
   a desktop. The ramp has to stay monotonic. */
@media(min-width:640px){:root{--edge-base:32px}}
@media(min-width:1024px){:root{--edge-base:48px;--gap:24px}}
@media(min-width:1280px){:root{--edge-base:64px;--hgap:32px}}
@media(min-width:1920px){:root{--edge-base:96px;--section:40px;--gap:32px;--hgap:48px;
  --t-display:calc(clamp(48px,5.6vw,120px) * var(--dscale));--t-h2:calc(clamp(40px,4.6vw,96px) * var(--dscale));
  --t-h3:calc(clamp(22px,1.6vw,32px) * var(--dscale));--t-stat:calc(clamp(28px,2.4vw,48px) * var(--dscale));
  --t-lead:20px;--t-body:16px;--t-small:14px;--t-nav:14px;--t-btn:13px;--t-label:12px}}
/* from 2560 the whole ladder moves up one notch, from 3200 two */
@media(min-width:2560px){:root{--edge-base:128px;--section:56px;--gap:48px;--hgap:64px;
  --s1:8px;--s2:16px;--s3:24px;--s4:32px;--s5:48px;--s6:64px;--s7:96px;--s8:128px;--s9:160px;
  --t-display:calc(clamp(48px,5.6vw,144px) * var(--dscale));--t-h2:calc(clamp(40px,4.6vw,120px) * var(--dscale));
  --t-h3:calc(clamp(22px,1.6vw,40px) * var(--dscale));--t-stat:calc(clamp(28px,2.4vw,60px) * var(--dscale));
  --t-lead:24px;--t-body:18px;--t-small:16px;--t-nav:16px;--t-btn:15px;--t-label:14px;
  --r-sm:12px;--r:16px;--r-lg:24px}}
@media(min-width:3200px){:root{--edge-base:160px;
  --s1:16px;--s2:24px;--s3:32px;--s4:48px;--s5:64px;--s6:96px;--s7:128px;--s8:160px;
  --t-display:calc(clamp(48px,5.6vw,176px) * var(--dscale));--t-h2:calc(clamp(40px,4.6vw,144px) * var(--dscale));
  --t-h3:calc(clamp(22px,1.6vw,48px) * var(--dscale));--t-stat:calc(clamp(28px,2.4vw,72px) * var(--dscale));
  --t-lead:28px;--t-body:20px;--t-small:18px;--t-nav:18px;--t-btn:17px;--t-label:16px}}
*{margin:0;padding:0;box-sizing:border-box}
html,body{overflow-x:clip}
/* системну смугу прокрутки сторінки не показуємо; сам скрол лишається робочим */
html{scrollbar-width:none;-ms-overflow-style:none}
html::-webkit-scrollbar,body::-webkit-scrollbar{width:0;height:0;display:none}
/* липкий хедер накривав ціль будь-якого якоря: перехід на #games клав
   заголовок "Our games" на y=36 під 61-піксельну шапку. --barh міряється
   в JS на кожній сторінці, тож відступ їде разом із тірами. */
html{scroll-behavior:smooth;scroll-padding-top:calc(var(--barh,var(--s7)) + var(--s3))}
@media(prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
body{background:var(--bg);color:var(--ink);font-family:var(--ui);font-size:var(--t-body);line-height:1.5;-webkit-font-smoothing:antialiased}
body::before{content:"";position:fixed;inset:0;z-index:-1;pointer-events:none;
  background:radial-gradient(900px 560px at 88% -8%,rgba(42,192,255,.16),transparent 60%),radial-gradient(700px 500px at -6% 8%,rgba(36,214,186,.09),transparent 58%),var(--bg)}
a{color:inherit;text-decoration:none}
button{font:inherit;cursor:pointer;background:none;border:none;color:inherit}
.r{text-align:right}.mut{color:var(--dim)}.hide-s{}
::selection{background:var(--p);color:#02101C}
:focus-visible{outline:2px solid var(--p);outline-offset:2px}

.btn{display:inline-flex;align-items:center;justify-content:center;gap:var(--s2);font-weight:600;font-size:var(--t-btn);letter-spacing:var(--track-btn);text-transform:uppercase;height:var(--s6);padding:0 var(--s4);border-radius:var(--r);border:1px solid transparent;white-space:nowrap;transition:.14s;line-height:1}
.btn.sm{height:40px;padding:0 var(--s3);font-size:var(--t-btn)}
.btn-p{background:var(--p);color:#fff}
.btn-p:hover{filter:brightness(1.08)}
.btn-o{border-color:var(--line-2);color:var(--ink)}
.btn-o:hover{border-color:var(--p);color:var(--p)}
.skip{position:absolute;left:-999px;top:0;z-index:200;background:var(--p);color:#fff;padding:var(--s2) var(--s3);border-radius:8px;font-weight:700}
.skip:focus{left:var(--s2);top:var(--s2)}

.brand{display:inline-flex;align-items:center;gap:var(--s2)}
/* the lockup owns the header line (client: maximize the logo to the bar) */
.brand-logo{height:var(--s6);width:auto;display:block;flex:none}
/* the footer lockup matches the header one — 24px read as an afterthought */
.foot-l .brand-logo{height:var(--s6)}
.brand-txt{font-family:var(--disp);font-weight:700;font-size:var(--t-lead);letter-spacing:-.01em}
.brand-txt b{color:var(--p)}

/* ── рідина в колбі · v3 ─────────────────────────────────────
   Та сама рідина, що й у "Lab." героя: пологa хвиля (довжина 60,
   гребінь 3 одиниці замість колишніх 12 на 44 — звідси й "каряво"),
   яка повільно пливе вбік, і один раз наливається знизу при завантаженні
   з тим самим таймінгом, що й labfill. Кліп висить на ЗОВНІШНІЙ групі,
   а рух — на внутрішній: інакше transform тягнув би за собою і кліп. */
.flask-wave{animation:flask-drift 4s linear infinite}
.flask{animation:flask-rise 2.6s var(--ease) .6s both}
@keyframes flask-drift{to{transform:translateX(-60px)}}
@keyframes flask-rise{from{transform:translateY(40px)}to{transform:none}}
.foot-l .flask,.foot-l .flask-wave{animation:none}
@media(prefers-reduced-motion:reduce){.flask-wave,.flask{animation:none}}

/* ── header ── */
/* ── utility strip (from the client's mockup) ─────────────────
   Status and compliance live in a thin strip above the bar, so the bar
   carries only logo / nav / CTA. Same edge and the same stepped tokens
   as everything else: height --s5 (32 → 48 → 64 on big panels), text in
   the label role. It scrolls away; the bar below stays sticky. */
/* every label in the strip sits on its vertical centre (client 06.10: the
   words hung 8px from the top and 16 from the bottom, the font pill
   touched the top). All labels share one size, so centred boxes still
   share one baseline. */
.util{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  height:var(--s5);padding:0 var(--edge);border-bottom:1px solid var(--line);
  font-family:var(--mono);font-size:var(--t-label);font-weight:500;letter-spacing:var(--track-label);
  text-transform:uppercase;color:var(--faint);white-space:nowrap}
.util-r{display:flex;align-items:center;gap:var(--s4)}
/* the labels' boxes are trimmed to their caps, so centring the box centres
   the letters themselves at every size (the font pill keeps its own box) */
.util-l,.util-r>:not(.fontpick-slot){text-box:trim-both cap alphabetic}
/* with Discord beside X the strip outgrew tablets (it already ran 23px
   past a 768 screen): the warning tail goes first — the footer carries
   it in full — then the Grid toggle */
.fontpick-slot:empty{display:none}
@media(max-width:1099px){.util-l .hide-s{display:none}}
@media(max-width:699px){.util-grid{display:none}}
.util a:hover{color:var(--ink)}
.util-play b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
/* the dot centres on the caps (JetBrains Mono cap height = .73em) */
.util-play i{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--win);
  margin-right:var(--s2);vertical-align:calc((.73em - 8px) / 2);box-shadow:0 0 0 3px rgba(55,224,126,.18);animation:util-pulse 2s infinite}
@keyframes util-pulse{50%{box-shadow:0 0 0 6px rgba(55,224,126,0)}}
.util-grid{font:inherit;letter-spacing:inherit;text-transform:inherit;color:var(--p)}
.util-grid[aria-pressed="true"]{color:var(--ink)}
@media(prefers-reduced-motion:reduce){.util-play i{animation:none}}
body.onescreen>.util{flex:0 0 auto}
/* the font picker is a review tool, so it lives in the strip, not the bar:
   a compact white pill, 24px tall, in the label type of the strip */
.util .fontpick{height:var(--s4);padding:0 var(--s2);gap:var(--s2);font-size:var(--t-label);letter-spacing:0;text-transform:none;font-family:var(--ui)}
.util .fontpick:hover{transform:none}
/* [ Grid · G ] — the mockup's 12-column overlay, laid on the same --edge
   and --gap as the page, so every block can be checked against it. */
/* ── one line per row ────────────────────────────────────────
   Client 02.10: a ruler laid under a row must be straight.
   · text beside text (a headline and its side label, RTP and 96.7%, nav
     and CTA label, footer) stands on ONE baseline — align-items:baseline;
   · anything beside a headline (the filters and arrows next to "Our
     games", "Live from Stake", the drop-dates form, the button in the
     game-page band) stands with its bottom edge ON the headline's baseline
     — one rule for every row (client 05.10). The h2 box is trimmed to
     cap-height … baseline, so "the bottom of the h2" IS its baseline and
     align-items:flex-end does the rest. */
.games-head h2,.wins-head h2,.sec2 h2,.notify-sec h2,.cta-band h2{text-box:trim-both cap alphabetic}
/* a label beside a headline: its box is trimmed to its letters too, so its
   baseline stands on the headline's — the same in every browser
   (Safari rounded the shared-baseline version 1px high) */
.wins-head .mut{text-box:trim-both cap alphabetic}
.gridlines{position:fixed;inset:0;z-index:998;pointer-events:none;display:none;padding-inline:var(--edge)}
.gridlines div{height:100%;display:grid;grid-template-columns:repeat(12,1fr);gap:var(--gap)}
.gridlines span{background:rgba(42,192,255,.07);border-inline:1px solid rgba(42,192,255,.25)}
.show-grid .gridlines{display:block}

/* 1fr auto 1fr keeps the nav centred on the PAGE, not between neighbours
   of unequal width (it used to sit slightly left of centre) */
.bar{position:sticky;top:0;z-index:100;display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:var(--s3);padding:var(--barpy) var(--edge-bar);border-bottom:1px solid var(--line);background:rgba(4,7,15,.88);backdrop-filter:blur(12px)}
.bar .brand{justify-self:start}
/* the bar is geometry first: logo, nav and CTA share one vertical centre.
   Nav links are as tall as the CTA (40px) so their words and its label sit
   on the same centre line too. */
.nav a{display:inline-flex;align-items:center;height:40px;padding-block:0}
/* footer: nav and the right-hand line share a baseline; their line box is
   as tall as the logo (--s6), so the words still sit centred against it */
.footer .foot-nav,.footer .foot-r{align-self:baseline;line-height:var(--s6)}
.nav{display:flex;gap:var(--navgap);justify-self:center}
.nav a{font-size:var(--t-nav);font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--dim);padding:var(--navpy) var(--navpx);border-radius:var(--r-sm);transition:.14s}
.nav a:hover{color:var(--ink);background:var(--panel-2)}
.bar-r{display:flex;align-items:center;gap:var(--s3);justify-self:end}
/* header and footer nav on the page grid (client 06.10: the header's and
   the footer's links sat under different columns). Both navs are four
   columns wide, centred on the page — columns 5–8 — and split into three
   equal cells; each link is centred in its cell, so the n-th header link
   and the n-th footer link share one axis.
   Was six columns (4–9) until 07.10 — the client wanted the links closer
   together. Four is the next width that still centres symmetrically on a
   12-column grid, so the shared axes survive the change.
   Column width comes from the bar / footer's content box (cqi — already
   inside the --edge padding), so a classic scrollbar can't shift it. */
/* логотип і Play on Stake стоять на --edge, як усе інше: смужка 18+ згори,
   заголовки секцій, логотип і лінія в підвалі. Був крок назовні на --s5
   (клієнт 06.10: "лого трохи лівіше, кнопку трохи правіше", потім "більше"),
   але на сітці вони єдині вилазили за лінію — знято 06.10 увечері. */
@media(min-width:1001px){
  .bar,footer.footer{container-type:inline-size;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr)}
  .bar .nav,.footer .foot-nav{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));column-gap:var(--gap);justify-items:center;
    width:calc((100cqi - 11 * var(--gap)) / 12 * 4 + 3 * var(--gap))}
}
/* below ~1200 the footer's right-hand line (Responsible play · 18+ · ©)
   reaches into the nav's last cell: logo and that line share the first
   row, the nav takes its own row — same cells, same axes as the header */
@media(min-width:1001px) and (max-width:1199px){
  footer.footer{grid-template-columns:minmax(0,1fr) minmax(0,1fr);row-gap:var(--s4)}
  .footer .foot-l{grid-area:1/1}
  .footer .foot-r{grid-area:1/2}
  .footer .foot-nav{grid-area:2/1/3/3;justify-self:center}
}
/* ── Play on Stake · v3 ──────────────────────────────────────
   Колба замість звичайної кнопки (макет клієнта v3): трапеція з вузьким
   верхом, тверда тінь-зсув, а всередині хвиля кольору тексту, яка на
   ховері заливає кнопку доверху. Висота 40 — на сітці. */
.trap{--slant:var(--s3);--cr:var(--s2);--cx:2.97px;--cy:7.43px;display:inline-block;flex:none;filter:drop-shadow(4px 4px 0 var(--ink));
  transition:transform .25s var(--ease),filter .25s var(--ease)}
.trap-in{position:relative;isolation:isolate;overflow:hidden;display:inline-flex;align-items:center;gap:var(--s3);
  height:40px;padding-inline:var(--s6);
  font:600 var(--t-btn)/1 var(--ui);letter-spacing:var(--track-btn);text-transform:uppercase;white-space:nowrap;
  background:var(--p);color:#02101C;
  clip-path:polygon(var(--slant) 0,calc(100% - var(--slant)) 0,100% 100%,0 100%)}
/* rounded corners: shape() lets every corner of the trapezoid curve by
   --cr (8px). --cx/--cy are that 8px measured along the slanted side
   (slant 16 on a 40px height → 2.97 / 7.43). Browsers without shape()
   keep the sharp polygon above. The drop-shadow follows the clip, so it
   rounds with it. */
@supports (clip-path:shape(from 0 0,line to 1px 1px,close)){
  .trap-in{clip-path:shape(from calc(var(--slant) + var(--cr)) 0,
    hline to calc(100% - var(--slant) - var(--cr)),
    curve to calc(100% - var(--slant) + var(--cx)) var(--cy) with calc(100% - var(--slant)) 0,
    line to calc(100% - var(--cx)) calc(100% - var(--cy)),
    curve to calc(100% - var(--cr)) 100% with 100% 100%,
    hline to var(--cr),
    curve to var(--cx) calc(100% - var(--cy)) with 0 100%,
    line to calc(var(--slant) - var(--cx)) var(--cy),
    curve to calc(var(--slant) + var(--cr)) 0 with var(--slant) 0,
    close)}
}
.trap-in::before{content:"";position:absolute;inset:0;z-index:-1;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 960 240' preserveAspectRatio='none'%3E%3Cpath d='M0 120 Q30 104 60 120 T120 120 T180 120 T240 120 T300 120 T360 120 T420 120 T480 120 T540 120 T600 120 T660 120 T720 120 T780 120 T840 120 T900 120 T960 120 V240 H0Z' fill='%23E9F3FD'/%3E%3C/svg%3E") repeat-x,
    linear-gradient(transparent 55%,var(--ink) 55%) no-repeat;
  background-size:calc(var(--s6) * 8) 200%,100% 200%;background-position:calc(var(--s6) * -1) -20%,0 -20%;
  transition:background-position-y .5s var(--ease);animation:trapwave 1.4s linear infinite}
@keyframes trapwave{from{background-position-x:calc(var(--s6) * -1),0}to{background-position-x:0,0}}
.trap .arr{transition:transform .25s var(--ease)}
.trap:hover{transform:translate(-2px,-2px);filter:drop-shadow(6px 6px 0 var(--ink))}
.trap:hover .trap-in::before{background-position-y:100%}
.trap:hover .arr{transform:translateX(var(--s1))}
.trap:active{transform:translate(2px,2px);filter:drop-shadow(2px 2px 0 var(--ink))}
.trap:focus-visible{outline:none}
.trap:focus-visible .trap-in{background:var(--ink)}
@media(prefers-reduced-motion:reduce){.trap-in::before{animation:none}}
.burger{display:none;font-size:var(--t-lead);border:1px solid var(--line-2);border-radius:var(--r-sm);width:40px;height:40px}

.takeover{position:fixed;inset:0;z-index:150;background:rgba(3,6,12,.97);backdrop-filter:blur(10px);display:none;flex-direction:column;justify-content:center;gap:var(--s2);padding:var(--pad)}
.takeover.on{display:flex}
.takeover a{font-family:var(--disp);font-weight:700;font-size:var(--t-h2);padding:var(--s2) 0;border-bottom:1px solid var(--line)}
.takeover a.trap{align-self:start;margin-top:var(--s5);padding:0;border-bottom:0;font-size:inherit}
/* хрестик стоїть РІВНО там, де стояв бургер. Було top:18/right:18 проти
   шапчиних --barpy/--edge — іконка стрибала на 4px ліворуч і 10px вниз
   щоразу при відкритті меню. Тепер обидва читають ті самі токени, тож
   розійтись не можуть. Розмір теж спільний — див. .burger,.takeover .close */
.takeover .close{position:absolute;top:var(--barpy);right:var(--edge-bar);font-size:var(--t-lead);
  border:1px solid var(--line-2);border-radius:var(--r-sm);width:40px;height:40px}

/* ── hero ── */
/* ── hero · v3 ───────────────────────────────────────────────
   Client (SS-44): too much empty space above the headline and between
   the hero and Our games, too little between the headline and the
   buttons. The hero used to fill the viewport and centre itself, so
   every gap grew with the screen height. Now its height is its content:
   one --s6 above, the section rhythm below (Our games adds none of its
   own), --s6 from headline to buttons and from buttons to the stats.
   Client 05.10: every section boundary on the home page is the game
   page's step — --section + --section — so Our games carries its own
   top half again. No hairlines between sections (client 06.10). */
/* the hero sits on the 12-column grid ([ Grid · G ]): copy on columns
   1–7, the featured game on 8–12, exactly as in the client's mockup */
.hero{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--gap);row-gap:var(--s7);align-items:center;
  padding:var(--s6) var(--edge) var(--section)}
.hero-copy{grid-column:1/8;min-width:0}
.hero-feat{grid-column:8/13}
.eyebrow{display:inline-flex;align-items:center;gap:var(--s2);font-size:var(--t-small);font-weight:600;letter-spacing:.02em;color:var(--dim)}
.eyebrow i{width:7px;height:7px;border-radius:50%;background:var(--p);box-shadow:0 0 8px var(--p)}
.hero h1{font-family:var(--disp);font-weight:700;font-size:var(--t-display);line-height:.98;letter-spacing:-.03em;margin:0 0 var(--s6)}
.hero h1 .grad,.chero h1 .grad{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent}
/* ── "Lab." · v3 ─────────────────────────────────────────────
   the word is a flask: a hairline outline that fills with liquid
   (2.6s pour, then the surface keeps drifting). Same wave as the
   logo flask and the Play on Stake button. While the headline decode
   runs (.decoding, set in app.js) it waits as an empty outline — the
   decode re-creates this span when it ends, and a pour that restarted
   mid-way would read as a glitch.
   The wave is a repeating tile, and while it drifts the tile edges land
   on fractional pixels and anti-alias into faint vertical lines. So the
   tile only draws the crest: a solid layer of the same height rides the
   same y-position underneath and carries the body of the liquid. */
.lab-word{color:transparent;-webkit-text-stroke:1.5px var(--p);padding-right:var(--s1)}
/* every letter is its own flask, so each can hold its own level: L and b
   (tall letters) fill to 66%, the short a to 56% so the surface still
   runs through its top stroke, the dot sits at 50%. Bottom layer: faint "glass", so the
   empty part of a letter reads as a vessel even without an outline. */
.lab-word>span{--lvl:50%;
  background:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 480 240' preserveAspectRatio='none'%3E%3Cpath d='M0 120 Q30 108 60 120 T120 120 T180 120 T240 120 T300 120 T360 120 T420 120 T480 120 V240 H0Z' fill='%232AC0FF'/%3E%3C/svg%3E") repeat-x,
    linear-gradient(transparent 54%,var(--p) 54%) no-repeat,
    linear-gradient(rgba(42,192,255,.12),rgba(42,192,255,.12)) no-repeat;
  background-size:5.6em 200%,100% 200%,100% 100%;background-position:-1.4em 0,0 0,0 0;
  -webkit-background-clip:text;background-clip:text;
  animation:labfill 2.6s var(--ease) .6s forwards,labwave 4s linear infinite}
/* a glyph can reach past its own box (the L's foot overhangs by the
   headline's negative letter-spacing); the liquid is painted only inside
   the box, so the overhang showed as a dark notch. Padding grows the
   painted area, the equal negative margin keeps the layout unchanged. */
.lab-word>span{padding-inline:.12em;margin-inline:-.12em}
.lab-word>.hi{--lvl:66%}
.lab-word>.mid{--lvl:56%}
/* fonts from the picker whose letters are built from overlapping outlines
   draw every outline under a text-stroke (the "several contours" bug): on
   any face but the default the outline goes and the glass layer carries
   the letter shape instead */
html[data-font]:not([data-font="chakra"]) .lab-word{-webkit-text-stroke:0}
html[data-font]:not([data-font="chakra"]) .lab-word>span{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 480 240' preserveAspectRatio='none'%3E%3Cpath d='M0 120 Q30 108 60 120 T120 120 T180 120 T240 120 T300 120 T360 120 T420 120 T480 120 V240 H0Z' fill='%232AC0FF'/%3E%3C/svg%3E"),linear-gradient(transparent 54%,var(--p) 54%),linear-gradient(rgba(42,192,255,.26),rgba(42,192,255,.26))}
.decoding .lab-word>span{animation:none}
/* the mockup fills LAB (caps) to 70%; our "Lab." has a short a, so the
   level is per letter (--lvl) instead of one line across the word */
@keyframes labfill{to{background-position-y:var(--lvl)}}
/* one tile (4 waves, 5.6em) is wider than any letter plus the 1.4em the
   wave travels, and it moves by exactly one wavelength: a tile edge never
   crosses a letter, so there is nothing to seam */
@keyframes labwave{from{background-position-x:-1.4em,0,0}to{background-position-x:0,0,0}}
@media(prefers-reduced-motion:reduce){.lab-word>span{animation:none;background-position:-1.4em var(--lvl),0 var(--lvl),0 0}}
.hero .sub{margin:var(--s3) 0 var(--s4);color:var(--dim);font-size:var(--t-lead);max-width:46ch}
.cta-row{display:flex;gap:var(--s3);flex-wrap:wrap}
/* the stats sit on the page grid: the hero copy spans 7 of the 12 columns,
   so the row is the same 7 columns (same --gap) and each figure starts on a
   column line — 1, 4 and 6 — instead of floating at a flex gap */
/* one even gap between the three figures (client 06.10): pinned to grid
   columns ($4,218,033 on 3, the others on 2) the gaps ran 150 / 65px at
   1440 and flipped to 205 / 263 at 1920. The first figure stays on the
   edge; the rhythm is the space between them, as on the phone. */
.hstats{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s7);margin-top:var(--s6)}
.hstats b{display:block;font-family:var(--disp);font-weight:700;font-size:var(--t-stat);line-height:1.1;font-variant-numeric:tabular-nums}
.hstats div:nth-child(2) b{color:var(--win)}
.hstats span{display:block;margin-top:var(--s2);font-size:var(--t-label);color:var(--faint)}

.hero-feat{display:block;background:var(--panel);border:1px solid var(--line);border-radius:16px;overflow:hidden;transition:border-color .15s,transform .15s}
.hero-feat:hover{border-color:var(--line-2);transform:translateY(-3px)}
.feat-art{position:relative;aspect-ratio:16/10;background:var(--grad);display:block;overflow:hidden}
/* the scrim needs z-index or the image paints over it and the lockup lands on bare artwork (.gart::before already had one) */
.feat-art::before{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(180deg,transparent 38%,rgba(0,0,0,.78))}
.feat-name{position:absolute;left:var(--s4);bottom:var(--s5);z-index:2;font-family:var(--disp);font-weight:700;font-size:var(--t-h2);line-height:1;letter-spacing:-.02em}
.feat-std{position:absolute;left:var(--s4);bottom:var(--s3);z-index:2;font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.8)}
/* a tile whose artwork already carries the game name must not print a second one */
.art-titled .gname,.art-titled .std,.art-titled .feat-name,.art-titled .feat-std{display:none}
/* hero stays landscape, so crop above the wordmark baked into the art */
.feat-art .gimg{object-position:center 6%}
/* обидва бейджі в правому верхньому куті. клієнт 10.09 скасував власну
   вимогу від 31.08 ("SOON праворуч, LIVE ліворуч") — тепер вони в одному
   місці, тож right живе в БАЗОВОМУ правилі, а не окремим випадком. */
.tag{position:absolute;top:var(--s3);right:var(--s3);z-index:3;font-size:var(--t-label);font-weight:700;letter-spacing:.05em;padding:var(--s1) var(--s2);border-radius:8px;background:var(--faint);color:#fff}
.tag.live{background:var(--win)}   /* ink — у спільному правилі з .btn-p нижче */
/* на героєвому арті підпис відступає 20px, а бейдж стояв на 14 — два
   кутові написи на одній картинці мусять мати спільний відступ */
.feat-art .tag{top:var(--s4);right:var(--s4)}
.feat-meta{display:grid;grid-template-columns:1fr 1fr;gap:1px;background:var(--line)}
.feat-meta .mrow{background:var(--panel);padding:var(--s3) var(--s3);display:flex;justify-content:space-between;align-items:baseline}
.feat-meta .k{font-size:var(--t-small);color:var(--dim)}
.feat-meta .v{font-size:var(--t-body);font-weight:700;font-variant-numeric:tabular-nums}

/* ── games carousel ── */
.games-sec{padding:var(--section) 0}
.games-head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s3);flex-wrap:wrap;padding:0 var(--gut);margin-bottom:var(--hgap)}
.games-head h2{font-family:var(--disp);font-weight:700;font-size:var(--t-h2);letter-spacing:-.02em;line-height:1}
.games-head .cnt{font-size:var(--t-label);color:var(--faint);font-weight:500}
.car-ctrl{display:flex;align-items:flex-end;gap:var(--s3)}
/* сортування живе в дропдауні. компактний варіант: кнопка по контенту,
   панель вирівняна по правому краю і ширша за кнопку — написи довші. */
/* мітка й значення одного кегля — розрізняються лише кольором і капсом */
.sort-lab{flex:none;color:var(--faint);text-transform:uppercase;letter-spacing:.06em}
.sortdrop,.filterdrop{flex:none}
/* ширина по НАЙДОВШІЙ опції, а не по вибраній. Інакше вибір
   "Volatility · high to low" роздував кнопку зі 146 до 221px і тягнув
   фільтр Show за собою на 75px — на очах у того, хто щойно клікнув.
   В em, щоб трималось на тірах, де кегль кнопки більший.
   17.7em = найдовший варіант сортування, 14.2em = "Coming soon". */
.sortdrop .drop-btn,.filterdrop .drop-btn{width:auto;gap:var(--s2);padding:var(--s2) var(--s3);font-size:var(--t-small);border-radius:12px}
.sortdrop .drop-btn{min-width:17.7em}
.filterdrop .drop-btn{min-width:14.2em}
.sortdrop .drop-val,.filterdrop .drop-val{flex:1;text-align:left}
.sortdrop .drop-list,.filterdrop .drop-list{left:auto;right:0;min-width:max(100%,240px)}

.car-nav{display:flex;gap:var(--s2)}
/* an explicit display beats the hidden attribute's UA rule, so the JS
   that hides the arrows when the row fits needs this to take effect. */
.car-nav[hidden]{display:none}
.car-nav button{width:40px;height:40px;border:1px solid var(--line-2);border-radius:12px;color:var(--ink);font-size:var(--t-body)}
.car-nav button:hover{border-color:var(--p);color:var(--p)}
/* sort: volatility / max win (↓ high→low, ↑ low→high, third click off) */

/* scroll-padding is NOT optional here: the track is padded by --gut so the
   first card lines up with the section heading, but scroll-snap measures
   against the scrollport EDGE, so without this the browser parks the first
   card flush to the screen and the row starts one whole gutter out of
   alignment with every other section (worst on wide panels). */
/* верхні 4px паддінга потрібні, щоб ховер-підйом картки (-3px) не
   обрізався: overflow-x:auto примусово робить overflow-y теж auto.
   Компенсуємо їх відʼємним margin, а НЕ відніманням усередині
   --hgap: браузер округляв margin і padding нарізно, і зазор під
   "Our games" систематично розходився з "Biggest wins" на ~1px.
   Так обидва шляхи округлюють одну й ту саму величину. */
.carousel{display:flex;gap:var(--cgap);overflow-x:auto;scroll-snap-type:x mandatory;scroll-behavior:smooth;
  margin-top:calc(var(--s1) * -1);margin-bottom:calc(var(--s1) * -1);padding:var(--s1) var(--gut) var(--s1);scroll-padding-inline:var(--gut);scrollbar-width:none}
.carousel::-webkit-scrollbar{display:none}
.gcard{flex:0 0 clamp(230px,26vw,280px);scroll-snap-align:start;background:var(--panel);border:1px solid var(--line);overflow:hidden;display:flex;flex-direction:column;transition:border-color .15s,transform .15s}
.gcard:hover{border-color:var(--line-2);transform:translateY(-3px)}
/* client 05.10: the boarding-pass notches and perforation are gone —
   back to the plain rounded card */
.gcard{border-radius:16px}
.gcard.filtered-out{display:none}
.gart{position:relative;aspect-ratio:3/4;display:block;overflow:hidden;background:#101B2E}
/* real key art replaces the placeholder gradients */
.gimg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;transition:transform .45s cubic-bezier(.2,.7,.2,1)}
.gcard:hover .gimg{transform:scale(1.04)}
.gart::before{content:"";position:absolute;inset:0;z-index:1;background:linear-gradient(180deg,transparent 38%,rgba(0,0,0,.78))}
.gname{position:absolute;left:var(--s3);right:var(--s3);bottom:var(--s5);z-index:2;font-family:var(--disp);font-weight:700;font-size:var(--t-h3);line-height:.95;letter-spacing:-.01em;overflow-wrap:anywhere}
.std{position:absolute;left:var(--s3);bottom:var(--s3);z-index:2;font-size:var(--t-label);letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.72)}
/* SOON-картки навмисно мають дрібнішу й тьмянішу назву — мистецтво ще
   в роботі. Але множник --dscale тут загубився, тож при виборі іншого
   шрифту ці п'ять назв лишались на місці, поки все навколо їхало. */
.is-soon .gname{font-size:var(--t-h3);color:#98AAC6}
.is-soon .gimg{filter:saturate(.9) brightness(.92)}
.gcard:hover .gimg{filter:none}
.art-1{background:var(--grad)}
.art-2{background:linear-gradient(150deg,#1E7BE0,#0A2242)}
.art-3{background:linear-gradient(150deg,#24D6BA,#0B3F44)}
.art-4{background:linear-gradient(150deg,#2AC0FF,#10375F)}
.art-5{background:linear-gradient(150deg,#15A69A,#07242E)}
.art-6{background:linear-gradient(150deg,#8FF0E6,#12557F)}
.gmeta{display:flex;flex-direction:column;padding:var(--s2) 0}
.mrow{display:flex;justify-content:space-between;align-items:baseline;padding:var(--s2) var(--s3);border-bottom:1px solid var(--line)}
.mrow:last-child{border-bottom:0}
.mrow .k{font-size:var(--t-small);color:var(--dim)}
.mrow .v{font-size:var(--t-body);font-weight:700;font-variant-numeric:tabular-nums}
.is-live .gmeta .mrow:nth-child(1) .v,.is-live .gmeta .mrow:nth-child(3) .v{color:var(--gold)}
.is-soon .mrow .v{color:var(--dim)}
/* the buttons sit in the middle of the card's foot (client 06.10: 8px
   above them, 16 below) — equal padding all round, and the strip takes
   any spare height so align-items really centres them */
.gacts{flex:1 0 auto;display:flex;align-items:center;gap:var(--s2);padding:var(--s3)}
.gacts .btn{flex:1}
/* смуга живе на дні картки; центруємо чесно (flex + рівний паддінг),
   а не "зсунути на 3px" — інакше розʼїдеться на іншому кеглі. */
/* клієнт просив відцентрувати — вертикально було 12/15, тепер 13/13,
   і по горизонталі теж; стрілка при центрованому написі зайва. */
/* картки в ряду однакової висоти, і на SOON-картці під написом лишався
   порожній залишок: над текстом 1px, під ним 29px. flex:1 віддає цей
   залишок самій смузі, і тоді align-items справді центрує напис у ній. */
.notify{flex:1 0 auto;display:flex;align-items:center;justify-content:center;color:var(--p);
  font-weight:600;font-size:var(--t-small);padding:var(--s3) var(--s3);min-height:44px}
.notify:hover{filter:brightness(1.1)}

/* ── wins board ── */
.wins-sec{padding:var(--sec) var(--gut)}
.wins-head{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s3);margin-bottom:var(--hgap)}
.wins-head h2{font-family:var(--disp);font-weight:700;font-size:var(--t-h2);letter-spacing:-.02em;line-height:1}
.wins-head .mut{font-size:var(--t-label);white-space:nowrap;flex:none}
/* letter-spacing trails the LAST letter too, so a tracked label set flush
   right stopped 2–4px short of the edge (client 05.10): pull the
   right-most one back by exactly its tracking */
.util-r>:last-child,.wins-head .mut{margin-inline-end:calc(var(--track-label) * -1)}
/* tabular figures are what actually makes a money table scannable:
   without them $152,000 and $19,200 are different physical widths and
   the digits never line up, however you align the cell. */
.board{width:100%;border-collapse:collapse;background:var(--panel);border:1px solid var(--line);border-radius:16px;overflow:hidden;
  font-variant-numeric:tabular-nums}
/* bet · multiplier · payout are one right-aligned numeric block. left
   aligned they read ragged ($6.08 over $400 over $1), and the eye had to
   cross ~500px of empty panel from the multiplier to the payout, so the
   three columns carry real width instead. the split was measured, not
   guessed: it is the one that minimises the LARGEST gap between two
   adjacent values (342px vs 483px when the numerics were narrower and
   PLAYER swallowed 43% of the table). */
.board th:nth-child(2),.board td:nth-child(2){width:20%}
.board th:nth-child(3),.board td:nth-child(3){width:14%}
.board th:nth-child(4),.board td:nth-child(4){width:16%}
.board th:nth-child(5),.board td:nth-child(5){width:18%}
.board th{text-align:left;font-size:var(--t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--faint);font-weight:600;padding:var(--s3) var(--s3);border-bottom:1px solid var(--line)}
/* .board th beats the bare .r utility on specificity — the numeric column
   header must right-align with its values (client: payout ↔ win amount) */
.board th.r{text-align:right}
.board td{padding:var(--s3) var(--s3);border-bottom:1px solid var(--line);font-size:var(--t-body);vertical-align:baseline}
.board tr:last-child td{border-bottom:0}
.board tbody tr:hover{background:var(--panel-2)}
.mult{display:inline-block;min-width:78px;text-align:center;
  font-weight:700;font-size:var(--t-small);padding:var(--s1) var(--s2);border-radius:8px;background:var(--panel-2);color:var(--dim)}
.mult.m3{color:var(--win)}.mult.m4{color:var(--o)}.mult.m5{color:var(--gold)}
.payout{color:var(--win);font-weight:700;font-variant-numeric:tabular-nums}
/* equal gaps between the columns, at every width (client 06.10: "why
   aren't the columns evenly spaced?" — pinned to 3/3/2/2/2 grid columns,
   names left and numbers right, the gap Game→Bet was ~3x Bet→Multiplier).
   Each column is as wide as its widest cell and the spare width is shared
   equally between them; the rows are subgrids, so every row uses the same
   tracks. Only the names may shrink (with an ellipsis) when a phone is too
   narrow for all of them. The frame sits on the edge line under "Biggest
   wins" at every width (06.10: the hang past the edge was tried and
   dropped). The frame is an inset outline, no width. */
/* the spare width lives in four equal 1fr spacer tracks between the
   columns (not justify-content: Safari packed the subgrid rows to the left
   and ignored the distribution) — cells sit on the odd tracks */
.board{display:grid;column-gap:0;
  grid-template-columns:minmax(0,max-content) minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content;
  border:0;outline:1px solid var(--line);outline-offset:-1px;
  width:100%}
.board thead,.board tbody{display:contents}
.board tr{display:grid;grid-column:1/-1;grid-template-columns:subgrid;align-items:baseline;
  padding-inline:var(--s3);border-bottom:1px solid var(--line)}
.board tbody tr:last-child{border-bottom:0}
.board th,.board td{padding-inline:0;border-bottom:0;min-width:0}
.board th:nth-child(n),.board td:nth-child(n){width:auto}
.board td:first-child{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.board :is(th,td):nth-child(1){grid-column:1}
.board :is(th,td):nth-child(2){grid-column:3}
.board :is(th,td):nth-child(3){grid-column:5}
.board :is(th,td):nth-child(4){grid-column:7}
.board :is(th,td):nth-child(5){grid-column:9}
@media(max-width:820px){
  .board tr{padding-inline:var(--s2)}
  .mult{min-width:0}
}
/* the Bet column is hidden on a phone: four tracks */
@media(max-width:560px){
  .board{grid-template-columns:minmax(0,max-content) minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content}
  .board :is(th,td):nth-child(4){grid-column:5}
  .board :is(th,td):nth-child(5){grid-column:7}
  .board td{font-size:var(--t-small)}
  .mult{font-size:var(--t-label)}
}

/* ── notify band (signup) ── */
/* drop-dates signup · v3 (04.10): a compact closing row, not a second
   hero — small headline + note on the left, the form on the right, on the
   12-column grid */
.notify-sec{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--gap);row-gap:var(--s3);
  align-items:start;padding:var(--section) var(--gut)}
/* заголовок і нотатка — один блок гріду: поки нотатка стояла окремим
   рядком, її відступ задавала висота форми (48px), а не row-gap, і під
   обрізаним по капітелі h2 зіяло 47px замість 16 */
.nb-copy{grid-column:1/7;grid-row:1;display:grid;row-gap:var(--s3)}
.notify-sec h2{font-family:var(--disp);font-weight:700;font-size:var(--t-h3);letter-spacing:-.01em;line-height:var(--s5)}
.nb-sub{font-size:var(--t-small);line-height:var(--s4)}
/* the headline's cap line is level with the top of the form's frame
   (client 06.10: "measure by the border and the top of the letters") —
   the h2 box is trimmed to its caps, so align-items:start does it. The note under the form is out of the flow so
   it never moves that line. */
.signup{grid-column:7/13;grid-row:1;justify-self:end;width:min(480px,100%);position:relative}
.signup .done{position:absolute;top:100%;left:0;right:0}
.su-row{display:flex;gap:var(--s2)}
.su-row input{flex:1;min-width:0;background:var(--panel);border:1px solid var(--line-2);border-radius:12px;color:var(--ink);padding:var(--s3) var(--s3);font-family:var(--ui);font-size:var(--t-body);outline:none}
.su-row input:focus{border-color:var(--p)}
.done{margin-top:var(--s2);font-size:var(--t-small)}
.done:empty{display:none}

/* ── footer ── */
.footer{display:grid;grid-template-columns:1fr auto 1fr;align-items:center;gap:var(--s3);
  padding:var(--section) var(--edge-bar)}
.foot-l{display:flex;align-items:center;gap:var(--s2);justify-self:start;min-width:0}
.foot-l small{font-size:var(--t-label);letter-spacing:.1em;text-transform:uppercase;color:var(--faint);margin-left:var(--s1)}
/* <small> порожній у всіх семи файлах, але як flex-елемент він досі
   з'їдав gap:var(--s2) + власні margin-left:var(--s1). На мобільному, де .foot-l
   центрується цілим блоком, ці 13px клали ЛОГО на 6.5px лівіше центру. */
.foot-l small:empty{display:none}
.foot-nav{display:flex;gap:var(--navgap);flex-wrap:wrap;justify-self:center;justify-content:center}
/* вертикальний паддінг НЕ потрібен для збігу — він не впливає на горизонталь,
   а на одноекранних сторінках кожен піксель висоти на рахунку */
.foot-nav a{font-size:var(--t-nav);font-weight:600;letter-spacing:.12em;text-transform:uppercase;padding:0 var(--navpx);color:var(--dim)}
.foot-nav a:hover{color:var(--p)}
.foot-legal{color:var(--dim);white-space:nowrap}.foot-legal:hover{color:var(--p)}
.foot-r{display:flex;align-items:baseline;white-space:nowrap;gap:var(--s3);font-size:var(--t-small);justify-self:end;min-width:0}
/* 18+ is the same chip as LIVE / SOON (client 05.10): mono label, 4/8
   padding, radius 8 — the outline is an inset shadow so the box stays
   exactly the tag's height. line-height is pinned: as a button it
   inherited the footer row's 48px and grew into a tall capsule. */
.badge-18{display:inline-block;font:600 var(--t-label)/1.5 var(--mono);letter-spacing:var(--track-label);text-transform:uppercase;
  color:var(--p);padding:var(--s1) var(--s2);border:0;border-radius:8px;box-shadow:inset 0 0 0 1px var(--p);flex:none}
.badge-18:hover{background:var(--p);color:#fff}

/* ── perf: idle loops only run where they are seen (06.10) ──────
   Endless background/transform loops (the Lab. wave, the marquee, the
   demo clock, the cards' idle glitch) pause off screen; the header's
   (logo wave, CTA wave, live dot) pause while the page is scrolling, so
   the sticky, blurred bar isn't repainted every frame of a scroll. */
.offscreen,.offscreen *,.is-scrolling .bar *,.is-scrolling .util *{animation-play-state:paused!important}
/* ── marquee · v4 ────────────────────────────────────────────
   Смуга між героєм і каталогом. Трек продубльований рівно двічі, а
   padding-left дорівнює gap, тож translateX(-50%) лягає сам на себе і
   шва на стику не видно. */
.marq{overflow:hidden;display:flex;align-items:center;height:var(--s7);
  border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.marq-track{display:flex;align-items:center;gap:var(--s6);padding-left:var(--s6);
  white-space:nowrap;will-change:transform;animation:marq 40s linear infinite}
.marq-track span{font:600 22px/1 var(--disp);letter-spacing:.06em;
  text-transform:uppercase;color:var(--faint)}
.marq-track span.on{color:var(--ink)}
.marq-track .mark{flex:none;height:18px;width:auto;opacity:.5}
@keyframes marq{to{transform:translateX(-50%)}}
@media(prefers-reduced-motion:reduce){.marq-track{animation:none}}

/* ── live bets ── */
/* док піднімається рівно настільки, щоб не накрити футер: --dock-lift
   рахує JS із реального положення футера, тож у середині сторінки док
   лишається біля самого низу і не висить у повітрі. */
.livebets{position:fixed;right:var(--edge);bottom:calc(var(--dockb) + var(--dock-lift,0px));z-index:120;width:320px;max-width:calc(100vw - 2 * var(--edge));background:var(--panel);border:1px solid var(--line-2);border-radius:16px;overflow:hidden;box-shadow:0 24px 60px -20px rgba(0,0,0,.7)}
.lb-head{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s3);border-bottom:1px solid var(--line);font-size:var(--t-label);font-weight:700;letter-spacing:.06em}
.lb-head>i{width:8px;height:8px;border-radius:50%;background:var(--p);box-shadow:0 0 8px var(--p)}
.lb-head .sp{flex:1}.lb-head button{color:var(--dim);font-size:var(--t-small);padding:var(--s1) var(--s1)}.lb-head button:hover{color:var(--p)}
.lb-body{max-height:300px;overflow:hidden;transition:max-height .25s}
.livebets.collapsed .lb-body{max-height:0}
.lb-row{display:grid;grid-template-columns:32px 1fr auto auto;align-items:center;gap:var(--s2);padding:var(--s2) var(--s3);border-bottom:1px solid var(--line)}
.lb-row.new{animation:lbin .35s ease}
@keyframes lbin{from{opacity:0;transform:translateY(-6px)}to{opacity:1}}
.lb-thumb{width:32px;height:32px;border-radius:8px}
.lb-main{min-width:0}.lb-main b{display:block;font-size:var(--t-small);font-weight:600}.lb-main span{font-size:var(--t-label);color:var(--faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.lb-mult{font-size:var(--t-label);font-weight:700;color:var(--dim);font-variant-numeric:tabular-nums}.lb-mult.m3{color:var(--win)}.lb-mult.m4{color:var(--o)}.lb-mult.m5{color:var(--gold)}.lb-mult.bust{color:var(--dim)}
.lb-amt{font-size:var(--t-small);font-weight:700;font-variant-numeric:tabular-nums}.lb-amt.win{color:var(--win)}.lb-amt.loss{color:var(--dim)}

/* ── gate ── */
.gate{position:fixed;inset:0;z-index:300;display:none;align-items:center;justify-content:center;padding:var(--s4);background:rgba(2,5,11,.88);backdrop-filter:blur(8px)}
.gate.on{display:flex}
.gate-card{max-width:420px;width:100%;background:var(--panel);border:1px solid var(--line-2);border-radius:16px;padding:var(--s6);text-align:center}
.gate-mark{height:var(--s7);width:auto;display:block;margin:0 auto var(--s3)}
/* the 18+ flask fills up (client 06.10): the liquid rises from the empty
   bottom to just under the neck's top bar while its surface drifts as a
   wave — the same liquid as the header logo, clipped to the flask's inside.
   The gate is display:none until shown, so every opening replays it. */
.gate-fill{transform:translateY(16px);animation:gate-rise 2.4s var(--ease) .3s both}
.gate-wave{animation:flask-drift 3s linear infinite}
@keyframes gate-rise{from{transform:translateY(152px)}}
@media(prefers-reduced-motion:reduce){.gate-fill,.gate-wave{animation:none}}
.big18{font-family:var(--disp);font-weight:700;font-size:var(--t-stat);color:var(--p);line-height:1}
.gate-card h2{font-family:var(--disp);font-weight:700;font-size:var(--t-h3);margin:var(--s2) 0}
.gate-card p{color:var(--dim);font-size:var(--t-small);max-width:32ch;margin:0 auto}
.gate-card .row{display:flex;gap:var(--s2);justify-content:center;margin:var(--s4) 0 var(--s2)}
.gate-note{font-size:var(--t-label);color:var(--faint)}

/* ── game detail ── */
.crumb{padding:var(--s3) var(--gut) 0;font-size:var(--t-small);color:var(--faint)}
.crumb a:hover{color:var(--p)} .crumb em{color:var(--ink);font-style:normal}
/* the copy column stretches into the free right half and centres there */
/* ── game page hero · v3 ─────────────────────────────────────
   Same rules as the home hero (client SS-44: too much empty space): on the
   12-column grid — poster on 1–4, copy on 6–12, left-aligned so the copy
   starts on a column line instead of floating centred in a half-empty
   right side; one --s6 under the crumb instead of a whole section. */
.detail-hero{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--gap);row-gap:var(--s6);
  padding:var(--s6) var(--gut) var(--section);align-items:center}
.detail-hero .dkey{grid-column:1/5}
.detail-hero .dhead{grid-column:6/13}
.dkey{border-radius:16px;overflow:hidden;background:var(--panel);border:1px solid var(--line)}
/* the poster shows whole — the artwork carries its own title */
.dkey .feat-art{aspect-ratio:3/4}
.dhead{text-align:left;min-width:0}
.dhead h1{font-family:var(--disp);font-weight:700;font-size:var(--t-display);line-height:.98;letter-spacing:-.02em}
.dhead h1 em{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;font-style:normal}
.hook{color:var(--dim);font-size:var(--t-lead);line-height:1.6;max-width:52ch;margin:var(--s4) 0 var(--s6)}
.hook strong{color:var(--ink)}
.dchips{display:flex;gap:var(--s2);flex-wrap:wrap;margin-bottom:var(--s4)}
.dchip{display:flex;flex-direction:column;gap:var(--s1);border:1px solid var(--line-2);border-radius:var(--r);padding:var(--s2) var(--s3);min-width:96px}
.dchip .k{font-size:var(--t-label);letter-spacing:.04em;text-transform:uppercase;color:var(--faint)}
.dchip .v{font-size:var(--t-body);font-weight:700}.dchip .v em{color:var(--p);font-style:normal}
.dacts{display:flex;gap:var(--s3);flex-wrap:wrap}
.sec2{padding:var(--sec) var(--gut)}
.sec2 h2{font-family:var(--disp);font-weight:700;font-size:var(--t-h2);letter-spacing:-.02em;line-height:1;margin-bottom:var(--hgap)}
.steps{display:grid;grid-template-columns:repeat(5,1fr);gap:var(--s3)}
.step{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:var(--s3)}
.step .num{font-family:var(--disp);font-weight:700;font-size:var(--t-h3);color:var(--p);line-height:1}
.step h3{font-size:var(--t-body);font-weight:700;margin:var(--s2) 0 var(--s1)}.step p{font-size:var(--t-small);color:var(--dim);line-height:1.5}
.specg{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--s3)}
.specc{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:var(--s3);
  display:flex;flex-direction:column}
.specc .k{font-size:var(--t-label);letter-spacing:.04em;text-transform:uppercase;color:var(--faint)}
.specc .v{font-family:var(--disp);font-weight:700;font-size:var(--t-h3);margin-top:var(--s1)}.specc .v em{color:var(--p);font-style:normal}
.rungs{display:grid;grid-template-columns:repeat(11,minmax(0,1fr));gap:var(--s2)}
.rung{aspect-ratio:1;display:grid;place-items:center;border:1px solid var(--line-2);border-radius:8px;font-size:var(--t-label);font-weight:700;color:var(--dim);background:var(--panel)}
.rung.h3{color:var(--win)}.rung.h4{color:var(--o)}.rung.h5{color:var(--gold);border-color:rgba(143,240,230,.4);background:rgba(143,240,230,.08)}
.cta-band{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--s4);flex-wrap:wrap;padding:var(--sec) var(--gut)}
.cta-band h2{font-family:var(--disp);font-weight:700;font-size:var(--t-h2);letter-spacing:-.02em;line-height:1}.cta-band h2 em{background:var(--grad);-webkit-background-clip:text;background-clip:text;color:transparent;font-style:normal}

/* ── reveal ── */
.rv{opacity:0;transform:translateY(16px);transition:opacity .5s,transform .5s}
.rv.in{opacity:1;transform:none}
@media(prefers-reduced-motion:reduce){.rv{opacity:1;transform:none;transition:none}}

/* ── responsive ── */
@media(max-width:1000px){
  .nav{display:none} .burger{display:block}
  .fontpick-wrap{display:none}
  .hero{grid-template-columns:1fr}
  .hero-copy,.hero-feat{grid-column:1/-1}
  /* one column below 1000: the stats go back to a plain wrapping row */
  .hstats{display:flex;flex-wrap:wrap;gap:var(--s3) var(--s6)}
  /* було max-width:560px + margin:0 auto: блок гри сідав по центру, а
     крихти й чотири .sec2 лишались на --gut від краю. На 900px це
     давало 18px проти ~188px — сторінка виглядала як два різні макети
     один під одним. Тепер блок на тій самій вертикалі, що й решта. */
  .detail-hero{grid-template-columns:1fr}
  .detail-hero .dkey,.detail-hero .dhead{grid-column:1/-1}
  .dkey{width:min(100%,400px)}
  /* кроків рівно п'ять, тож дві колонки завжди лишають п'ятий сиротою
     на пів ширини. Нижче 760 це вже полагоджено в один стовпчик —
     смуга 761-1000 (iPad портрет) лишалась із 2+2+1. */
  .steps{grid-template-columns:1fr}
  .specg{grid-template-columns:repeat(2,minmax(0,1fr))} .rungs{grid-template-columns:repeat(6,minmax(0,1fr))}
}
@media(max-width:560px){.hide-s{display:none!important}
  /* X, Discord and Grid are gone — the counter is the right-most label */
  .util-play{margin-inline-end:calc(var(--track-label) * -1)}
  .footer{grid-template-columns:1fr;justify-items:center;text-align:center}
  .foot-l,.foot-r{justify-self:center}}

/* colour comp 03 · Blue × Teal, deep: accent surfaces carry dark ink for contrast */
.btn-p,.skip,.badge-18:hover,.tag.live{color:#02101C}

/* ── demo stage ──────────────────────────────────────────────────────
   a centred 16:9 frame, sized to sit inside the section rather than
   dominate it. the iframe is real and hidden; the waiting card sits
   in its place until a demo URL is set on data-demo-src. */
/* the frame matches the stage a Stake Engine game actually gets:
   its layout module (utils-layout/createLayout) designs the desktop
   canvas at 1920x1080, the shipped games at 1422x800, landscape at
   1600x900 — all 16:9 — and resizes the canvas to the window, scaling
   by min(widthScale,heightScale). its ratio breakpoints matter here:
   >=1.3 keeps the DESKTOP layout, <=0.8 flips to portrait. so 16/9
   (1.778) is the safe target and the frame must never get squarer. */
.demo-stage{position:relative;aspect-ratio:16/9;
  /* full content width, like every other block on the page: at 16:9 that
     is 738px tall at 1440 and 972 at 1920, inside the viewport under the bar */
  width:100%;
  background:var(--panel);border:1px solid var(--line-2);border-radius:16px;
  overflow:hidden;display:grid;place-items:center}
.demo-frame{position:absolute;inset:0;width:100%;height:100%;border:0}
.demo-wait{display:grid;justify-items:center;gap:var(--s2);text-align:center;color:var(--dim);padding:var(--s4)}
.demo-wait svg{color:var(--p)}
.demo-wait b{font-family:var(--disp);font-size:var(--t-h3);letter-spacing:.02em;color:var(--ink);text-transform:uppercase}
.demo-wait span{font-size:var(--t-body);max-width:46ch}
@media(max-width:700px){.demo-stage{border-radius:12px}}


/* mobile: the lockup steps down with the bar */
@media(max-width:560px){.brand-logo,.foot-l .brand-logo{height:var(--s5)}
  /* the arrow is the first thing to go when the bar gets tight */
  .trap{--slant:var(--s2);--cx:1.57px;--cy:7.84px}.trap-in{padding-inline:var(--s5)}.trap .arr{display:none}}

/* ── HOLOGRAM PROJECTION (merged from the /holo/ build) ───────────
   the card is not wiped in — it is ASSEMBLED. a grid of voxels
   renders the art area tile by tile in a bottom-up wave, every tile
   revealing its own square of real card pixels; the ceremony (chip →
   name stamp → spec rows → buttons) then plays on top.
   the resting state is untouched: no script, no change. */
.gcard,.hero-feat,.dkey{position:relative}

.holo-grid{position:absolute;inset:0;z-index:6;pointer-events:none;display:grid;
  border-radius:inherit;overflow:hidden}
/* the voxel is a transparent glass frame: the PICTURE in it is the real
   card, revealed through a JS-driven mask square underneath — so every
   square carries its piece of the card UI from its very first frame.
   the spark just marks the moment a tile renders, then burns off. */
.holo-grid i{
  background:radial-gradient(closest-side,rgba(255,255,255,.36),rgba(224,244,255,.15) 62%,rgba(224,244,255,0));
  outline:1px solid rgba(255,255,255,.4);outline-offset:-1px;
  opacity:0;transform:scale(.35)}
/* the bars grid assembles the art out of short glitch shards */
.holo-grid.bars i{border-radius:2.5px;outline-color:rgba(255,255,255,.3);
  background:linear-gradient(90deg,rgba(255,255,255,.05),rgba(255,255,255,.4) 50%,rgba(255,255,255,.05))}
/* only the figure mode needs the filter (glow must follow the clip-path);
   for squares a box-shadow costs a fraction of a per-element filter */
.holo.figures .holo-grid i{box-shadow:none;filter:drop-shadow(0 0 8px rgba(255,255,255,.5))}
/* the projection is built from mixed geometry — each tile is dealt a
   figure per cycle (class set in JS, mask layer matches the shape) */
.holo-grid i.s1{clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}          /* diamond */
.holo-grid i.s2{clip-path:polygon(50% 0,100% 100%,0 100%)}                 /* triangle up */
.holo-grid i.s3{clip-path:polygon(0 0,100% 0,50% 100%)}                    /* triangle down */
.holo-grid i.s4{clip-path:polygon(25% 5%,75% 5%,100% 50%,75% 95%,25% 95%,0 50%)} /* hexagon */
.holo-grid i.s5{border-radius:50%}                                         /* circle */
.holo .holo-grid i{animation:holo-spark .85s cubic-bezier(.3,.7,.3,1) var(--d,0ms) both}
@keyframes holo-spark{
  0%   {opacity:0;transform:scale(.5)}
  26%  {opacity:.85;transform:scale(1.03)}
  60%  {opacity:.5;transform:scale(1)}
  100% {opacity:0;transform:scale(1)}
}

/* a soft settle at the end — the projection breathing into place */
.holo .gcard,.holo .hero-feat,.holo .dkey{animation:holo-flick .6s ease-in-out calc(var(--hd,0ms) + var(--build,620ms) + .3s) both}
@keyframes holo-flick{
  0%,100% {opacity:1}
  30%     {opacity:.88}
  55%     {opacity:1}
  75%     {opacity:.94}
}

@media(prefers-reduced-motion:reduce){
  .holo .holo-grid i,.holo .gcard,.holo .gcard>:not(.holo-grid){animation:none}
  .holo-grid{display:none}
}

/* ── headline decode ─────────────────────────────────────────────
   type gets a type animation: characters flicker through glyphs in
   the flask blue and lock into the real letter, left to right.
   spans are width-fixed during the run so the line never jitters;
   the original markup is restored the moment the run ends. */
.hero h1 .ch,.dhead h1 .ch{display:inline-block;text-align:center;white-space:pre;transition:opacity .22s ease}
.hero h1 .ch.dec,.dhead h1 .ch.dec{color:var(--p);opacity:.85;text-shadow:0 0 16px rgba(42,192,255,.55)}

/* ── hologram generation (default build) ─────────────────────────
   the card appears first as a translucent cyan projection of its own
   art — scanlined, flickering — then a beam rises from the base and
   the real card materialises below it. */
.holo-ghost{position:absolute;inset:0;z-index:5;pointer-events:none;border-radius:inherit;
  background-size:cover;background-position:center;
  filter:sepia(1) hue-rotate(158deg) saturate(2.4) brightness(1.02);
  opacity:.4}
.holo-ghost::after{content:"";position:absolute;inset:0;
  background:repeating-linear-gradient(0deg,rgba(150,228,255,.18) 0 1px,transparent 1px 4px),
             linear-gradient(180deg,rgba(42,192,255,.2),rgba(42,192,255,.04) 55%,rgba(42,192,255,.16))}
.holo .holo-ghost{animation:ghost-flick .9s linear infinite}
@keyframes ghost-flick{
  0%,100%{opacity:.4}
  42%{opacity:.28}
  50%{opacity:.5}
  58%{opacity:.34}
  76%{opacity:.44}
}
.holobeam{position:absolute;left:-3%;right:-3%;top:0;height:7px;z-index:7;pointer-events:none;opacity:0;
  border-radius:50%;
  background:linear-gradient(90deg,transparent,rgba(120,220,255,.9) 22%,#fff 50%,rgba(120,220,255,.9) 78%,transparent);
  box-shadow:0 0 18px 4px rgba(90,205,255,.5),0 0 52px 14px rgba(42,192,255,.28);
  will-change:transform}
.gen-flash{animation:scan-flash .42s ease-out both}

/* ── scanline reveal (?fx=scan) ──────────────────────────────────
   gacha-style card reveal: a neon laser line sweeps top-to-bottom,
   the real card resolves above the line, a cyber wireframe grid
   holds the un-scanned part, and the card flashes when the line
   reaches the bottom. beam colour: --scanc (?scanc=RRGGBB). */
:root{--scanc:#2AC0FF}
.holo-scan{position:absolute;inset:0;z-index:6;pointer-events:none;border-radius:inherit;
  background-image:
    repeating-linear-gradient(0deg,rgba(42,192,255,.13) 0 1px,transparent 1px 13px),
    repeating-linear-gradient(90deg,rgba(42,192,255,.13) 0 1px,transparent 1px 13px),
    radial-gradient(rgba(160,230,255,.30) 1px,transparent 1.4px);
  background-size:auto,auto,7px 7px;
  background-color:rgba(4,8,16,.6);
  transition:opacity .3s}
.scanbeam{position:absolute;left:0;right:0;top:0;height:4px;z-index:7;pointer-events:none;opacity:0;
  color:var(--scanc);
  background:linear-gradient(90deg,transparent,currentColor 18%,#fff 50%,currentColor 82%,transparent);
  box-shadow:0 0 14px 3px currentColor,0 0 44px 12px rgba(42,192,255,.35);
  will-change:transform}
/* in scan mode the generic projector flick is off — the flash below is the finale */
.holo.scan .gcard,.holo.scan .hero-feat,.holo.scan .dkey{animation:none}
.scan-flash{animation:scan-flash .42s ease-out both}
@keyframes scan-flash{
  0%   {filter:brightness(1)}
  20%  {filter:brightness(1.85) saturate(1.25)}
  100% {filter:brightness(1)}
}

/* ── stamp ceremony ──────────────────────────────────────────────
   brawl-style card reveal, all compositor-friendly (transform+opacity):
   status chip pops → the name stamps down → the spec rows snap out one
   by one. Play / Details keep their place and simply fade up last. */
.holo.stamp .gcard,.holo.stamp .hero-feat,.holo.stamp .dkey{
  animation:cere-shell .3s ease-out var(--cd,0ms) both,
            cere-shake .28s linear calc(var(--cd,0ms) + var(--bld,480ms) + 240ms) both}
@keyframes cere-shake{
  0%,100%{translate:0 0;rotate:0deg}
  20%{translate:1.5px -1px;rotate:.35deg}
  40%{translate:-2px 1px;rotate:-.4deg}
  60%{translate:1.5px 1px;rotate:.25deg}
  80%{translate:-1px -1px;rotate:0deg}
}
@keyframes cere-shell{from{opacity:0}to{opacity:1}}

/* pure stamp mode: the art flies in. combo mode: the voxel hologram has
   already rendered it, so the art gets its own pulse the moment the build
   completes (--bld is the per-card build length, set in JS) */
.holo.stamp:not(.combo) .gart .gimg,.holo.stamp:not(.combo) .feat-art .gimg,.holo.stamp:not(.combo) .dkey .feat-art{
  animation:cere-art .55s cubic-bezier(.22,.75,.25,1) calc(var(--cd,0ms) + 80ms) both}
@keyframes cere-art{0%{opacity:0;transform:scale(1.26)}100%{opacity:1;transform:scale(1)}}
@keyframes cere-pulse{0%{transform:scale(1);filter:brightness(1)}35%{transform:scale(1.045);filter:brightness(1.3)}100%{transform:scale(1);filter:brightness(1)}}

.holo.stamp .gart .tag,.holo.stamp .feat-art .tag{
  animation:cere-pop .34s cubic-bezier(.3,1.5,.5,1) calc(var(--cd,0ms) + var(--bld,480ms) + 60ms) both}
@keyframes cere-pop{0%{opacity:0;transform:scale(.4)}100%{opacity:1;transform:scale(1)}}

.holo.stamp .gname,.holo.stamp .std,.holo.stamp .feat-name,.holo.stamp .feat-std{
  animation:cere-stamp .4s cubic-bezier(.3,1.35,.45,1) calc(var(--cd,0ms) + var(--bld,480ms) + 150ms) both}
@keyframes cere-stamp{0%{opacity:0;transform:scale(2)}60%{opacity:1;transform:scale(.97)}100%{opacity:1;transform:scale(1)}}

.holo.stamp .gmeta .mrow,.holo.stamp .feat-meta .mrow{animation:cere-row .38s cubic-bezier(.25,1.2,.4,1) both}
.holo.stamp .gmeta .mrow:nth-child(1),.holo.stamp .feat-meta .mrow:nth-child(1){animation-delay:calc(var(--cd,0ms) + var(--bld,480ms) + 260ms)}
.holo.stamp .gmeta .mrow:nth-child(2),.holo.stamp .feat-meta .mrow:nth-child(2){animation-delay:calc(var(--cd,0ms) + var(--bld,480ms) + 350ms)}
.holo.stamp .gmeta .mrow:nth-child(3),.holo.stamp .feat-meta .mrow:nth-child(3){animation-delay:calc(var(--cd,0ms) + var(--bld,480ms) + 440ms)}
.holo.stamp .gmeta .mrow:nth-child(4),.holo.stamp .feat-meta .mrow:nth-child(4){animation-delay:calc(var(--cd,0ms) + var(--bld,480ms) + 530ms)}
@keyframes cere-row{0%{opacity:0;transform:translateX(-16px) scale(1.04)}100%{opacity:1;transform:none}}

/* the buttons stay put — no motion, just a late fade so they arrive after the stats */
.holo.stamp .gacts,.holo.stamp .notify{animation:cere-shell .35s ease-out calc(var(--cd,0ms) + var(--bld,480ms) + 660ms) both}

/* ── spec rows on hover ──────────────────────────────────────────
   on hover-capable devices the RTP / Release / Max win / Volatility
   rows live INSIDE the art box (moved there by JS) and slide up over
   it on hover, row by row. touch devices keep the static layout. */
.hovermeta .gart .gmeta{position:absolute;inset:0;z-index:4;
  display:flex;flex-direction:column;justify-content:center;
  background:rgba(4,8,17,.92);
  padding:var(--s2) var(--s1);opacity:0;transform:translateY(14px);pointer-events:none;
  transition:opacity .26s ease,transform .3s cubic-bezier(.2,.8,.25,1)}
.hovermeta .gcard:hover .gart .gmeta,.hovermeta .gcard:focus-within .gart .gmeta{opacity:1;transform:none}
.hovermeta .gart .gmeta .mrow{border-bottom-color:rgba(42,192,255,.14);
  opacity:0;transform:translateX(-10px);
  transition:opacity .22s ease,transform .26s cubic-bezier(.25,1,.4,1)}
.hovermeta .gcard:hover .gart .gmeta .mrow,.hovermeta .gcard:focus-within .gart .gmeta .mrow{opacity:1;transform:none}
.hovermeta .gcard:hover .gart .gmeta .mrow:nth-child(1){transition-delay:.02s}
.hovermeta .gcard:hover .gart .gmeta .mrow:nth-child(2){transition-delay:.08s}
.hovermeta .gcard:hover .gart .gmeta .mrow:nth-child(3){transition-delay:.14s}
.hovermeta .gcard:hover .gart .gmeta .mrow:nth-child(4){transition-delay:.20s}

/* ── ceremony juice ──────────────────────────────────────────────
   at each card's landing moment white sparks burst over the art.
   all one-shot, transform/opacity only.
   the page-wide dim that used to ride under this (body::after at 60%
   black, keyed off .holo.stamp) is GONE on purpose: when a reveal
   stalled — a backgrounded tab pauses rAF — the overlay stayed up and
   the whole page read as "loading forever". nothing may darken content
   the visitor can already see. */
.holo.stamp .gcard,.holo.stamp .hero-feat,.holo.stamp .dkey,
.holo.stamp .hero h1,.holo.stamp .dhead h1{position:relative;z-index:96}

.cere-burst{position:absolute;left:50%;top:50%;width:5px;height:5px;margin:-2.5px;border-radius:50%;
  z-index:3;pointer-events:none;opacity:0;
  box-shadow:0 -46px 0 -1px #FFFFFF,33px -33px 0 -1.5px #EAF7FF,46px 0 0 -1px #FFFFFF,
             33px 33px 0 -1.5px #CBEBFF,0 46px 0 -1px #FFFFFF,-33px 33px 0 -1.5px #EAF7FF,
             -46px 0 0 -1px #FFFFFF,-33px -33px 0 -1.5px #CBEBFF}
.holo.combo .cere-burst{animation:cere-burst .55s cubic-bezier(.2,.7,.3,1) calc(var(--cd,0ms) + var(--bld,480ms) + 60ms) both}
@keyframes cere-burst{0%{opacity:0;transform:scale(.25)}18%{opacity:1}100%{opacity:0;transform:scale(1.9)}}

/* ── render glitch ───────────────────────────────────────────────
   while the card renders it twitches like an unstable feed: short
   scattered noise shards (not full-width stripes) tear across the
   art and the image jitters sideways, in three short bursts.
   burst positions are % of the timeline, so they scale with each
   card's own build length. */
.cere-glitch{position:absolute;inset:0;z-index:2;pointer-events:none;opacity:0;
  will-change:opacity;
  background-image:
    linear-gradient(rgba(168,178,192,.5),rgba(168,178,192,.5)),
    linear-gradient(rgba(255,255,255,.45),rgba(255,255,255,.45)),
    linear-gradient(rgba(122,134,152,.45),rgba(122,134,152,.45)),
    linear-gradient(rgba(42,192,255,.4),rgba(42,192,255,.4)),
    linear-gradient(rgba(148,158,174,.4),rgba(148,158,174,.4)),
    linear-gradient(rgba(255,59,71,.28),rgba(255,59,71,.28)),
    linear-gradient(rgba(196,206,220,.45),rgba(196,206,220,.45)),
    linear-gradient(rgba(143,227,255,.32),rgba(143,227,255,.32));
  background-size:36% 3px,18% 2px,28% 3px,15% 2px,44% 2px,20% 2px,24% 3px,13% 2px;
  background-position:8% 14%,92% 26%,26% 38%,74% 50%,12% 62%,64% 72%,34% 82%,82% 92%;
  background-repeat:no-repeat}
.holo.combo .cere-glitch{animation:cere-glitch calc(var(--bld,480ms) + 700ms) linear var(--cd,0ms) both}
/* retired continuous-static variant, kept for the ?fx experiments */
@keyframes gen-noise{
  0%{opacity:0}
  5%{opacity:.85;background-position:8% 6%,90% 15%,20% 26%,72% 37%,14% 49%,60% 60%,30% 74%,84% 88%}
  16%{opacity:.5;background-position:70% 10%,12% 22%,55% 33%,25% 45%,80% 57%,38% 68%,66% 80%,18% 92%}
  27%{opacity:.8;background-position:24% 8%,78% 19%,40% 30%,88% 42%,10% 54%,52% 66%,74% 78%,32% 90%}
  38%{opacity:.45;background-position:60% 12%,18% 24%,72% 36%,34% 48%,86% 58%,22% 70%,58% 82%,12% 94%}
  49%{opacity:.75;background-position:14% 9%,68% 20%,28% 32%,82% 44%,46% 55%,16% 67%,78% 79%,50% 91%}
  61%{opacity:.4;background-position:76% 11%,30% 23%,64% 34%,20% 46%,72% 59%,42% 71%,26% 83%,68% 93%}
  73%{opacity:.65;background-position:20% 7%,84% 18%,36% 29%,66% 41%,26% 53%,74% 65%,44% 77%,20% 89%}
  85%{opacity:.35;background-position:52% 13%,26% 25%,80% 35%,38% 47%,64% 60%,28% 72%,70% 84%,36% 94%}
  100%{opacity:0}
}
/* the same interference replays once, a few seconds after the reveal settled */
.afterglitch .cere-glitch{animation:cere-glitch calc(var(--bld,480ms) + 700ms) linear calc(var(--cd,0ms)*0.4) both}
@keyframes cere-glitch{
  0%,25%,33%,58%,66%,86%,100%{opacity:0}
  27%,31%{opacity:1;background-position:8% 14%,92% 26%,26% 38%,74% 50%,12% 62%,64% 72%,34% 82%,82% 92%}
  60%,64%{opacity:.85;background-position:66% 10%,18% 24%,58% 40%,22% 52%,80% 64%,30% 74%,70% 84%,14% 94%}
  88%,94%{opacity:1;background-position:22% 18%,76% 30%,42% 42%,60% 54%,28% 66%,84% 76%,16% 86%,52% 94%}
}
.holo.combo .feat-art .gimg{
  animation:cere-pulse .42s cubic-bezier(.3,.9,.3,1) calc(var(--cd,0ms) + var(--bld,480ms)) both}
.holo.combo .gart .gimg{
  animation:cere-pulse .42s cubic-bezier(.3,.9,.3,1) calc(var(--cd,0ms) + var(--bld,480ms)) both,
            cere-jit calc(var(--bld,480ms) + 700ms) linear var(--cd,0ms) both}
.afterglitch .gart .gimg{animation:cere-jit calc(var(--bld,480ms) + 700ms) linear calc(var(--cd,0ms)*0.4) both}
@keyframes cere-jit{
  0%,25%,33%,58%,66%,86%,100%{translate:0 0}
  27%{translate:-3px 0}29%{translate:2.5px 0}31%{translate:-1.5px 0}
  60%{translate:2.5px 0}64%{translate:-2px 0}
  88%{translate:-3.5px 0}91%{translate:3px 0}94%{translate:-1.5px 0}
}

/* ── ceremony perf guard ─────────────────────────────────────────
   backdrop blur re-rasterises everything beneath it on every frame
   of the reveal — switch the fixed chrome to solid fills while the
   projection runs, restore after. */
.holo .bar{-webkit-backdrop-filter:none;backdrop-filter:none;background:rgba(4,7,15,.97)}
.holo .livebets{-webkit-backdrop-filter:none;backdrop-filter:none}

/* ── solo replay ─────────────────────────────────────────────────
   the bars card re-renders on its own every minute (class lives on
   the CARD, not the body, so the rest of the page stays still).
   --cd is 0 here, timings hang off --bld alone. */
.solo-holo .holo-grid i{animation:holo-spark .85s cubic-bezier(.3,.7,.3,1) var(--d,0ms) both}
.solo-holo .cere-glitch{animation:cere-glitch calc(var(--bld,480ms) + 700ms) linear both}
.solo-holo .gart .gimg{animation:cere-pulse .42s cubic-bezier(.3,.9,.3,1) var(--bld,480ms) both,
                       cere-jit calc(var(--bld,480ms) + 700ms) linear both}
.solo-holo .cere-burst{animation:cere-burst .55s cubic-bezier(.2,.7,.3,1) calc(var(--bld,480ms) + 60ms) both}

/* between replays the bars card idles with a brief interference blink
   every few seconds — the glitch card is identifiable at rest, not only
   during its render. :where() keeps specificity at zero so every state
   animation (combo / afterglitch / solo) overrides it. */
:where(.gcard[data-fx="bars"]) .cere-glitch{animation:bars-idle 8s linear 2.6s infinite}
@keyframes bars-idle{
  0%,90%,93.2%,100%{opacity:0}
  90.6%,91.2%{opacity:.6;background-position:12% 20%,85% 30%,35% 42%,70% 54%,15% 66%,55% 76%,78% 86%,28% 94%}
  92.4%{opacity:.35;background-position:64% 14%,18% 28%,52% 40%,28% 52%,80% 64%,42% 74%,12% 84%,68% 92%}
}

/* ── action burst ────────────────────────────────────────────────
   the white spark scatter every primary button answers a click with */
.clickburst{position:fixed;width:6px;height:6px;margin:-3px;border-radius:50%;z-index:400;
  pointer-events:none;opacity:0;background:#fff;
  box-shadow:0 -38px 0 -1px #FFFFFF,27px -27px 0 -2px #EAF7FF,38px 0 0 -1px #FFFFFF,
             27px 27px 0 -2px #CBEBFF,0 38px 0 -1px #FFFFFF,-27px 27px 0 -2px #EAF7FF,
             -38px 0 0 -1px #FFFFFF,-27px -27px 0 -2px #CBEBFF;
  animation:clickburst .62s cubic-bezier(.2,.7,.3,1) both}
.clickburst::after{content:"";position:absolute;inset:0;border-radius:50%;
  box-shadow:0 -20px 0 -2.5px #FFFFFF,14px -14px 0 -3px #DFF2FF,20px 0 0 -2.5px #FFFFFF,
             14px 14px 0 -3px #FFFFFF,0 20px 0 -2.5px #DFF2FF,-14px 14px 0 -3px #FFFFFF,
             -20px 0 0 -2.5px #FFFFFF,-14px -14px 0 -3px #DFF2FF;
  animation:clickburst .5s cubic-bezier(.2,.7,.3,1) .06s both}
@keyframes clickburst{0%{opacity:0;transform:scale(.3)}16%{opacity:1}100%{opacity:0;transform:scale(1.65)}}
@media(prefers-reduced-motion:reduce){.clickburst{display:none}}

/* ── notify popup ────────────────────────────────────────────────
   Notify me answers with a compact card: game art, one email field,
   a done state. sits above everything except the click burst. */
.npop{position:fixed;inset:0;z-index:320;display:none;align-items:center;justify-content:center;
  padding:var(--s4);background:rgba(2,5,11,.7);backdrop-filter:blur(6px)}
.npop.on{display:flex}
.npop-card{position:relative;width:min(430px,100%);background:var(--panel);border:1px solid var(--line-2);
  border-radius:16px;padding:var(--s4);box-shadow:0 30px 80px -30px rgba(0,0,0,.8)}
.npop.on .npop-card{animation:npop-in .2s cubic-bezier(.2,.9,.3,1.2) both}
@keyframes npop-in{from{opacity:0;transform:scale(.94) translateY(8px)}to{opacity:1;transform:none}}
.npop-x{position:absolute;top:var(--s3);right:var(--s3);width:34px;height:34px;border:1px solid var(--line-2);
  border-radius:8px;color:var(--dim);font-size:var(--t-body)}
.npop-x:hover{color:var(--p);border-color:var(--p)}
.npop-head{display:flex;gap:var(--s3);align-items:center;margin-bottom:var(--s3);padding-right:var(--s5)}
.npop-art{flex:none;width:72px;aspect-ratio:3/4;border-radius:12px;overflow:hidden;border:1px solid var(--line-2);background:var(--panel-2)}
.npop-art img{width:100%;height:100%;object-fit:cover;display:block}
.npop-name{display:block;font-family:var(--disp);font-weight:700;font-size:var(--t-lead);letter-spacing:-.01em}
.npop-sub{display:block;font-size:var(--t-small);color:var(--dim);margin-top:var(--s1);line-height:1.45}
.npop-form{display:flex;gap:var(--s2)}
.npop-form input{flex:1;min-width:0;background:var(--bg);border:1px solid var(--line-2);border-radius:12px;
  color:var(--ink);padding:var(--s3) var(--s3);font-family:var(--ui);font-size:var(--t-body);outline:none}
.npop-form input:focus{border-color:var(--p)}
.npop-done{font-size:var(--t-small);text-align:center;padding:var(--s2) 0 var(--s1)}
.npop-done b{color:var(--p);font-weight:700}
@media(prefers-reduced-motion:reduce){.npop.on .npop-card{animation:none}}
@media(max-width:480px){.npop-form{flex-direction:column}.npop-form .btn{width:100%}}

/* ── type preview (temporary control) ────────────────────────────
   deliberately LIGHT on the dark page so the team can't miss it */
/* v3: the picker moved from the bar to the utility strip (see .util .fontpick),
   so the bar no longer needs to hide it below 1340px to keep the nav centred. */

.fontpick-wrap{position:relative;z-index:130}
/* живе в шапці поруч із лічильником і соцмережами, тож і виглядає як вони:
   темна пігулка з обвідкою. помітність дає МІСЦЕ, а не яскравість. */
.fontpick{font-weight:600;color:#0A1420;background:#FFFFFF;border:1px solid #FFFFFF;
  border-radius:999px;transition:.14s;
  box-shadow:0 6px 22px -8px rgba(0,0,0,.75)}
.fontpick{font-size:var(--t-small);padding:var(--s2) var(--s2);display:inline-flex;align-items:center;gap:var(--s2);white-space:nowrap}
.fontpick:hover{background:#FFFFFF;box-shadow:0 8px 26px -8px rgba(0,0,0,.85);transform:translateY(-1px)}
.fontpick[aria-expanded="true"]{box-shadow:0 0 0 3px rgba(42,192,255,.35),0 8px 26px -8px rgba(0,0,0,.85)}
.fontpick .aa{color:#0A1420;font-family:var(--disp);font-weight:700;flex:none}
/* назви шрифтів різної довжини: від "Teko" до "Barlow Condensed" — це
   127px проти 183px пігулки. Пігулка стоїть у ряду шапки, тож на кожному
   виборі зсувала сусіда ліворуч на 56px. Ширина в em, а не px, щоб
   трималась і в бургер-меню, де кегль більший. 9.3em — найдовша назва
   з 34 наявних, тож нічого не обрізається. */
.fontpick b{flex:none;width:9.3em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:left}
/* панель росте ВГОРУ від пігулки — вона живе в нижньому куті */
.fontpick-panel{position:absolute;right:0;top:calc(100% + var(--s2));width:268px;
  background:var(--panel-2);border:1px solid var(--p);border-radius:16px;padding:var(--s2);
  box-shadow:0 28px 64px -24px rgba(0,0,0,.9),0 0 0 4px rgba(42,192,255,.09)}
.fontpick-panel[hidden]{display:none}
.fp-head{display:flex;justify-content:space-between;align-items:center;gap:var(--s2);
  padding:var(--s2) var(--s2) var(--s2);font-size:var(--t-label);letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
.fp-head span{color:var(--dim);font-weight:700}
.fp-list{list-style:none;margin:0;max-height:min(52vh,420px);overflow:auto;scrollbar-width:thin}
.fp-opt{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s2);
  padding:var(--s2) var(--s2);border-radius:8px;cursor:pointer;color:var(--dim)}
.fp-opt b{font-weight:700;font-size:var(--t-body);color:var(--ink);line-height:1.2}
.fp-opt span{flex:none;font-size:var(--t-label);color:var(--faint)}
.fp-opt:hover,.fp-opt.active{background:rgba(42,192,255,.13)}
.fp-opt[aria-selected="true"]{background:rgba(42,192,255,.09)}
.fp-opt[aria-selected="true"]::after{content:"✓";flex:none;color:var(--p);font-size:var(--t-small);font-weight:700}
.fontpick b{color:#0A1420;font-weight:700}
@media(max-width:560px){
  .fontpick-panel{width:min(248px,calc(100vw - 28px))}
}
/* wide display faces need one step down so the headline holds its lines */

/* ── contact · the lab report ────────────────────────────────────
   feedback reads as a playful session report, not a mail form:
   pick the game, rate the session on the multiplier chain, set the
   volatility taste on a slider, tap what to tune. */
.chero{padding:var(--s7) var(--pad) var(--s2);text-align:center}
.chero .eyebrow{justify-content:center}
.chero h1{font-family:var(--disp);font-weight:700;font-size:var(--t-h2);letter-spacing:-.02em;line-height:1;margin-top:var(--s3)}
.chero .sub{margin:var(--s3) auto 0;color:var(--dim);font-size:var(--t-lead);max-width:52ch}
.labform{width:min(800px,100%);margin:0 auto;padding:var(--s4) var(--pad) var(--s7);display:grid;gap:var(--s3);counter-reset:q}
.qcard{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:var(--s4)}
.qtitle{font-family:var(--disp);font-weight:700;font-size:var(--t-lead);margin-bottom:var(--s3)}
.qtitle::before{counter-increment:q;content:counter(q,decimal-leading-zero);color:var(--p);margin-right:var(--s2);font-size:.82em}
.qhint{font-size:var(--t-small);color:var(--faint);margin:calc(var(--s2) * -1) 0 var(--s3)}

.gpick{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--s2)}
.gpk{position:relative;display:block;aspect-ratio:3/4;border:1px solid var(--line-2);border-radius:12px;overflow:hidden;cursor:pointer;transition:border-color .15s,transform .15s,box-shadow .15s}
.gpk:hover{transform:translateY(-2px);border-color:var(--p)}
.gpk input{position:absolute;opacity:0;pointer-events:none}
.gpk img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.gpk::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,transparent 40%,rgba(0,0,0,.74))}
.gpk b{position:absolute;left:var(--s2);right:var(--s2);bottom:var(--s2);z-index:1;font-size:var(--t-label);font-weight:600;line-height:1.2}
.gpk .pin{position:absolute;top:var(--s2);right:var(--s2);z-index:1;width:22px;height:22px;border-radius:50%;border:1px solid rgba(255,255,255,.55);display:grid;place-items:center;font-size:var(--t-small);color:transparent;background:rgba(4,10,20,.5);transition:.15s}
.gpk:has(input:checked){border-color:var(--p);box-shadow:0 0 0 1px var(--p),0 12px 34px -16px rgba(42,192,255,.55)}
.gpk:has(input:checked) .pin{background:var(--p);border-color:var(--p);color:#02101C}
.gpk:has(input:focus-visible){outline:2px solid var(--p);outline-offset:2px}

.xscale{display:flex;gap:var(--s2);flex-wrap:wrap}
.xchip{position:relative;display:grid;gap:var(--s1);justify-items:center;min-width:96px;flex:1;padding:var(--s3) var(--s2);border:1px solid var(--line-2);border-radius:12px;cursor:pointer;transition:.15s;text-align:center}
.xchip input{position:absolute;opacity:0;pointer-events:none}
.xchip b{font-family:var(--disp);font-weight:700;font-size:var(--t-lead)}
.xchip span{font-size:var(--t-label);color:var(--dim)}
.xchip:hover{border-color:var(--p)}
.xchip:has(input:checked){border-color:var(--p);background:rgba(42,192,255,.1)}
.xchip:has(input:checked) b{color:var(--p)}
.xchip:has(input:focus-visible){outline:2px solid var(--p);outline-offset:2px}

.volrow{display:grid;grid-template-columns:auto 1fr auto auto;align-items:center;gap:var(--s3)}
.volend{font-size:var(--t-label);color:var(--faint);text-transform:uppercase;letter-spacing:.07em}
.volrow output{font-family:var(--disp);font-weight:700;font-size:var(--t-body);color:var(--p);border:1px solid var(--line-2);border-radius:8px;padding:var(--s2) var(--s3);min-width:96px;text-align:center}
.volrow input[type=range]{-webkit-appearance:none;appearance:none;height:26px;background:none;min-width:0;cursor:pointer}
.volrow input[type=range]::-webkit-slider-runnable-track{height:6px;border-radius:4px;background:linear-gradient(90deg,#24D6BA,#2AC0FF 55%,#1E7BE0)}
.volrow input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:20px;height:20px;margin-top:calc(var(--s2) * -1);border-radius:50%;background:#fff;border:3px solid var(--p);box-shadow:0 0 12px rgba(42,192,255,.6)}
.volrow input[type=range]::-moz-range-track{height:6px;border-radius:4px;background:linear-gradient(90deg,#24D6BA,#2AC0FF 55%,#1E7BE0)}
.volrow input[type=range]::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:#fff;border:3px solid var(--p)}

.mchips{display:flex;gap:var(--s2);flex-wrap:wrap}
.mchip{position:relative;cursor:pointer}
.mchip input{position:absolute;opacity:0;pointer-events:none}
.mchip span{display:inline-block;font-size:var(--t-small);font-weight:600;color:var(--dim);border:1px solid var(--line-2);border-radius:999px;padding:var(--s2) var(--s3);transition:.15s}
.mchip:hover span{color:var(--ink);border-color:var(--p)}
.mchip input:checked+span{background:var(--p);color:#02101C;border-color:var(--p)}
.mchip input:focus-visible+span{outline:2px solid var(--p);outline-offset:2px}

.labform textarea{width:100%;background:var(--bg);border:1px solid var(--line-2);border-radius:12px;color:var(--ink);padding:var(--s3) var(--s3);font-family:var(--ui);font-size:var(--t-body);resize:vertical;outline:none;min-height:96px}
.labform textarea:focus{border-color:var(--p)}
.mailrow{display:flex;gap:var(--s2);margin-top:var(--s3);flex-wrap:wrap}
.mailrow input{flex:1;min-width:220px;background:var(--bg);border:1px solid var(--line-2);border-radius:12px;color:var(--ink);padding:var(--s3) var(--s3);font-size:var(--t-body);font-family:var(--ui);outline:none}
.mailrow input:focus{border-color:var(--p)}
.labform .small{margin-top:var(--s3);font-size:var(--t-small)}
.maillink{color:var(--p)}
.form-done{text-align:center;display:grid;gap:var(--s2);justify-items:center;padding:var(--s6)}
.form-done[hidden]{display:none}
.form-done b{font-family:var(--disp);font-weight:700;font-size:var(--t-h3)}
.form-done p{max-width:40ch}
.labform.sent .qsec{display:none}

@media(max-width:640px){
  .gpick{grid-template-columns:repeat(3,1fr)}
  .gpk b{font-size:var(--t-label)}
  .xchip{min-width:74px;padding:var(--s2) var(--s2)}
  .volrow{grid-template-columns:auto 1fr auto}
  .volrow output{grid-column:1/-1;justify-self:center}
}

/* ════════════════════════════════════════════════════════════════
   SCROLL-DRIVEN REVEAL · a card-scoped run must not touch the hero
   ════════════════════════════════════════════════════════════════
   the catalogue now projects as it scrolls into view, so project()
   runs again long after the hero has settled. without this guard the
   hero re-ran its whole ceremony (shell fade + shake) every time a
   card came into view, or a filter/sort tab was pressed. */
.holo.cards-only .hero-feat,.holo.cards-only .dkey,
.holo.cards-only .feat-art .gimg,.holo.cards-only .dkey .feat-art,
.holo.cards-only .hero h1,.holo.cards-only .dhead h1{animation:none}

/* ════════════════════════════════════════════════════════════════
   WAITING CLOCK · the demo stage keeps time until the URL lands
   ════════════════════════════════════════════════════════════════
   hands sweep (minute fast, hour 12x slower), a flask-blue arc runs
   the rim once per minute-turn, and a halo pulses out on each pass —
   the card reads as "counting down", not "broken". */
.wclock{width:clamp(58px,5.4vw,88px);height:auto;overflow:visible;color:var(--p);display:block}
.wc-face{fill:rgba(42,192,255,.05);stroke:none}
.wc-ring{fill:none;stroke:var(--line-2);stroke-width:2}
.wc-sweep{fill:none;stroke:var(--p);stroke-width:2;stroke-linecap:round;
  stroke-dasharray:34 111;stroke-dashoffset:145;
  transform:rotate(-90deg);transform-origin:32px 32px;
  filter:drop-shadow(0 0 5px rgba(42,192,255,.7));
  animation:wc-sweep 3s cubic-bezier(.45,0,.55,1) infinite}
@keyframes wc-sweep{0%{stroke-dashoffset:145;opacity:.2}35%{opacity:1}100%{stroke-dashoffset:0;opacity:.2}}
.wc-halo{fill:none;stroke:var(--p);stroke-width:1.2;opacity:0;
  transform-origin:32px 32px;animation:wc-halo 3s ease-out infinite}
@keyframes wc-halo{0%{opacity:.45;transform:scale(.82)}72%,100%{opacity:0;transform:scale(1.26)}}
.wc-ticks line{stroke:var(--line-2);stroke-width:1.7;stroke-linecap:round}
.wc-hand{stroke-linecap:round;transform-origin:32px 32px}
.wc-m{stroke:currentColor;stroke-width:2.4;animation:wc-turn 3s linear infinite}
.wc-h{stroke:var(--dim);stroke-width:3;animation:wc-turn 36s linear infinite}
@keyframes wc-turn{to{transform:rotate(360deg)}}
.wc-pin{fill:currentColor}
.demo-wait{transition:opacity .3s}
.demo-wait b{animation:wait-breathe 3s ease-in-out infinite}
@keyframes wait-breathe{0%,100%{opacity:.72}50%{opacity:1}}
@media(prefers-reduced-motion:reduce){
  .wc-sweep,.wc-halo,.wc-m,.wc-h,.demo-wait b{animation:none}
  .wc-sweep{stroke-dashoffset:0;opacity:.85}
}

/* ════════════════════════════════════════════════════════════════
   DROPDOWN · a real listbox, not a native <select>
   ════════════════════════════════════════════════════════════════
   single or multi (data-multi). the panel scales out of the button,
   options stagger in, the caret flips. keyboard is the full listbox
   contract: arrows/Home/End move, Enter/Space picks, Esc closes. */
.drop{position:relative}
/* label + value stand on one baseline, and that line is centred in the
   button (a wrapping flex line can be centred with align-content) */
.drop-btn{display:flex;flex-wrap:wrap;align-content:center;align-items:baseline;justify-content:space-between;gap:var(--s3);width:100%;
  background:var(--bg);border:1px solid var(--line-2);border-radius:12px;
  padding:var(--s2) var(--s3);font-family:var(--ui);font-size:var(--t-body);font-weight:600;
  color:var(--faint);text-align:left;transition:border-color .15s,color .15s,box-shadow .15s}
.drop-btn:hover{border-color:var(--p);color:var(--ink)}
.drop-btn.filled{color:var(--ink)}
.drop.on .drop-btn{border-color:var(--p);color:var(--ink);box-shadow:0 0 0 3px rgba(42,192,255,.13)}
.drop-val{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.drop-n{flex:none;font-family:var(--disp);font-size:var(--t-label);font-weight:700;color:#02101C;
  background:var(--p);border-radius:999px;padding:var(--s1) var(--s2);margin-left:auto}
.drop-caret{align-self:center;width:11px;height:7px;flex:none;stroke:currentColor;stroke-width:1.9;fill:none;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .24s cubic-bezier(.3,1.1,.4,1)}
.drop.on .drop-caret{transform:rotate(180deg);color:var(--p)}
.drop-list{position:absolute;left:0;right:0;top:calc(100% + var(--s2));z-index:60;margin:0;
  background:var(--panel-2);border:1px solid var(--p);border-radius:16px;padding:var(--s2);
  list-style:none;max-height:min(340px,42vh);overflow:auto;scrollbar-width:thin;
  box-shadow:0 28px 64px -24px rgba(0,0,0,.9),0 0 0 4px rgba(42,192,255,.09);
  opacity:0;transform:translateY(-10px) scale(.97);transform-origin:top center;
  pointer-events:none;visibility:hidden;
  transition:opacity .16s ease,transform .24s cubic-bezier(.3,1.12,.4,1),visibility 0s .24s}
.drop.on .drop-list{opacity:1;transform:none;pointer-events:auto;visibility:visible;transition-delay:0s}
.drop.up .drop-list{top:auto;bottom:calc(100% + var(--s2));transform-origin:bottom center}
.drop-opt{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s3);border-radius:8px;
  font-size:var(--t-small);font-weight:600;color:var(--dim);cursor:pointer;user-select:none;
  opacity:0;transform:translateX(-10px);transition:background .14s,color .14s}
.drop.on .drop-opt{opacity:1;transform:none;
  transition:background .14s,color .14s,
             opacity .2s ease var(--od,0ms),
             transform .3s cubic-bezier(.25,1.15,.4,1) var(--od,0ms)}
.drop-opt:hover,.drop-opt.active{background:rgba(42,192,255,.13);color:var(--ink)}
.drop-opt[aria-selected="true"]{color:var(--ink)}
.drop[data-single] .drop-opt[aria-selected="true"]::after{content:"✓";margin-left:auto;
  flex:none;color:var(--p);font-size:var(--t-small);font-weight:700}
.drop-tick{width:17px;height:17px;flex:none;border-radius:4px;border:1px solid var(--line-2);
  display:grid;place-items:center;font-size:var(--t-label);line-height:1;color:transparent;transition:.14s}
.drop[data-single] .drop-tick{border-radius:50%}
.drop-opt[aria-selected="true"] .drop-tick{background:var(--p);border-color:var(--p);color:#02101C}
@media(prefers-reduced-motion:reduce){
  .drop-list,.drop.on .drop-opt{transition:none}
  .drop-opt{opacity:1;transform:none}
}

/* ════════════════════════════════════════════════════════════════
   CONTACT · ONE SCREEN, NO SCROLL
   ════════════════════════════════════════════════════════════════
   the lab report used to run ~2.5 viewports. it is now a two-column
   console: a fixed rail carries the title, the pitch and the send
   button, the questions sit in a compact grid beside it. every
   vertical measurement below is vh-driven, so the whole thing
   compresses instead of spilling. below 1040px wide (or on a very
   short window) it drops back to an ordinary scrolling page —
   clipping content is worse than scrolling it. */
/* client 05.10: no more one-screen box — it clipped (v4's taller footer
   ran over the form) and centring left ~250px of air above the title.
   An ordinary page now, footer held at the bottom like .docpage. */
body.onescreen{min-height:100svh;display:flex;flex-direction:column}
body.onescreen>.bar{flex:0 0 auto}
body.onescreen>main{flex:1 0 auto;display:flex;flex-direction:column}
body.onescreen main>footer{margin-top:auto}
/* Клієнт 25.09: підвал має бути однаковий на всіх сторінках. Раніше на
   контактних він був стиснутий до 9-18px заради одноекранності — але
   заміряно, що вони вміщаються в екран і з повними 24px на 1470x900,
   1440x722, 1280x800 і 1920x1080. flex:0 0 auto лишається: він тримає
   підвал від розтягування у флекс-колонці, до висоти стосунку не має. */
body.onescreen>main>footer{flex:0 0 auto}

.lab{display:grid;grid-template-columns:minmax(250px,335px) minmax(0,1fr);
  gap:var(--s6);align-items:start;
  padding:var(--s6) var(--gut) var(--section);width:100%}

.lab-rail{display:flex;flex-direction:column;justify-content:flex-start;
  gap:var(--s2);min-width:0}
.lab-rail h1{font-family:var(--disp);font-weight:700;letter-spacing:-.025em;line-height:.97;
  font-size:var(--t-h2)}
.lab-rail .sub{color:var(--dim);font-size:var(--t-lead);line-height:1.6;max-width:36ch}
.rail-foot{margin-top:var(--s4);display:grid;gap:var(--s2);justify-items:start}
.rail-foot .btn{padding:0 var(--s4)}
.rail-foot .small{font-size:var(--t-small);color:var(--dim)}
/* the send button lives in the rail but drives the form beside it */
.lab:has(.labform.sent) .rail-foot{display:none}

.lab .labform{width:auto;max-width:none;margin:0;padding:0;align-content:start;
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s2)}
.q-games,.q-rate,.q-note,.lab .form-done{grid-column:1/-1}

.lab .qcard{padding:var(--s3) var(--s3)}
.lab .qtitle{font-size:var(--t-lead);margin-bottom:var(--s2)}
.lab .qtitle::before{margin-right:var(--s2)}
/* the posters are sized off the VIEWPORT HEIGHT, not the column width —
   that is what keeps five 3:4 keys inside one screen */
/* the posters are HEIGHT-driven (they must never push a one-screen page
   into scroll), so their row width is a consequence, not a setting. both
   are tokens because the questions column on Contact 1 is computed from
   them on large screens — see --qcol. */
.lab{--gpk-cap:192px;--gpk-gap:var(--s2);
  --gpk-h:clamp(96px,max(14vh,6vw),var(--gpk-cap))}
.lab .gpick{display:flex;flex-wrap:wrap;gap:var(--gpk-gap)}
.lab .gpk{aspect-ratio:3/4;height:var(--gpk-h);width:auto;flex:0 0 auto}
.lab .gpk b{font-size:var(--t-label)}
.lab .xscale{gap:var(--s2)}
.lab .xchip{min-width:0;padding:var(--s2) var(--s2)}
.lab .xchip b{font-size:var(--t-body)}
.lab .volrow{gap:var(--s2)}
.lab .volrow output{min-width:84px;padding:var(--s2) var(--s2)}
.lab textarea{height:clamp(50px,8.2vh,110px);min-height:0;resize:none}
.lab .mailrow{margin-top:var(--s2)}
.lab .mailrow input{min-width:0}
.lab .form-done{padding:var(--s5)}

/* the count that tells you this picker takes more than one */
.qtitle-row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s3);
  margin-bottom:var(--s2)}
.qtitle-row .qtitle{margin-bottom:0}
.qhint{flex:none;font-size:var(--t-label);font-weight:600;letter-spacing:.03em;color:var(--faint)}
.qhint.on{color:var(--p)}
/* multi-select reads as squares, single-select as circles */
.gpick.multi .pin{border-radius:8px}

/* докнутий фід стоїть у правому нижньому куті, а футер одноекранної
   сторінки лежить прямо під ним. раніше вбік відсувався ВЕСЬ футер
   (padding-right), і разом із ним центрована навігація їхала на 159px від
   центру сторінки — а клієнт просив саме центровану. тепер паддінги
   симетричні, а з дороги йде лише правий блок, рівно на слід дока. */
/* на одноекранних сторінках дока НЕМА. між формою і футером лишається ~40px,
   а сам док 48px — він не вміщається туди ніяк: або накриває кнопку Send,
   або "Responsible play" у футері. контактна сторінка це задача, а не вітрина,
   тож віджет живих ставок їй нічого не додає. разом із ним пішли й усі
   контортації футера, які існували тільки щоб його обійти. */
body.onescreen .livebets{display:none}

@media(max-width:1040px){
  /* Тут одноекранність вимкнена — сторінка вільно росте. Але підвал
     усе одно тримаємо внизу, інакше на планшеті під ним лишалась
     пустка (39px на 768x1024). Та сама схема, що й на .docpage.
     .lab доводиться скинути явно: поза цим запитом він має
     flex:1 1 auto;min-height:0 для розтягування в одноекранному
     режимі, і у звичайному потоці це дало б йому стиснутись. */
  .lab{grid-template-columns:1fr;gap:var(--s5)}
  .lab-rail .sub{max-width:52ch}
  .rail-foot{margin-top:var(--s1)}
  .lab .gpk{height:clamp(112px,26vw,170px)}
  .lab textarea{resize:vertical}
}
@media(max-width:760px){
  .lab .labform{grid-template-columns:1fr}
  /* five posters wrapped 4 + 1 and read as a mistake — three up reads
     as a deliberate grid and gives each key more room */
  .lab .gpick{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s2)}
  .lab .gpk{height:auto;width:auto}
}

/* the crumb rides in the rail on the one-screen contact page */
.lab-crumb{padding:0 0 var(--s1)}
/* an open panel must clear the cards that come after it in the grid */
/* above the docked live feed (z-index 120), not just its siblings */
.qcard:has(.drop.on){position:relative;z-index:130}

/* ════════════════════════════════════════════════════════════════
   CONTACT · PLAIN FORM
   ════════════════════════════════════════════════════════════════
   the client's brief: who are you → your email → a few lines → goes
   to an inbox. one column, still one screen, still no scroll. the
   fuller lab report lives on contact-lab.html and keeps the two-up
   grid above. */
/* on the page's 12 columns, from --edge (client 05.10): the rail on 1–5,
   the form on 7–12 — the hero's split */
.lab-simple{grid-template-columns:repeat(12,minmax(0,1fr));column-gap:var(--gap);row-gap:var(--s5)}
.lab-simple>.lab-rail{grid-column:1/6}
.lab-simple>.labform{grid-column:7/13}
.lab-simple .labform{grid-template-columns:minmax(0,1fr);gap:var(--s3)}
.lab-simple .qcard{padding:var(--s3) var(--s4)}
/* .fld is a STANDALONE class: on Contact 1 the email box lives in the
   rail and is only tied to the form by the form= attribute, so it is
   not a descendant of .labform and a scoped selector missed it. */
.fld{width:100%;background:var(--bg);border:1px solid var(--line-2);border-radius:12px;
  color:var(--ink);padding:var(--s2) var(--s3);font-family:var(--ui);font-size:var(--t-body);outline:none}
.fld:focus{border-color:var(--p)}
.fld::placeholder{color:var(--faint)}
/* the browser's autofill wash is opaque and light — repaint it */
.fld:-webkit-autofill,.fld:-webkit-autofill:hover,.fld:-webkit-autofill:focus,
.mailrow input:-webkit-autofill,.su-row input:-webkit-autofill{
  -webkit-box-shadow:0 0 0 1000px var(--bg) inset;-webkit-text-fill-color:var(--ink);
  caret-color:var(--ink)}
.sendrow{display:flex;justify-content:flex-end;margin-top:var(--s3)}
.sendrow .btn{padding:0 var(--s4)}
/* rich variant: who-are-you sits beside the reply address */
.whorow{display:grid;grid-template-columns:minmax(0,230px) minmax(0,1fr);gap:var(--s2);align-items:center}
/* a required answer that was skipped */
.drop.invalid .drop-btn{border-color:#FF5A6E;color:var(--ink);box-shadow:0 0 0 3px rgba(255,90,110,.16)}
@media(max-width:1040px){
  .lab-simple>.lab-rail,.lab-simple>.labform{grid-column:1/-1}
  .lab-simple .labform{max-width:600px;width:100%}
}
@media(max-width:760px){.whorow{grid-template-columns:1fr}}

/* ════════════════════════════════════════════════════════════════
   CONTACT 1 · ROLE-DRIVEN FORM
   ════════════════════════════════════════════════════════════════
   the restored fuller form. the old one asked everybody every question
   down a flat 2.5-screen stack — no hierarchy, so nothing led. here the
   ROLE is the first decision and it swaps the block beneath it, which
   is also what keeps the whole thing on one screen. */
.roles-wrap{grid-column:1/-1;display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap}
.roles-lab{flex:none;font-size:var(--t-label);letter-spacing:.09em;text-transform:uppercase;color:var(--faint)}
.roles{display:flex;gap:var(--s2);flex-wrap:wrap;min-width:0}
.role{position:relative;cursor:pointer}
.role input{position:absolute;opacity:0;pointer-events:none}
.role span{display:inline-block;white-space:nowrap;font-size:var(--t-small);font-weight:600;color:var(--dim);
  border:1px solid var(--line-2);border-radius:999px;padding:var(--s2) var(--s3);transition:.15s}
.role:hover span{color:var(--ink);border-color:var(--p)}
.role input:checked+span{background:var(--p);color:#02101C;border-color:var(--p);
  box-shadow:0 10px 28px -12px rgba(42,192,255,.75)}
.role input:focus-visible+span{outline:2px solid var(--p);outline-offset:2px}
.roles-wrap.invalid .role span{border-color:#FF5A6E}

/* the active block is itself a two-up grid, so its cards keep the same
   rhythm as the rest of the form */
.role-block{grid-column:1/-1;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));
  gap:var(--s2);align-content:start}
.role-block[hidden]{display:none}
.role-block .q-wide{grid-column:1/-1}
.role-block>section{animation:role-in .34s cubic-bezier(.25,1,.4,1) both}
.role-block>section:nth-child(2){animation-delay:.05s}
.role-block>section:nth-child(3){animation-delay:.1s}
.role-block>section:nth-child(4){animation-delay:.15s}
@keyframes role-in{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){.role-block>section{animation:none}}


/* ════════════════════════════════════════════════════════════════
   CONTACT 1 · QUIETER
   ════════════════════════════════════════════════════════════════
   the page was carrying four levels of box at once: a panel per
   question, a frame per poster, a frame per chip, and the pills on
   top. the questions give up their panels — spacing separates them
   instead — and the numbering goes, so the only framed things left
   are the ones you actually click. */
.lab-roles .qcard{background:none;border:0;border-radius:0;padding:0}
.lab-roles .role-block{gap:var(--s3)}
.lab-roles .labform{gap:var(--s4)}
.lab-roles .qtitle{font-family:var(--ui);font-size:var(--t-small);font-weight:600;letter-spacing:.01em;
  color:var(--dim);margin-bottom:var(--s2)}
.lab-roles .qtitle::before{content:none}        /* 01 / 02 / 03 off */
.lab-roles .qtitle-row{margin-bottom:var(--s2)}
.lab-roles .qhint{font-size:var(--t-label);color:var(--faint)}
.lab-roles .qhint.on{color:var(--dim)}

/* the multiplier row loses its five boxes and becomes one segmented
   control — still five targets, a quarter of the ink */
.lab-roles .xscale{gap:0;border:1px solid var(--line);border-radius:12px;overflow:hidden}
.lab-roles .xchip{border:0;border-radius:0;border-left:1px solid var(--line);padding:var(--s2) var(--s2)}
.lab-roles .xchip:first-child{border-left:0}
.lab-roles .xchip:has(input:checked){background:rgba(42,192,255,.12)}
.lab-roles .xchip span{color:var(--faint)}

/* the slider row no longer sits in a panel, so it needs its own floor */
.lab-roles .volrow{border:1px solid var(--line);border-radius:12px;padding:var(--s2) var(--s3)}

/* ════════════════════════════════════════════════════════════════
   CONTACT 1 · COMPOSED
   ════════════════════════════════════════════════════════════════
   one fixed frame, whatever the role. the two columns share a top
   line; the role strip never moves (it is a tab bar, and tabs do not
   jump); the form completes inside its own column — questions, then
   the message, then email + send — so the eye runs top to bottom and
   stops at the button. the rail is copy only. on tall screens the
   whole block is capped and centred as ONE piece, which keeps the
   strip fixed there as well. */
.lab-roles{align-items:start;align-content:start;
  grid-template-columns:minmax(240px,330px) minmax(0,1fr);
  column-gap:var(--s7);
  padding-top:var(--s6);padding-bottom:var(--section)}
.lab-roles .lab-rail{justify-content:flex-start;gap:var(--s2)}
.lab-roles .lab-rail .small{margin-top:var(--s2)}
.lab-roles .labform{grid-template-columns:minmax(0,1fr);gap:var(--s4);align-content:start}

/* the roles are a tab strip — the same component as the games filter */
.lab-roles .roles-wrap{gap:var(--s3)}
.lab-roles .roles{gap:var(--s1);background:var(--panel);border:1px solid var(--line);border-radius:999px;padding:var(--s1)}
.lab-roles .role span{border:0;padding:var(--s2) var(--s3);color:var(--dim)}
.lab-roles .role:hover span{color:var(--ink)}
.lab-roles .role input:checked+span{background:var(--p);color:#02101C;box-shadow:none}
.lab-roles .roles-wrap.invalid .roles{border-color:#FF5A6E}

/* message + reach-me close the column, set off by one hairline */
.q-msg{display:grid;gap:var(--s2);border-top:1px solid var(--line);padding-top:var(--s3)}
.q-msg textarea{width:100%;background:var(--bg);border:1px solid var(--line-2);border-radius:12px;
  color:var(--ink);padding:var(--s3) var(--s3);font-family:var(--ui);font-size:var(--t-body);outline:none;resize:none;
  height:clamp(58px,8vh,110px)}
.q-msg textarea:focus{border-color:var(--p)}
.q-msg .mailrow{display:flex;gap:var(--s2);margin:0}
.q-msg .mailrow .fld{flex:1;min-width:0}
.q-msg .mailrow .btn{flex:none;padding:0 var(--s4)}

/* sent: only the done card remains, centred where the form was */
.lab-roles .labform.sent .roles-wrap,.lab-roles .labform.sent .role-block,.lab-roles .labform.sent .q-msg{display:none}
.lab-roles .labform.sent{align-content:center;min-height:min(60vh,420px)}

@media(max-width:1040px){
  /* .lab drops to one column here, but .lab-roles re-states the two-column
     track later in the file and outranks it, so without this the questions
     column stayed and collapsed to 0px on a phone (posters 2x3px, 143px of
     horizontal overflow). */
  .lab-roles{align-items:stretch;
    grid-template-columns:minmax(0,1fr)}
  .lab-roles .roles-wrap{justify-content:center}
  .lab-roles .roles{flex-wrap:wrap;justify-content:center;border-radius:16px}
}
@media(max-width:600px){.q-msg .mailrow{flex-wrap:wrap}.q-msg .mailrow .btn{width:100%}}

/* ── game picker · unreleased games are locked ───────────────────
   they keep their place in the row (the line-up is part of the pitch)
   but read as not-yet: SOON tag where the check would be, dimmed,
   no hover lift, not-allowed cursor. the input underneath is disabled. */
.gpk.is-soon{cursor:not-allowed;opacity:.55;filter:saturate(.55)}
.gpk.is-soon:hover{transform:none;border-color:var(--line-2)}
.gpk.is-soon .pin{display:none}
.gpk.is-soon::before{content:"SOON";position:absolute;top:var(--s2);right:var(--s2);z-index:1;
  font-size:var(--t-label);font-weight:700;letter-spacing:.06em;line-height:1;
  padding:var(--s1) var(--s2);border-radius:8px;background:var(--faint);color:#fff}

/* ════════════════════════════════════════════════════════════════
   TERMS · document index
   ════════════════════════════════════════════════════════════════
   "Responsible play" used to be a fifth footer link, which is what made
   the footer nav out of step with the header. it is a DOCUMENT, not a
   destination, so it lives here with the rest of them and the footer
   goes back to mirroring the header. rows are one hit target each. */
.docs-sec{padding:var(--sec) var(--gut);
  max-width:calc(var(--wide) + 2 * var(--pad));margin:0 auto}
.docs-head{max-width:62ch;margin-bottom:var(--s6)}
.docs-head h1{font-family:var(--disp);font-weight:700;letter-spacing:-.025em;line-height:1.02;
  font-size:var(--t-h2);margin:var(--s2) 0 var(--s3)}
.docs-head .sub{color:var(--dim);font-size:var(--t-lead);line-height:1.6}

.doclist{list-style:none;border-top:1px solid var(--line)}
.doc{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto;
  align-items:baseline;column-gap:var(--s6);row-gap:var(--s2);
  padding:var(--s4) 0;border-bottom:1px solid var(--line);transition:border-color .15s}
.doc:hover{border-color:var(--line-2)}
/* the whole row is the target, but the link keeps its own accessible name */
.doc-hit::after{content:"";position:absolute;inset:0}
.doc-hit:focus-visible{outline:none}
.doc-hit:focus-visible::after{outline:2px solid var(--p);outline-offset:4px;border-radius:12px}
.doc-name{font-family:var(--disp);font-weight:700;font-size:var(--t-h3);
  letter-spacing:-.01em;color:var(--ink);transition:color .15s}
.doc:hover .doc-name{color:var(--p)}
.doc-sub{grid-column:1;color:var(--dim);font-size:var(--t-body);line-height:1.55;max-width:74ch}
.doc-meta{grid-row:1;grid-column:2;justify-self:end;white-space:nowrap;
  font-size:var(--t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--faint)}
.doc-meta em{font-style:normal;color:var(--dim);font-weight:600}
.docs-foot{margin-top:var(--s5);color:var(--faint);font-size:var(--t-small);line-height:1.6;max-width:70ch}
.docs-foot a{color:var(--p)}
@media(max-width:640px){
  .doc{grid-template-columns:minmax(0,1fr)}
  .doc-meta{grid-row:auto;grid-column:1;justify-self:start}
}

/* ── підвал притиснутий донизу ────────────────────────────────
   Клієнт 25.09: порожнеча має бути МІЖ контентом і підвалом, а не
   під підвалом. Зі згорнутими вкладками сторінка коротша за екран,
   і підвал висів посеред нього, а нижче лишалась пустка.
   Той самий прийом, що вже працює для контактних (.onescreen), але
   без фіксованої висоти й overflow:hidden — тут сторінка мусить
   вільно рости, щойно розгорнули документ. Тоді margin-top:auto
   просто нічого не додає, і підвал іде за текстом як звичайно.
   Клас, а не :has(.legal-stack) — щоб не залежати від підтримки. */
body.docpage{min-height:100svh;display:flex;flex-direction:column}
body.docpage>main{flex:1 0 auto;display:flex;flex-direction:column}
body.docpage main>footer{margin-top:auto}

/* ── юридичні сторінки: ряд вкладок + панель ──────────────────
   Клієнт 25.09: три документи лежали трьома окремими сторінками,
   кожна — довгим нерозчленованим скролом. Тепер це ряд із трьох
   вкладок, а повний текст розкривається під ними на всю ширину.
   Три адреси лишились робочими: кожна відкриває свою вкладку.

   Спершу це було <details>/<summary> у три колонки — і воно не
   злетіло двічі. У колонці 467px документ на 1400px лишав дві
   третини екрана порожніми. А спроба розтягнути саму панель через
   display:contents на <details> не працює в принципі: браузер
   тримає вміст у власній UA-обгортці, тож у грід потрапляє лише
   заголовок. Звідси явні кнопки й панелі — однаково в усіх
   браузерах, без залежності від ::details-content. */
/* Розмітка — пари "вкладка + її панель" поспіль. На телефоні цього
   досить: природний порядок і є потрібним. На широкому екрані грід
   розкладає їх явно — вкладки в перший рядок, кожна панель у ДРУГИЙ
   рядок СВОЄЇ колонки, тож текст завжди стоїть під своїм заголовком. */
.legal-stack{display:grid;grid-template-columns:minmax(0,1fr);
  gap:var(--s3);border-top:1px solid var(--line);padding-top:var(--s5)}
@media(min-width:901px){
  .legal-stack{grid-template-columns:repeat(3,minmax(0,1fr));align-items:start}
  .legal-stack>:nth-child(1){grid-area:1/1}
  .legal-stack>:nth-child(2){grid-area:2/1}
  .legal-stack>:nth-child(3){grid-area:1/2}
  .legal-stack>:nth-child(4){grid-area:2/2}
  .legal-stack>:nth-child(5){grid-area:1/3}
  .legal-stack>:nth-child(6){grid-area:2/3}
}
.lc-top{display:grid;grid-template-columns:1fr auto;align-items:center;
  gap:var(--s2) var(--s3);padding:var(--s4) var(--s4);
  text-align:left;cursor:pointer;width:100%;
  background:var(--panel);border:1px solid var(--line);border-radius:16px;
  transition:border-color .16s,background .16s}
.lc-top:hover{border-color:var(--line-2)}
.lc-top[aria-expanded="true"]{border-color:var(--p)}
.lc-top:focus-visible{outline:2px solid var(--p);outline-offset:2px}
.lc-head{grid-column:1;display:flex;align-items:baseline;gap:var(--s2);flex-wrap:wrap;min-width:0}
.lc-title{font-family:var(--disp);font-weight:700;letter-spacing:-.015em;
  font-size:var(--t-h3);color:var(--ink)}
.lc-top[aria-expanded="true"] .lc-title{color:var(--p)}
.lc-n{font-size:var(--t-label);letter-spacing:.06em;text-transform:uppercase;color:var(--faint);
  border:1px solid var(--line-2);border-radius:999px;padding:var(--s1) var(--s2);white-space:nowrap}
/* рівно два рядки в кожній вкладці: підписи різної довжини, а в ряду
   три шапки різної висоти читаються як збій */
.lc-sub{grid-column:1;color:var(--dim);font-size:var(--t-small);line-height:1.55;
  min-height:calc(2 * 1.55em);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
/* шеврон розтягнутий на обидва рядки правої колонки — інакше він
   чіплявся б до першого і стояв не по центру вкладки */
.lc-chev{grid-column:2;grid-row:1/-1;width:13px;height:9px;flex:none;
  fill:none;stroke:var(--faint);stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;
  transition:transform .28s cubic-bezier(.25,1,.4,1),stroke .16s}
.lc-top[aria-expanded="true"] .lc-chev{transform:rotate(180deg);stroke:var(--p)}

/* 0fr -> 1fr анімує висоту, не знаючи її в пікселях */
.lc-panel{display:grid;grid-template-rows:1fr;
  transition:grid-template-rows .3s cubic-bezier(.25,1,.4,1)}
/* .lc-panel{display:grid} має вищу вагу за службове [hidden]{display:none},
   тож закриті панелі лишались у потоці: висота 0, але рамка .lc-inner
   малювала двопіксельну риску під кожною закритою вкладкою. */
.lc-panel[hidden]{display:none}
.lc-panel.shut{grid-template-rows:0fr}
.lc-panel>.lc-inner{overflow:hidden;min-height:0}
.lc-inner{background:var(--panel);border:1px solid var(--line-2);border-radius:16px}
.lc-inner .legal-block{padding-inline:var(--s4)}
.lc-inner .legal-block:first-child{padding-top:var(--s4)}
.lc-inner .legal-block p{max-width:70ch}
.lc-inner .legal-meta{padding:0 var(--s4) var(--s4)}
/* межа між панеллю і рядом вкладок зайва — вона вже має свою рамку */
.lc-inner>.legal-block:first-child{border-top:0}

@media(max-width:900px){.lc-sub{-webkit-line-clamp:3}}
@media(prefers-reduced-motion:reduce){.lc-panel,.lc-chev{transition:none}}

/* ── юридичні сторінки: типографіка документів ───────────────────────────────────────────
   клієнт: Terms і Responsible Play ведуть на ВЛАСНІ сторінки, "як на
   решті ігрових сайтів". спільний макет на три документи; список
   .doclist унизу лишається як перехресні посилання між ними. */
.legal{max-width:74ch;border-top:1px solid var(--line)}
.legal-block{padding:var(--s5) 0;border-bottom:1px solid var(--line)}
.legal-block h2{font-family:var(--disp);font-weight:700;letter-spacing:-.01em;
  font-size:var(--t-lead);margin-bottom:var(--s2)}
.legal-block p{color:var(--dim);font-size:var(--t-body);line-height:1.65}
.legal-block p + p{margin-top:var(--s2)}
.legal-meta{margin-top:var(--s3);font-size:var(--t-label);letter-spacing:.04em;text-transform:uppercase;color:var(--faint)}
.legal-meta em{font-style:normal;color:var(--dim);font-weight:600}
/* документи ще не написані — сторінка не має вдавати, що написані */
.legal-draft{text-transform:none;letter-spacing:0;color:var(--o)}
.legal-more{margin-top:var(--s7)}
.more-lab{font-size:var(--t-label);letter-spacing:.09em;text-transform:uppercase;color:var(--faint);
  font-weight:600;margin-bottom:var(--s1)}

/* ════════════════════════════════════════════════════════════════
   МОБІЛЬНА ВЕРСІЯ
   ════════════════════════════════════════════════════════════════
   Десктоп клієнт затвердив, тож телефон його НЕ переосмислює: ті самі
   кольори, шрифти, порядок блоків, ті самі тексти. Змінюється рівно
   те, що на 390px фізично не працює — сітки, які не влазять, цілі
   дотику дрібніші за палець, і плаваючий док, який накривав контент.
   ════════════════════════════════════════════════════════════════ */

/* ── усе, де вже зникло горизонтальне меню (≤1000) ────────────── */
@media(max-width:1000px){
  /* виріз камери в ландшафті. --edge — єдине джерело бічного відступу
     (--gut дорівнює йому), тож достатньо підняти сам токен, і шапка,
     секції та підвал відходять від "чубчика" разом. */
  :root{--edge:max(var(--edge-base),env(safe-area-inset-left,0px),env(safe-area-inset-right,0px))}

  /* .nav тут display:none, а такий елемент у Grid НЕ створює трек:
     колонок лишалось три (1fr auto 1fr), а дітей стало двоє, тож
     .bar-r сідав у СЕРЕДНЮ колонку. Праворуч висіла мертва зона 40px
     і бургер не діставав до краю екрана. */
  .bar{grid-template-columns:auto 1fr}
  .bar-r{justify-self:end}
  .burger,.takeover .close{width:40px;height:40px}
  .takeover{gap:var(--s1);justify-content:center}
  .takeover a{padding:var(--s3) 0}

  /* стрілки каруселі — інструмент миші: пальцем ряд гортається сам.
     А їхні 38+38+гепи виштовхували .car-ctrl за правий край —
     409px контролів у 390px екрана. */
  .car-nav{display:none}
  /* фільтри переносяться під заголовок, тож проміжок між рядками
     .games-head стає частиною того самого ритму: заголовок → фільтри →
     картки має бути --hgap на обох кроках, а не 16 і потім --hgap */
  .games-head{row-gap:var(--hgap)}
  .car-ctrl{flex:1 1 100%;gap:var(--s2)}
  .sortdrop,.filterdrop{flex:1 1 0;min-width:0}
  /* min-width по найдовшій опції — це десктопна історія. На телефоні
     дві кнопки ділять рядок навпіл, і 17.7em виштовхували їх за екран. */
  .sortdrop .drop-btn,.filterdrop .drop-btn{width:100%;min-width:0;min-height:40px}
  /* панель ширша за свою кнопку (написи довгі), тож кожна тулиться до
     свого боку екрана, інакше вилазить за край */
  .filterdrop .drop-list{left:0;right:auto}
  .sortdrop .drop-list{left:auto;right:0}
  .sortdrop .drop-list,.filterdrop .drop-list{min-width:min(300px,calc(100vw - 2 * var(--edge)))}

  /* перемикач шрифту всередині бургер-меню: сховане правило вище
     стосується ШАПКИ, а сюди його переносить app.js на час відкриття */
  .takeover .fontpick-wrap{display:block;margin-top:var(--s3);align-self:start}
  .takeover .fontpick{font-size:var(--t-body);padding:var(--s2) var(--s3)}
  /* у меню перемикач стоїть унизу списку, тож панель розкривається
     ВГОРУ — вниз вона вилазила на 170px за нижній край екрана */
  .takeover .fontpick-panel{left:0;right:auto;top:auto;bottom:calc(100% + var(--s2));
    width:min(300px,calc(100vw - 2 * var(--edge)))}
  .takeover .fp-list{max-height:min(42svh,330px)}

  /* цілі дотику: 44px — це ширина подушечки пальця, менше дає промахи.
     лого мало 34px, пункти списків 39px, посилання в підвалі 36px. */
  .bar .brand{min-height:40px}
  .drop-opt{min-height:44px;padding-block:var(--s2)}
  .fp-opt{min-height:44px}
  .foot-legal{padding-block:var(--s3)}
  /* крихти були 15px заввишки, посилання-пошта 18px — обидва нижчі за
     мінімум WCAG 2.5.8 (24px), і на планшеті теж */
  .crumb a,.crumb em{display:inline-block;padding-block:var(--s2)}
  /* єдина іконкова кнопка, що лишилась 34px — решта підняті до 44 */
  .npop-x{width:40px;height:40px}
  .crumb{padding-top:var(--s2)}
  .maillink{display:inline-block;padding-block:var(--s2)}
}

/* ── стрічка ставок не накриває контент ───────────────────────── */
@media(max-width:900px){
  /* фіча клієнта, тож лишається. але 300px у 390px екрана накривали
     заголовок "Our games" і пів каруселі, а на game.html — саму назву
     гри. На телефоні стартує згорнутою (див. app.js): у кутку смужка
     "LIVE BETS", яка розкривається по тапу. */
  /* кут має бути кутом: було 12px збоку проти --dockb 16px знизу.
     На решті тірів ця пара завжди рівна (18/18, 24/24, 28/28). */
  .livebets{width:min(320px,calc(100vw - 2 * var(--edge)))}
  .lb-body{max-height:min(46svh,300px);overflow-y:auto}
  .lb-head{padding:var(--s2) var(--s3)}
  .lb-head button{min-width:40px;min-height:40px;font-size:var(--t-body)}
}

/* ── телефон ─────────────────────────────────────────────────── */
@media(max-width:760px){
  /* iOS Safari роздуває кегль у ландшафті, якщо не заборонити */
  html{-webkit-text-size-adjust:100%}
  /* поле дрібніше за 16px змушує iOS зумити сторінку на фокусі — і
     назад вона вже не від'їжджає. Це єдина причина числа 16. */
  .su-row input,.labform textarea,.q-msg textarea,.mailrow input,.fld,
  .npop-form input{font-size:16px}

  /* герой: колонка одна, тож примус "рівно один екран" лишав ~110px
     порожнечі між карткою гри і "Our games". Висоту задає вміст. */
  .hero{gap:var(--s5);padding-top:var(--s5)}
  /* прив'язка до vw: на 390 це ті самі 40px, що й на десктопі, але на
     360 і 320 заголовок стискається замість того, щоб вилізти */
  /* two buttons share one row on a phone: tighter tracking, not smaller type */
  .cta-row .btn{flex:1 1 0;padding-inline:var(--s3);letter-spacing:.06em}
  .hstats{gap:var(--s3) var(--s4)}

  /* картка гри: обидві дії під палець */
  .gacts .btn.sm{height:var(--s6);padding-inline:var(--s2)}
  .notify{min-height:48px}

  /* game.html */
  /* п'ять кроків у двох колонках лишали п'ятий сиротою і різали текст
     на ~165px — у стовпчик кожен крок читається цілим */
  .steps{grid-template-columns:1fr}
  .step{padding:var(--s3) var(--s3)}
  /* "x25,000" не вміщався в 60px квадрат: чотири в ряд і висота по
     вмісту замість aspect-ratio:1 */
  .rungs{grid-template-columns:repeat(4,minmax(0,1fr));gap:var(--s2)}
  .rung{aspect-ratio:auto;padding:var(--s3) var(--s1)}
  .cta-band{gap:var(--s3)}
  .cta-band .btn{width:100%;min-height:48px}
  .dkey{width:100%}
  /* чотири чипи через flex-wrap ставали 3 + 1, і VOLATILITY висів
     сиротою по центру. Сітка 2x2 читається як один блок. */
  .dchips{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s2)}
  .dchip{min-width:0}
  .dacts .btn{flex:1 1 0;min-height:48px}


  /* контактні сторінки */
  .chero{padding-inline:var(--edge)}
  .sendrow .btn{width:100%;min-height:48px}


  /* підвал: посилання були 26px і 18px заввишки — нижче за палець */
  /* .notify-sec — грід із justify-items:center, тож неявна колонка
     бралась по max-content поля вводу, а не по контейнеру: на 320px
     форма підписки вилазила на 25px */
  .notify-sec{grid-template-columns:minmax(0,1fr)}
  .nb-copy,.signup{grid-column:1/-1;grid-row:auto;justify-self:stretch;width:100%}

  .foot-nav{gap:var(--s1)}
  .foot-nav a{padding:var(--s2) var(--navpx)}
  .foot-legal{padding:var(--s2) 0}
}

/* ── будь-який тач-пристрій, незалежно від ширини ──────────────
   iPad у ландшафті — це 1024px, там показується десктопна шапка, але
   тицяють у неї пальцем. Тож дрібні другорядні посилання беремо за
   типом вказівника, а не за медіазапитом ширини. */
@media(hover:none){
  .crumb a,.crumb em,.maillink,.foot-legal{display:inline-block;padding-block:var(--s2)}
  .drop-opt,.fp-opt{min-height:44px}
}

/* ── таблиця виграшів ────────────────────────────────────────── */
/* Своя ширина таблиці — 353px, тож вона перестає вміщатись, щойно
   вьюпорт вужчий за 353 + 2 x 14 = 381px. Замість ховати колонку
   (кожна тут щось означає) віддаємо поля й кегль: цього рівно
   вистачає до 320px включно. */
@media(max-width:384px){
  .board td{font-size:var(--t-small)}
  .board th{font-size:var(--t-label)}
  .mult{font-size:var(--t-label);padding:var(--s1) var(--s1)}
}

/* ── малий телефон (iPhone SE, старі Android) ─────────────────── */
@media(max-width:360px){
  /* 83 лого + 18 геп + 159 CTA + 12 геп + 44 бургер + 28 поля = 344px.
     У 320px екрана шапка вилазила на 22px — і на contact/contact1, де
     body.onescreen скасовує overflow-x:clip, це давало реальний
     горизонтальний скрол усієї сторінки. */
  .bar,.bar-r{gap:var(--s2)}
  .trap-in{letter-spacing:.06em;padding-inline:var(--s4)}
  .hstats{gap:var(--s3) var(--s3)}
  /* два фільтри в ряд мали мін-ширину 152px кожен — 7px понад екран */
  .car-ctrl{gap:var(--s2)}
  .sortdrop .drop-btn,.filterdrop .drop-btn{gap:var(--s2);padding-inline:var(--s2)}
  .drop-val{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
}

/* ── вузький телефон ─────────────────────────────────────────── */
@media(max-width:600px){
  /* дві колонки питань давали ~165px на колонку: назва опції в
     дропдауні обрізалась на "Pick anything t…" */
  .role-block{grid-template-columns:minmax(0,1fr)}
  .whorow{grid-template-columns:1fr}
}

/* ── the line-up fits the panel ──────────────────────────────────
   below 1600 the card row is deliberately wider than the column: it
   is a carousel and it pages. from 1600 up there is no reason to make
   someone page a five-game catalogue on a 27" screen, so the card is
   sized FROM the content width — five cards + four gaps == --wide —
   which also puts the first card on the same line as the heading and
   the last one flush with the board below it. */
/* every card spans a whole number of the page's 12 columns (client 06.10:
   the fixed 230–280px card drifted across the grid, each one sat at a
   different distance from its column lines). Card + gap = --span column
   steps, so every card in the row starts on a grid line. Measured from the
   section's own width (cqi), not 100vw, so a classic scrollbar can't
   shift it off the overlay. */
.games-sec{container-type:inline-size}
.gcard{--span:9;flex:0 0 calc((100cqi - 2 * var(--gut) - 11 * var(--gap)) / 12 * var(--span) + (var(--span) - 1) * var(--gap))}
@media(min-width:480px){.gcard{--span:6}}
@media(min-width:768px){.gcard{--span:4}}
@media(min-width:1280px){.gcard{--span:3}}
@media(min-width:1600px){.gcard{--span:2}}
/* the card row starts on the edge line, under "Our games", at every width
   (client 06.10: tried hanging it past the edge, went back to one line) */

/* ════════════════════════════════════════════════════════════════
   LABELS · one role, one face (v3)
   ════════════════════════════════════════════════════════════════
   Client (SS-44): Chakra Petch for headings and numbers, Inter for
   text and buttons, JetBrains Mono for labels. Everything that is a
   tag, a meta key, a table head or a counter reads the same way.
   Large displays need no rules here: every size above is a token, and
   the tiers in :root step the tokens. */
.tag,.feat-std,.std,.feat-meta .k,.mrow .k,.board th,.games-head .cnt,.sort-lab,.lb-head,
.hstats span,.wins-head .mut,.dchip .k,.specc .k,.doc-meta,.legal-meta,.more-lab,.roles-lab,
.volend,.lc-n,.foot-l small,.gate-note{
  font-family:var(--mono);font-size:var(--t-label);font-weight:500;letter-spacing:var(--track-label);text-transform:uppercase}
.tag,.lb-head{font-weight:600}

/* ════════════════════════════════════════════════════════════════
   CONTROL HEIGHTS · a field and the button beside it are one height
   ════════════════════════════════════════════════════════════════
   Buttons have a fixed height (48 / 40); fields used to take theirs
   from padding + line-height (~51px), so "Notify me" sat 3px short
   of the email box. Every one-line control now uses the same two
   heights as the buttons. */
.su-row input,.npop-form input,.mailrow input,.fld,.drop-btn{height:var(--s6);padding-block:0}
.sortdrop .drop-btn,.filterdrop .drop-btn{height:40px}
.sort-lab{font-size:inherit}

/* ── large AND tall ──────────────────────────────────────────────
   14vh was tuned for a 720-900px laptop, where it is the only thing
   keeping the one-screen form clear of the footer. on a panel that is
   both wide and tall that leaves the posters small with a couple of
   hundred px of unused height under them, so the share of the viewport
   goes up here. the per-tier cap still applies and --qcol follows the
   posters on its own, so nothing needs re-measuring by hand. */
@media(min-width:1800px) and (min-height:900px){
  .lab{--gpk-h:clamp(96px,max(18vh,6vw),var(--gpk-cap))}
}

/* ── v5 · client feedback 19.10 ──────────────────────────────────────
   Правки поверх v3. Кожен блок підписаний номером пункту з фідбеку. */

/* 2. Play on Stake жирним. */
.trap-in{font-weight:700}

/* 9. Герой: обидві кнопки жирні. */
.hero .cta-row .btn{font-weight:700}

/* 6. На картках ігор: Play, Details і Notify me — жирним і капсом.
   .btn уже дає uppercase, бракувало тільки ваги; .notify не мав ні
   того, ні іншого. */
.gacts .btn{font-weight:700}
.notify{font-weight:700;text-transform:uppercase;letter-spacing:var(--track-btn)}

/* Колба в лого підвалу оживає, як у шапці (клієнт 19.10). У таблиці
   стояло .foot-l .flask,.foot-l .flask-wave{animation:none} — анімацію
   там свідомо глушили, бо підвальне лого було статичним малюнком.
   Хвиля тече постійно, як і в шапці. А ось підйом рідини — разова
   анімація на 2.6s: у шапці вона грає на завантаженні, коли лого вже
   на екрані, а підвал у цей момент за кілометр нижче, і все закінчиться
   задовго до того, як туди дошкрябають. Тому підйом чекає на клас .in,
   який JS вішає, коли підвал заходить у кадр.
   Без JS колба просто повна — так само, як було досі. */
.foot-l .flask-wave{animation:flask-drift 4s linear infinite}
.foot-l .flask{animation:none}
.foot-l.in .flask{animation:flask-rise 2.6s var(--ease) both}
@media(prefers-reduced-motion:reduce){
  .foot-l .flask-wave,.foot-l.in .flask{animation:none}
}

/* Magistral Medium — шрифт, яким зроблене лого (пункт 11). Файл дав
   Алекс 20.10 через канал проєкту; це справжній ParaType-івський
   Magistral-Medium, у ньому вшита їхня ліцензійна угода. Веб-ліцензію
   для продакшну підтверджує клієнт, не ми.
   Два накреслення: Medium (usWeightClass 500) і Bold (700), обидва від
   Алекса. Поки був лише Medium, усе, що просить 600 чи 700 — цифри в
   герої, бігучка, назви карток — діставало синтетичний жирний, тобто
   обведений контур замість справжнього накреслення (Алекс, 20.10).
   Тепер 700 бере справжній Bold, а 600 округлюється до нього ж —
   ближчого немає, і це краще за домальований.
   swap, щоб текст не зникав на час завантаження (26 + 27 КБ). */
@font-face{
  font-family:Magistral;
  src:url('art/magistral-medium.woff2') format('woff2');
  font-weight:500;
  font-style:normal;
  font-display:swap;
}
@font-face{
  font-family:Magistral;
  src:url('art/magistral-bold.woff2') format('woff2');
  font-weight:700;
  font-style:normal;
  font-display:swap;
}
/* Дисплейна роль цілком: заголовки секцій, назви карток, герой. Саме це
   і є «the text in the logo font» з фідбеку. Текст, лейбли й цифри
   лишаються на Inter і JetBrains Mono.
   Саме сімейство підставляє не CSS, а перемикач шрифтів: він переписує
   --disp інлайном на <html> при кожному завантаженні, тож правило в
   :root він би просто перебив. Magistral доданий першим пунктом його
   списку, тобто стоїть за замовчуванням. */
/* Заголовки лишаються на Medium — так вирішив Алекс. Решта місць, що
   просять 700, тепер беруть справжній Bold, бо він у сімействі є. */
.games-head h2,.wins-head h2,.notify-sec h2,.foot-drop h2,.sec2 h2,
.cta-band h2,.gate-card h2,.legal-block h2,
.hero h1,.dhead h1,.chero h1,.docs-head h1,.lab-rail h1,
.gname,.feat-name,.lc-title,.doc-name,.qtitle{font-weight:500}

/* 5. Обидва дропдауни, SHOW і SORT: пункти по центру і жирним. Клієнт називав
   лише Live і Coming soon, але центровані два рядки з трьох поруч із
   притиснутим ліворуч третім читались як помилка, тож All games пішов
   за ними (19.10, друге уточнення).
   Галочка вибраного пункту — це ::after у тому ж флексі, тож поки вона
   в потоці, центрується ТЕКСТ РАЗОМ З НЕЮ, і напис з'їжджає ліворуч
   рівно на пів її ширини, щойно пункт обрали. Виносимо її з потоку в
   правий край рядка — тоді текст стоїть на тому самому місці і з
   галочкою, і без неї. */
/* Вибране значення на кнопці стоїть на тій самій осі, що й список під
   нею (клієнт 20.10). .drop-val має flex:1, тобто займає все між
   написом SHOW/SORT і стрілкою — центруємо всередині цього проміжку. */
.filterdrop .drop-val,.sortdrop .drop-val{text-align:center}

.filterdrop .drop-opt,.sortdrop .drop-opt{position:relative;justify-content:center;font-weight:700}
.filterdrop.drop[data-single] .drop-opt[aria-selected="true"]::after,
.sortdrop.drop[data-single] .drop-opt[aria-selected="true"]::after{
  position:absolute;right:var(--s3);top:50%;transform:translateY(-50%);margin:0}

/* 3. Email-підписка по центру. Була на grid-column 7/13 з
   justify-self:end, тобто рівно під фіксованим блоком LIVE BETS, який
   висить у правому нижньому куті — він її й перекривав. */
.notify-sec{grid-template-columns:minmax(0,1fr);justify-items:center;text-align:center}
.nb-copy{grid-column:1/-1;grid-row:auto;justify-items:center}
.signup{grid-column:1/-1;grid-row:auto;justify-self:center;width:min(480px,100%)}

/* 4. Хедер з v2. v2 не має верхньої util-смужки взагалі: лічильник
   гравців, перемикач шрифту і соцмережі стоять у самому хедері праворуч,
   а CTA — звичайна кнопка, не колба. Відступи й кегль навігації
   лишаються від v5 — клієнт просив зберегти саме їх. Discord додано
   поруч із X (Алекс, 19.10: "у v2 там тільки X").
   Правила .util і .trap лишаються в таблиці, але нічого не добирають —
   розмітки під них більше немає. */
.playing{display:inline-flex;align-items:center;gap:var(--s2);white-space:nowrap;
  font-size:var(--t-small);color:var(--dim);border:1px solid var(--line-2);
  padding:var(--s1) var(--s3);border-radius:999px}
.playing i{flex:none;width:7px;height:7px;border-radius:50%;background:var(--win);
  box-shadow:0 0 8px var(--win)}
.playing b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}
.socials{display:flex;gap:var(--s1)}
.socials a{display:grid;place-items:center;width:var(--s5);height:var(--s5);
  border:1px solid var(--line-2);border-radius:9px;color:var(--dim);
  font-size:var(--t-small);transition:border-color .14s,color .14s}
.socials a:hover{border-color:var(--p);color:var(--ink)}
.socials svg{width:1em;height:1em;fill:currentColor}
/* Права група хедера тепер несе те, що раніше стояло в util-смужці, і
   вона вдвічі ширша за свою колонку в сітці 1fr auto 1fr. Три кроки,
   щоб усе стало в рядок і нав лишився по центру сторінки:
   — перемикач шрифту ужимається до розмірів, які він мав у v2 (у v5
     компактний варіант жив у правилі .util .fontpick, а його більше
     нема кому добирати);
   — проміжки в групі 16 -> 12, як у v2;
   — нав повертається на flex: кегль і падінги пунктів лишаються від v5,
     як просив клієнт, але фіксована ширина в 4 колонки сітки зникає —
     вона з'їдала 420px і виштовхувала праву групу на нав. Футерний нав
     уже переведений на flex тією ж правкою. */
.bar-r{gap:var(--s2)}
.bar-r .fontpick{font-size:var(--t-label);padding:var(--s1) var(--s2);gap:var(--s1)}
.bar-r .fontpick b{width:7.6em}

/* Та сама техніка, якою v2 розвантажує свій хедер: що вужче вікно, то
   менше другорядного лишається праворуч. У v2 перемикач шрифту зникає
   на 1340 (@media max-width:1340px), а нав, лічильник і соцмережі — на
   1000, де вмикається бургер.
   У v5 пороги довелося підняти. Хедер тут ширший за v2 — поля
   --edge-bar 64px проти 16, тобто 96px з'їдено ще до вмісту. Заміряно
   після того, як нав повернувся на flex по центру: на 1440 перемикач
   штовхає праву групу просто на навігацію, мінус 12px; поміщається він
   від 1520. Тож поріг 1519, а не 1340, як у v2. Лічильник гравців тримається
   до 1200, нижче місця під усе четверо немає.
   Перемикач шрифту нижче 1001 не зникає: app.js перекладає його в
   мобільне меню, а .takeover .fontpick-wrap його там показує. */
@media(max-width:1519px){
  .bar .fontpick-wrap{display:none}
}
@media(max-width:1200px){
  .playing{display:none}
}
@media(max-width:1000px){
  .playing,.socials{display:none}
}


/* 2 + 4. Play on Stake жирним — і в хедері, і в мобільному меню, і той,
   що в тілі сторінки гри (Алекс, 19.10). Сусідній "Play demo" теж, бо
   інакше дві кнопки поруч мали б різну вагу — так само, як це вже
   зроблено на картках ігор. */
.bar-r .btn-p,.takeover a.hot{text-transform:uppercase;letter-spacing:.04em;font-weight:700}
.takeover a.hot{color:var(--p)}
.dacts .btn{font-weight:700}

/* Відкритий дропдаун мусить лягати поверх каруселі. .drop-list має
   z-index:60, а .games-head і .carousel — сусіди в одному контексті
   накладання (.games-sec робить його через container-type). Картки
   свого z-index не мають, тож 60 їх перекриває — але лише доти, доки
   жодна з них його не отримає.
   Перша спроба підіймала рядок через .games-head:has(.drop.on), за
   зразком .qcard:has(.drop.on) з тієї ж таблиці. У Chrome воно
   працювало, а в Safari клієнт і далі бачив картки поверх списку:
   клас .on вішає JS у момент відкриття, і Safari не перераховує
   :has() на батькові, коли клас міняється всередині піддерева.
   Тому правило безумовне. Рядок складається з заголовка і контролів,
   свого тла не має, карусель його не перетинає — тримати його над
   каруселлю постійно нічим не шкодить, зате не залежить від :has().
   Числа тут не довільні. Поки картки будуються (reveal-анімація, клас
   .holo.stamp на body), вони отримують власний z-index:96 — правило
   .holo.stamp .gcard,.holo.stamp .hero-feat,.holo.stamp .dkey,
   .holo.stamp .hero h1,.holo.stamp .dhead h1 у цій же таблиці. Саме в
   цей момент клієнт і ловив картку поверх списку: 90 програвало 96.
   Беремо 99 — вище за будь-яку картку і все ще нижче за .bar зі 100,
   тож липка шапка далі накриває список, коли той під неї заїжджає. */
.games-head{position:relative;z-index:99}

/* Список має ставати рівно під своєю кнопкою. Обидва списки приколоті
   правим краєм (right:0) і мають підлогу min-width:240px. У SORT кнопка
   240.5px, тож підлога нічого не міняє і край сходиться. А SHOW лише
   184.6px — список розгортався до 240 і, прибитий правим краєм, вилазив
   на 55px ліворуч від кнопки. Прив'язуємо ширину списку до кнопки.
   Нижче 1001px не чіпаємо: там кнопки ділять рядок навпіл і списку
   навмисно дають власну ширину. */
@media(min-width:1001px){
  .sortdrop .drop-list,.filterdrop .drop-list{min-width:100%}
}

/* Сортування: ширина кнопки не повинна стрибати. v3 уже тримає її на
   min-width, але 17.7em трохи замало — "Volatility · high to low" просить
   233.4px при 230.1px мінімуму, і кнопка підростала на 3px просто від
   вибору пункту, тягнучи за собою весь рядок контролів. 18.5em = 240.5px,
   із запасом на найдовший варіант. Нижче 1001px не чіпаємо: там обидві
   кнопки ділять рядок порівну і min-width навмисно знятий. */
@media(min-width:1001px){
  .sortdrop .drop-btn{min-width:18.5em}
}

/* Футерна навігація як у v2: звичайний регістр, без розрядки, без
   потовщення і трохи більшим кеглем (клієнт 20.10). У v3 її зробили
   капсом на 600 з letter-spacing .12em — поруч із легким «Responsible
   play · 18+ · © 2026» праворуч це читалось як другий заголовок, а не
   як набір посилань. Шапку це не зачіпає: там капс лишається, як і в
   самому v2. */
.footer .foot-nav a{font-size:var(--t-lead);font-weight:400;
  letter-spacing:normal;text-transform:none}

/* Навігація як у v2 — звичайний flex за вмістом, а .bar це
   1fr auto 1fr, тож вона стає рівно по центру сторінки (клієнт 20.10).
   Сітка з чотирьох рівних колонок, що тримала спільні осі з підвалом,
   знята: три пункти в чотирьох комірках сиділи в лівих трьох чвертях
   бокса, тобто на 64px ліворуч від центру.
   Підвал теж повертається на flex — з сіткою він ішов у парі. */
@media(min-width:1001px){
  .bar .nav{display:flex;width:auto;gap:var(--navgap)}
  .footer .foot-nav{display:flex;width:auto;column-gap:var(--navgap)}
  .footer .foot-nav a{white-space:nowrap}
}

/* Насиченість CTA. Клієнт просив "жирним" у пунктах 2, 6 і 9, і 700
   формально це дало — але кнопки й до того стояли на 600, тож крок був
   майже невидимий. Обрано 900 з живого порівняння 700/800/900 (19.10):
   це стеля Inter, 1000 просто не існує і малюється як 900.
   Точково — тільки CTA, яких стосувався фідбек. Заголовки, навігація і
   підписи лишаються як були.
   Разом з ними йде кнопка підписки: напис там той самий NOTIFY ME, що
   й на картках, і 600 поруч із 900 читалось би як недогляд. */
.hero .cta-row .btn,
.bar-r .btn-p,
.takeover a.hot,
.dacts .btn,
.gacts .btn,
.signup .btn,
.notify{font-weight:900}


/* ── backend wiring (SS-49/50) ─────────────────────────────────────── */
/* honeypot: real visitors never see or fill it, form-filling bots do */
.hp{position:absolute!important;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}
.form-err{margin:var(--s2) 0 0;color:#FF5A6E;font-size:var(--t-small,14px)}
.labform.busy button[type=submit],.signup.busy button,.npop-form.busy button{opacity:.6;cursor:progress}
.nf{display:grid;justify-items:center;text-align:center;gap:var(--s3);padding:clamp(64px,14vh,160px) var(--s4)}
.nf .code{font-family:var(--disp);font-size:clamp(72px,16vw,180px);line-height:.9;color:var(--p)}
.nf .sub{max-width:44ch}
.su-legal{margin:var(--s2) 0 0;font-size:var(--t-small,13px);line-height:1.45;color:var(--dim);text-align:center}
.su-legal a{color:inherit;text-decoration:underline}
.npop .su-legal{margin-top:var(--s2)}
/* Turnstile: empty unless Cloudflare wants the visitor to click */
.ts-box:not(:empty){margin-top:var(--s2)}

/* ── live bets (SS-41) ─────────────────────────────────────────────── */
/* hidden until /api/live-bets has recent bets (html.live-on, app.js) */
html:not(.live-on) .livebets,html:not(.live-on) .wins-sec,html:not(.live-on) a[href$="#wins"]{display:none!important}
a.lb-row{color:inherit;text-decoration:none}a.lb-row:hover{background:rgba(255,255,255,.03)}
/* the dock's bet amount sits under the result, so the row stays two lines */
.lb-amt{text-align:right}.lb-amt small{display:block;font-size:var(--t-label);font-weight:500;color:var(--faint)}
/* Stake's six columns (30.10): Game · User · Time · Bet Amount · Multiplier
   · Payout, on the same equal-gap subgrid as before (cells on odd tracks).
   Game and User may shrink with an ellipsis; on a phone Time and Bet Amount
   go (hide-s) and it is four columns again */
.board{grid-template-columns:minmax(0,max-content) minmax(var(--s3),1fr) minmax(0,max-content) minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content}
.board :is(th,td):nth-child(6){grid-column:11}
.board td:nth-child(2){white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media(max-width:560px){
  .board{grid-template-columns:minmax(0,max-content) minmax(var(--s3),1fr) minmax(0,max-content) minmax(var(--s3),1fr) max-content minmax(var(--s3),1fr) max-content}
  .board :is(th,td):nth-child(5){grid-column:5}
  .board :is(th,td):nth-child(6){grid-column:7}
  .bg-thumb{display:none}   /* the game's name needs the room more */
}
/* baseline: the row lines its cells up on the text, and an empty thumb would
   otherwise lend the link its bottom edge as the baseline */
.bg-game{display:flex;align-items:baseline;gap:var(--s2);min-width:0;color:inherit;text-decoration:none}
.bg-game:hover{color:var(--p)}
.bg-game span{overflow:hidden;text-overflow:ellipsis}
.bg-thumb{flex:none;align-self:center;width:20px;height:20px;border-radius:5px;background:linear-gradient(150deg,#2AC0FF,#0E5FB8) center/cover}
.board .cur{font-size:var(--t-label);font-weight:600;letter-spacing:.04em;color:var(--faint);margin-inline-start:6px}
.board .loss{color:var(--dim);font-variant-numeric:tabular-nums}
.board .empty td{grid-column:1/-1;color:var(--faint)}
.wins-tabs{display:flex;gap:var(--s1);flex:none}
.wins-tabs button{font-size:var(--t-label);font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--dim);
  padding:var(--s1) var(--s2);border-radius:8px;border:1px solid transparent;background:none;cursor:pointer}
.wins-tabs button:hover{color:var(--ink)}
.wins-tabs button[aria-selected="true"]{color:var(--ink);background:var(--panel);border-color:var(--line)}
