/* Game shell — base layout and components. Every colour, radius and font is a token, so a game's
   skin.css restyles the shell by overriding tokens and adding decoration (it never rewrites layout logic).
   Tokens set by the shell from the admin colours: --primary(-hi/-lo), --bg, --bg2, --accent(-hi). Text the shell
   colours from them reads an override token first, which contrast.js sets only where the default pair misses WCAG
   contrast on its ground: --ink-on-accent, --panel-title, --panel-sub, --won-ink, --fs-num, --ov-text. */
:root{
  --primary:#F5C542; --primary-hi:#FFE08A; --primary-lo:#7A5A10; --bg:#0B1020; --bg2:#151B30; --accent:#00CFFF; --accent-hi:#80E8FF;
  --ink:#F4F1EA; --muted:#A9A9B8; --display:Georgia,"Times New Roman",serif; --ui:system-ui,-apple-system,"Segoe UI",sans-serif;
  --radius:14px; --radius-sm:9px; --line:color-mix(in srgb,var(--primary) 35%,transparent);
  --panel-bg:linear-gradient(180deg,var(--bg2),var(--bg)); --panel-border:var(--line);
  --hud-bg:linear-gradient(180deg,color-mix(in srgb,var(--bg2) 92%,transparent),color-mix(in srgb,var(--bg) 95%,transparent));
  --btn-bg:linear-gradient(180deg,var(--primary-hi),var(--primary) 55%,var(--primary-lo)); --btn-ink:var(--bg);
  --ibtn-bg:color-mix(in srgb,var(--bg2) 85%,#000); --ibtn-ink:var(--primary-hi);
  --win-glow:var(--accent); --focus:var(--primary-hi); --cell:96px;
  /* motion: arrive with --ease-out, leave with --ease-in (exits are shorter), change state with --ease-std; --ease-back
     only for a reel's stop / a symbol landing (overshoot <= 6 %). Durations: press, fast (hover, exits), base (panels),
     slow (scene parts), scene (feature transitions, 600-1200 ms, the skin's own). */
  --ease-out:cubic-bezier(.2,.8,.2,1); --ease-in:cubic-bezier(.4,0,1,1); --ease-std:cubic-bezier(.4,0,.2,1); --ease-back:cubic-bezier(.34,1.4,.64,1);
  --t-press:90ms; --t-fast:140ms; --t-base:220ms; --t-slow:360ms;
  /* opt-in looks a skin can retune (game-shell.md): the spin button's busy ring, the light behind a win card's title,
     the plate under its amount, the scrim behind panels */
  --spin-ring:color-mix(in srgb,var(--primary-hi) 85%,transparent);
  --veil-light:color-mix(in srgb,var(--primary) 20%,transparent);
  --ov-plate:color-mix(in srgb,var(--bg2) 78%,transparent); --ov-plate-line:var(--line);
  --scrim:rgba(0,0,0,.68);
  color-scheme:dark; box-sizing:border-box;
}
html{height:100%}
*,*::before,*::after{box-sizing:inherit}
body{margin:0;height:100%;overflow:hidden;background:var(--bg);color:var(--ink);font-family:var(--ui);-webkit-font-smoothing:antialiased;user-select:none;-webkit-tap-highlight-color:transparent}
/* admin font choice (ui.font): the skin's own pair, a readable face, or the device's system font */
body[data-font="readable"]{--display:"Atkinson Hyperlegible",system-ui,sans-serif;--ui:"Atkinson Hyperlegible",system-ui,sans-serif}
body[data-font="system"]{--display:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;--ui:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif}
button{font:inherit;color:inherit;cursor:pointer}
button:disabled{cursor:default}
.num,b{font-variant-numeric:tabular-nums}
[hidden]{display:none!important}
.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
button:focus-visible,a:focus-visible,[tabindex]:focus-visible{outline:3px solid var(--focus);outline-offset:3px}

/* scene (background built by the skin) */
.scene{position:fixed;inset:0;overflow:hidden;z-index:0;background:var(--bg)}
.scene>*{position:absolute;inset:0}
.scene canvas#bgfx{width:100%;height:100%}
body.bg-custom .scene{background:var(--bg-image) center/cover no-repeat}
body.bg-custom .scene>:not(canvas){display:none}
canvas#fx{position:fixed;inset:0;width:100%;height:100%;z-index:40;pointer-events:none}
.flash{position:fixed;inset:0;z-index:41;pointer-events:none;opacity:0;background:radial-gradient(circle at 50% 45%,var(--primary-hi),color-mix(in srgb,var(--accent) 60%,transparent) 45%,transparent 80%)}

/* page grid */
.game{position:fixed;inset:0;z-index:2;display:grid;grid-template-rows:auto minmax(0,1fr) auto;grid-template-columns:minmax(0,1fr);gap:6px;
  padding:calc(env(safe-area-inset-top,0px) + 8px) calc(env(safe-area-inset-right,0px) + 14px) calc(env(safe-area-inset-bottom,0px) + 10px) calc(env(safe-area-inset-left,0px) + 14px)}
/* The header: two equal button groups (home + sound | title | info + settings), so the title's column is centred on the
   page; title.js then moves the title over the board where a side HUD column moves the board (alignTitle), balances a
   skin's letter-spacing (text-indent) and fits the size. The h1 clips with a margin (overflow-clip-margin), so a
   skin's glow or drop shadow is not cut into a box; the ellipsis still works. */
.top{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:10px;min-width:0}
/* the header paints over the stage: a board or feature bar that ever runs out of its area (a skin's tall frame, a cell
   at its 40 px floor) never covers the title or the header's buttons (game-shell.md §11) */
.game>.top{position:relative;z-index:4}
.logo{justify-self:center;text-align:center;min-width:0;max-width:100%;overflow:visible}
.logo h1{margin:0;font-family:var(--display);font-weight:700;font-size:clamp(24px,3.6vw,44px);line-height:1.05;color:var(--primary);white-space:nowrap;overflow:hidden;overflow:clip;overflow-clip-margin:.6em;text-overflow:ellipsis}
.logo img{max-height:52px;width:auto;max-width:100%}
.topl,.topr{display:flex;gap:8px}
/* sound turned off by the admin: its slot stays (invisible, not focusable, not announced) so both groups keep one width */
.topl>#btnSound[hidden]{display:grid!important;visibility:hidden}
/* a header still built with all three buttons on the right (no .topl): the same balance by grid placement */
.game>.top:not(:has(>.topl)){grid-template-columns:auto auto minmax(0,1fr) auto auto}
.game>.top:not(:has(>.topl))>.topr{display:contents}
.game>.top:not(:has(>.topl))>.home{grid-area:1/1}.game>.top:not(:has(>.topl)) #btnSound{grid-area:1/2}
.game>.top:not(:has(>.topl))>.logo{grid-area:1/3}.game>.top:not(:has(>.topl)) #btnPay{grid-area:1/4}.game>.top:not(:has(>.topl)) #btnSet{grid-area:1/5}
.game>.top:not(:has(>.topl)) #btnSound[hidden]{display:grid!important;visibility:hidden}
/* a name too long for one line even at the floor size (title.js): the title alone on a second row, full width */
.game>.top.title-row{row-gap:4px}
.game>.top.title-row>.logo{grid-area:2/1/3/-1}.game>.top.title-row>.topr{grid-area:1/3}
.game>.top.title-row:not(:has(>.topl))>.logo{grid-area:2/1/3/-1}
.game>.top.title-row .logo h1{white-space:normal;text-wrap:balance}
.ibtn{position:relative;width:42px;height:42px;border-radius:var(--radius-sm);border:1px solid var(--line);background:var(--ibtn-bg);color:var(--ibtn-ink);display:grid;place-items:center;text-decoration:none;padding:0;
  transition:border-color var(--t-fast) var(--ease-std),translate var(--t-press) var(--ease-out)}
.ibtn svg{width:20px;height:20px}
.ibtn:hover{border-color:var(--primary)}
.ibtn:active{translate:0 1px}
/* 44px minimum tap target on every icon / bet button without enlarging the compact visual: a transparent, centred
   overlay adds no layout width, so the HUD budget down to 320px is unchanged. (Visuals stay as the skin draws them;
   WCAG 2.5.8 only needs 24px, but the product bar is 44px.) */
.ibtn::before,.pm::before{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:max(100%,44px);height:max(100%,44px);border-radius:inherit}
#btnSound .mute{display:none}#btnSound[aria-pressed="false"] .mute{display:inline}#btnSound[aria-pressed="false"] .waves{display:none}

.stage{position:relative;min-height:0;display:grid;grid-template-columns:minmax(0,1fr);align-items:center;justify-items:center}
.side{display:none}
/* safe center: content taller than the area starts at its top (under the header) instead of spilling up over the title */
.boardarea{position:relative;min-height:0;min-width:0;width:100%;height:100%;display:flex;flex-direction:column;align-items:center;justify-content:safe center;gap:8px}
.frame{position:relative;display:flex;flex-direction:column;align-items:center;gap:6px}
.board{position:relative}
.message{min-height:28px;font-size:clamp(14px,1.45vw,16px);font-weight:600;line-height:1.35;text-align:center;color:var(--ink)}
.message b{color:var(--primary);font-weight:800}
/* the feature bar sits in the board area over the frame (board.layout() keeps room for it: shell.js lays the board out
   when the bar shows, hides or changes size); it never runs wider than the area — a long bar wraps, centred */
.fsbar{display:none;flex-wrap:wrap;justify-content:center;max-width:100%;gap:2px 18px;align-items:center;padding:6px 18px;border-radius:var(--radius-sm);background:color-mix(in srgb,var(--bg) 80%,transparent);border:1px solid var(--accent);font-weight:700}
.fsbar b{color:var(--fs-num,var(--primary))} .fsbar .fsx{font-family:var(--display);font-size:1.2em;color:var(--primary-hi)}
body.fs .fsbar{display:flex}
/* over the frame's own ornaments (a crest or an arch a skin raises above the frame's box): the bar's numbers stay read */
.boardarea>.fsbar{position:relative;z-index:5}

/* side tablets (buy, ante, extra info) — shown on wide screens by HUD layouts that use them */
.tablet{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;width:100%;min-height:44px;min-width:44px;padding:12px 10px;border-radius:var(--radius);border:1px solid var(--line);background:var(--panel-bg);text-align:center;color:var(--ink);
  transition:border-color var(--t-fast) var(--ease-std),translate var(--t-press) var(--ease-out)}
.tablet:hover:not(:disabled){border-color:var(--primary)}
.tablet:active:not(:disabled){translate:0 1px}
.tablet .th{font-family:var(--display);font-weight:700;color:var(--primary);font-size:16px}
.tablet .price{font-size:20px;font-variant-numeric:tabular-nums}
.tablet small{color:var(--muted);font-size:13px}
.tablet:disabled{opacity:.45}
.tablet .switch{width:42px;height:22px;border-radius:11px;border:1.5px solid var(--line);position:relative}
.tablet .switch::after{content:"";position:absolute;top:2px;left:2px;width:15px;height:15px;border-radius:50%;background:var(--muted);transition:transform .2s,background .2s}
.tablet[aria-pressed="true"] .switch::after{transform:translateX(20px);background:var(--primary)}

/* HUD */
.hud{display:grid;grid-template-columns:1fr auto 1fr auto;align-items:center;gap:clamp(10px,2vw,28px);width:min(1060px,100%);margin:0 auto;padding:10px clamp(12px,2vw,24px);border-radius:var(--radius);
  background:var(--hud-bg);border:1.5px solid var(--line)}
.meter{min-width:0}
/* labels: sentence case, quiet; values: tabular figures. The win value is lit (--primary) only while it shows a win:
   at zero it is --muted like the labels (#winMeter.at-zero), so the HUD is calm between spins. */
.meter span{display:block;font-size:13px;font-weight:600;line-height:18px;color:var(--muted);letter-spacing:.01em}
.meter b{display:block;font-size:clamp(20px,2.1vw,28px);font-weight:800;line-height:1.1;white-space:nowrap;font-variant-numeric:tabular-nums}
.meter small{display:block;font-size:12px;color:var(--muted)}
.meter.win b{color:var(--primary);transition:color var(--t-base) var(--ease-std)}
.hud .meter.win.at-zero b{color:var(--muted)}
.demo{font-style:normal;font-size:10px;font-weight:800;color:var(--ink-on-accent,var(--bg));background:var(--accent);border-radius:4px;padding:0 5px;margin-left:4px;vertical-align:1px}
.betctl{display:flex;align-items:center;gap:10px}.betctl .meter{text-align:center;min-width:110px}
/* flex-shrink:0 keeps the −/+ at their set size: a wide bet sub-label grows/wraps the meter instead of squeezing the
   keys into thin slivers (seen at ≤360px on games with a long "N lines · $x per line" subtitle). */
.pm{position:relative;flex-shrink:0;width:38px;height:38px;border-radius:var(--radius-sm);border:1px solid var(--line);background:var(--ibtn-bg);color:var(--ibtn-ink);font-size:22px;font-weight:700;line-height:1;display:grid;place-items:center;padding:0;
  transition:border-color var(--t-fast) var(--ease-std),translate var(--t-press) var(--ease-out),opacity var(--t-fast)}
.pm:hover:not(:disabled){border-color:var(--primary)}
.pm:active:not(:disabled){translate:0 1px}
.pm:disabled{opacity:.35}
.spinbox{display:flex;align-items:center;gap:12px}
.auto{position:relative;width:54px;height:54px;border-radius:50%;border:1px solid var(--line);background:var(--ibtn-bg);color:var(--ibtn-ink);display:grid;place-items:center;padding:0;
  transition:border-color var(--t-fast) var(--ease-std),translate var(--t-press) var(--ease-out),box-shadow var(--t-base) var(--ease-std)}
.auto:hover:not(:disabled){border-color:var(--primary)}
.auto:active:not(:disabled){translate:0 1px}
.auto svg{width:24px;height:24px}
.auto span{position:absolute;top:-6px;right:-8px;min-width:22px;height:20px;padding:0 5px;border-radius:10px;background:var(--accent);color:var(--ink-on-accent,var(--bg));font-size:12px;font-weight:800;display:none;place-items:center}
.auto[aria-pressed="true"]{box-shadow:0 0 16px var(--accent)}
.auto[aria-pressed="true"] span{display:grid}
/* the spin key: pressed = 2 px down and a touch smaller (90 ms); busy = a thin ring turning round its edge (transform
   only; a skin sets --spin-ring:transparent to draw its own). Filters are static (no animated brightness). */
.spin{--s:clamp(78px,7.5vw,100px);width:var(--s);height:var(--s);border-radius:50%;border:0;padding:0;position:relative;color:var(--btn-ink);background:var(--btn-bg);box-shadow:0 8px 22px rgba(0,0,0,.5);transition:transform var(--t-press) var(--ease-out)}
.spin svg{position:absolute;left:50%;top:50%;width:42%;height:42%;transform:translate(-50%,-50%)}
.spin:hover:not(:disabled){filter:brightness(1.07)}
.spin:active:not(:disabled){transform:translateY(2px) scale(.96)}
.spin:disabled{filter:brightness(.65) saturate(.6)}
.spin:focus-visible{outline-offset:6px}
.spin>.spin-ring{position:absolute;inset:-6px;border-radius:50%;border:2px solid transparent;border-top-color:var(--spin-ring);border-right-color:color-mix(in srgb,var(--spin-ring) 35%,transparent);
  opacity:0;pointer-events:none;transition:opacity var(--t-fast) var(--ease-std)}
.spin.busy>.spin-ring{opacity:1;animation:shell-sp .9s linear infinite}

/* overlays */
/* the veil: the board shows through faintly; 85 % of --bg at the centre keeps the card's text readable over the
   brightest symbol art (with 55 % the reels under the text pulled the feature and big-win cards below WCAG contrast) */
/* + a soft light of the game's key colour behind the card's title (--veil-light) and a vignette to the edges */
.overlay{position:fixed;inset:0;z-index:30;display:none;align-items:center;justify-content:center;padding:20px;
  background:radial-gradient(46% 34% at 50% 44%,var(--veil-light),transparent),radial-gradient(circle at 50% 45%,color-mix(in srgb,var(--bg) 85%,transparent),color-mix(in srgb,var(--bg) 92%,#000) 75%)}
.overlay.open{display:flex;animation:shell-fade var(--t-base) var(--ease-out) both}
.ovcard{text-align:center;max-width:100%}
.overlay.open .ovcard{animation:shell-card var(--t-slow) var(--ease-out) both}
.ovcard h2{margin:0;font-family:var(--display);font-weight:800;font-size:clamp(44px,9vw,116px);line-height:.95;color:var(--primary);overflow-wrap:anywhere}
.overlay.bigwin.t1 h2{font-size:clamp(50px,10.5vw,138px)} .overlay.bigwin.t2 h2{font-size:clamp(56px,12vw,160px)}
/* the amount sits on a plate of the game's surface (--ov-plate, --ov-plate-line: transparent = none) */
.ovamt{font-weight:800;font-size:clamp(34px,6vw,78px);line-height:1.1;margin-top:12px;font-variant-numeric:tabular-nums}
.ovamt:not(:empty){display:inline-block;padding:.08em .5em .12em;border-radius:var(--radius);background:var(--ov-plate);box-shadow:inset 0 0 0 1px var(--ov-plate-line)}
.ovcard p{color:var(--ov-text,var(--muted));font-size:16px;line-height:1.5;margin:14px auto 0;max-width:46ch}
.overlay.bigwin .ovcard p{font-size:14px}
#ovBtns{margin-top:22px}
.btn{border:0;border-radius:var(--radius);padding:13px 30px;min-height:48px;font-family:var(--display);font-weight:800;font-size:22px;letter-spacing:.02em;color:var(--btn-ink);background:var(--btn-bg);box-shadow:0 8px 20px rgba(0,0,0,.45);
  transition:transform var(--t-press) var(--ease-out)}
.btn:active{transform:translateY(2px)}
.btn.ghost{background:var(--ibtn-bg);color:var(--ibtn-ink);box-shadow:0 0 0 1.5px var(--line)}
/* panels open with a fade and 12 px rise (base, ease-out) and close faster (fast, ease-in: panels.js closeModal) */
.sheet{position:fixed;inset:0;z-index:50;display:none;align-items:center;justify-content:center;padding:16px;background:var(--scrim);user-select:text}
.sheet.open{display:flex;animation:shell-fade var(--t-base) var(--ease-out) both}
.sheet.open>.panel{animation:shell-rise var(--t-base) var(--ease-out) both}
.sheet.closing,.overlay.closing{pointer-events:none}
.sheet.dialog{z-index:55}
.panel{position:relative;width:min(960px,100%);max-height:100%;overflow:auto;border-radius:var(--radius);padding:22px clamp(16px,3vw,30px) 26px;background:var(--panel-bg);border:1.5px solid var(--panel-border);box-shadow:0 30px 80px rgba(0,0,0,.6)}
.panel.narrow{width:min(440px,100%)}
.panel h2{margin:0 0 6px;font-family:var(--display);font-weight:800;font-size:clamp(28px,4vw,40px);line-height:1.05;color:var(--panel-title,var(--primary))}
.panel h3{margin:22px 0 8px;font-family:var(--display);font-weight:700;font-size:24px;color:var(--panel-sub,var(--primary-hi))}
.panel p,.panel li{line-height:1.5}
.panel .lead{color:var(--muted);max-width:68ch}
.close{position:absolute;top:14px;right:14px}
.dlgbtns{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;margin-top:18px}
#dialog .panel{text-align:center}
.ptgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px}
/* paytable cards: the symbol at 72 px, its name and pays in the UI face with tabular figures; one hairline, no heavy box */
.ptc{display:grid;grid-template-columns:72px 1fr;gap:12px;align-items:center;padding:10px 12px;border-radius:var(--radius-sm);background:rgba(0,0,0,.22);border:1px solid var(--line)}
.ptc .symbox{width:72px;height:72px;position:relative;--cell:72px}
.ptc h4{margin:0 0 4px;font-size:16px;line-height:1.3}
.ptc table{border-collapse:collapse;width:100%;font-size:15px;line-height:1.45;font-variant-numeric:tabular-nums}.ptc td:last-child{text-align:right;font-weight:800}
.special{display:grid;grid-template-columns:96px 1fr;gap:14px;align-items:center;margin:10px 0}
.rules{padding-left:20px}
.setrow{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 2px;border-bottom:1px solid var(--line);font-weight:700;font-size:17px}
.setrow small{display:block;font-weight:500;color:var(--muted);font-size:14px}
.tog{width:46px;height:26px;border-radius:13px;border:1.5px solid var(--line);background:rgba(0,0,0,.3);position:relative;padding:0;flex:none}
/* settings controls are 44 px targets too: the switch by a transparent overlay (its visual stays 46 × 26), the chips and
   rows by their own height */
.tog::before{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:max(100%,44px);height:max(100%,44px);border-radius:inherit}
.tog::after{content:"";position:absolute;top:3px;left:3px;width:17px;height:17px;border-radius:50%;background:var(--muted);transition:transform .2s,background .2s}
.tog[aria-checked="true"]{background:color-mix(in srgb,var(--primary) 30%,transparent)}.tog[aria-checked="true"]::after{transform:translateX(20px);background:var(--primary)}
.chips{display:flex;gap:6px;flex-wrap:wrap}.chips button{min-width:44px;min-height:44px;border:1.5px solid var(--line);background:rgba(0,0,0,.3);border-radius:var(--radius-sm);padding:5px 12px;font-weight:800}
.chips button[aria-pressed="true"]{background:var(--primary);color:var(--bg);border-color:var(--primary)}
.linkrow{display:flex;justify-content:space-between;align-items:center;width:100%;min-height:44px;padding:12px 2px;border:0;border-bottom:1px solid var(--line);background:none;font-weight:700;font-size:17px;text-align:left;color:inherit;text-decoration:none}
.demo-note{margin-top:14px;font-size:14px}
.screen{position:fixed;inset:0;z-index:70;display:none;flex-direction:column;align-items:center;justify-content:center;gap:14px;text-align:center;padding:24px;background:var(--bg)}
.screen.open{display:flex}
.screen h2{margin:0;font-family:var(--display);font-weight:800;font-size:clamp(30px,5vw,52px);color:var(--primary)}
.screen p{margin:0;max-width:44ch;color:var(--muted)}
.spinner{width:56px;height:56px;border-radius:50%;border:3px solid color-mix(in srgb,var(--accent) 25%,transparent);border-top-color:var(--accent);animation:shell-sp 1s linear infinite}
@keyframes shell-sp{to{transform:rotate(360deg)}}
@keyframes shell-fade{from{opacity:0}}
@keyframes shell-rise{from{opacity:0;translate:0 12px}}
@keyframes shell-card{from{opacity:0;translate:0 10px;scale:.985}}
/* the page's one load moment (panels.js hideLoading -> body.entering, ~700 ms): the board and its frame rise into place,
   the HUD follows 80 ms later, the title fades in (the loading screen itself goes at once). Individual transform
   properties (translate), so a skin's own transform on these parts is kept. Reduced motion: the end state at once. */
body.entering .boardarea,body.entering .stage>.side{animation:shell-rise 320ms var(--ease-out) both}
body.entering .hud{animation:shell-rise 240ms var(--ease-out) 80ms both}
body.entering .hud-corners .hud{animation-name:shell-fade} /* its corner plates are position:fixed: no translate above them */
body.entering .top .logo{animation:shell-fade 200ms var(--ease-out) 40ms both}
.toast{position:fixed;left:50%;top:calc(env(safe-area-inset-top,0px) + 14px);transform:translateX(-50%);z-index:60;background:var(--bg2);border:1px solid var(--line);color:var(--ink);padding:10px 16px;border-radius:var(--radius-sm);opacity:0;pointer-events:none;transition:opacity var(--t-base) var(--ease-std);max-width:calc(100vw - 32px)}
.toast.show{opacity:1}
.hist-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius-sm)}
table.hist{border-collapse:collapse;width:100%;font-size:16px}
table.hist th,table.hist td{padding:8px 10px;border-bottom:1px solid var(--line);text-align:left;white-space:nowrap}
table.hist th{color:var(--muted);font-size:14px} table.hist .r{text-align:right} table.hist .won{color:var(--won-ink,var(--primary));font-weight:800}
.hist-state{color:var(--muted)} .hist-more{min-height:44px;margin-top:12px;border:1.5px solid var(--line);background:var(--ibtn-bg);color:var(--ibtn-ink);border-radius:var(--radius-sm);padding:8px 18px;font-weight:700}

/* HUD layouts (skin.hud -> class .hud-<name> on #game). The shell has rules for "side-tablets", "corners" and
   "side-column"; "bar" (the default), "plinth" and "console" are the base layout below, which skins decorate. Any other
   name matches no rule here and falls back to that base layout: the HUD panel under the board, the buy / ante row
   under the board on wide screens, the two-row thumb-zone HUD on phones (spin bottom right, bottom left with lefty).
   HUD skeletons named in the wave-3 GDDs that the shell does NOT lay out — each skin declares an existing layout and
   draws the look in its own skin.css (decoration only, never layout logic), as its skin.js header records:
     "top-arc"       throne-of-rime (crown-arc)          -> "corners": balance and win as plates high on either side
     "radial"        dragon-empire (moon-ring),          -> "bar": the lower arc of the gate ring / an arced console
                     cosmic-forge (cockpit)                 (cosmic-forge centres its spin in the arc on wide screens only)
     "wraparound-u"  dream-factory (conveyor-loop)       -> "bar": a belt with rollers and two rising arms
     side meter      jungle-temple (side-meter-bottom-bar) -> "bar" + the Idol Charge presenter's totem beside the grid
     centred spin    sunstone-terraces (bottom plinth), dragon-empire (6 o'clock), cosmic-forge on phones
                                                         -> phones keep the thumb-zone spin (bottom right). A centred
                     phone spin does not fit: at 360 px the HUD has ≈ 308 px of columns, a centred 72 px spin leaves two
                     ≈ 118 px columns, while the bet control needs ≈ 150 px and a win meter of $1,000,000.00 ≈ 135 px; a
                     third HUD row would push the cells under 44 px.
   A shell layout for any of these needs design sign-off and a GDD note first; until then this fallback is the contract. */
/* HUD layout "side-tablets": options on the left, game info on the right of the board (wide screens) */
@media (min-width:861px) and (min-aspect-ratio:4/5){
  .hud-side-tablets .stage{grid-template-columns:minmax(130px,210px) minmax(0,1fr) minmax(130px,210px);gap:clamp(10px,1.6vw,26px)}
  .hud-side-tablets .side{display:flex;flex-direction:column;gap:12px;justify-content:center}
  .hud-side-tablets .side:empty{visibility:hidden}
  /* pinned columns: with #sideL [hidden] (no buy, no ante) auto-placement would move the board into column 1 */
  .hud-side-tablets .side.left{grid-column:1}.hud-side-tablets .boardarea{grid-column:2}.hud-side-tablets .side.right{grid-column:3}
}
/* every HUD but "side-tablets" (wide screens): the options (buy, ante) sit in a row under the board, so a game never
   loses its buy or ante on a desktop whatever HUD its skin picks ("plinth", "corners", "bar", "console", "side-column") */
@media (min-width:861px) and (min-aspect-ratio:4/5){
  .game:not(.hud-side-tablets) .stage{display:flex;flex-direction:column;align-items:stretch;gap:10px}
  .game:not(.hud-side-tablets) .boardarea{flex:1 1 auto;min-height:0}
  .game:not(.hud-side-tablets) .side.left:not([hidden]){display:flex;order:2;gap:12px;justify-content:center}
  .game:not(.hud-side-tablets) .side.left .tablet{flex-direction:row;align-items:center;gap:12px;padding:8px 20px;width:auto}
  /* "corners": balance top left, win top right, bet bottom left, spin bottom right — no HUD panel */
  .hud-corners .hud{background:none;border:0;box-shadow:none;grid-template-columns:auto 1fr auto;grid-template-areas:"bet . spin";width:100%;padding:0 clamp(12px,2vw,28px) 10px}
  .hud-corners .hud>.bal,.hud-corners .hud>.win{position:fixed;top:clamp(64px,9vh,84px);z-index:5;padding:8px 14px;border-radius:var(--radius-sm);background:var(--corner-bg,rgba(0,0,0,.45));border:1px solid var(--line)}
  .hud-corners .hud>.bal{left:clamp(12px,2vw,28px)}.hud-corners .hud>.win{right:clamp(12px,2vw,28px);text-align:right}
  .hud-corners .betctl{grid-area:bet;padding:6px 12px;border-radius:var(--radius-sm);background:var(--corner-bg,rgba(0,0,0,.45));border:1px solid var(--line)}
  .hud-corners .spinbox{grid-area:spin}
}
/* HUD "side-column" (wide screens): balance, bet, win and spin stand in a column beside the board — on the left, on the
   right for the left-handed layout. Phones keep the two-row thumb-zone HUD below. */
@media (min-width:861px) and (min-aspect-ratio:4/5){
  .hud-side-column{grid-template-columns:minmax(190px,232px) minmax(0,1fr);grid-template-rows:auto minmax(0,1fr);column-gap:clamp(12px,1.6vw,26px)}
  .hud-side-column>.top{grid-column:1/-1}
  .hud-side-column>.stage{grid-column:2;grid-row:2}
  .hud-side-column>.hud{grid-column:1;grid-row:2;align-self:center;width:100%;margin:0;display:flex;flex-direction:column;align-items:stretch;gap:16px;padding:20px 14px;text-align:center}
  .hud-side-column .betctl{justify-content:center}.hud-side-column .betctl .meter{min-width:0;flex:1}
  .hud-side-column .spinbox{justify-content:center}
  body.lefty .hud-side-column{grid-template-columns:minmax(0,1fr) minmax(190px,232px)}
  body.lefty .hud-side-column>.stage{grid-column:1}
  body.lefty .hud-side-column>.hud{grid-column:2}
  body.lefty .hud-side-column>.hud>.spinbox{order:0;flex-direction:row-reverse}
}
/* narrow screens: options move into the HUD row, spin stays in the thumb zone (bottom right) */
@media (max-width:860px),(max-aspect-ratio:4/5){
  .game{padding-left:8px;padding-right:8px}
  .hud{grid-template-columns:1fr 1fr;grid-template-areas:"bal win" "bet spin";row-gap:8px}
  .hud>.bal{grid-area:bal}.hud>.win{grid-area:win;text-align:right}.betctl{grid-area:bet}.spinbox{grid-area:spin;justify-self:end}
  .betctl .meter{min-width:84px}
  .stage{display:flex;flex-direction:column;align-items:stretch;gap:8px}
  .boardarea{flex:1 1 auto;min-height:0}
  /* the buy / ante row sits under the board, just above the HUD: the thumb's reach, and the board stays near the title */
  .side.left:not([hidden]){display:flex;order:2;gap:8px;width:100%;justify-content:center}
  .side.left .tablet{flex-direction:row;align-items:center;justify-content:center;gap:8px;padding:6px 12px;width:auto;min-height:44px}
  .side.left .tablet small{display:none}
  .logo h1{font-size:clamp(20px,6.4vw,36px)}
}
/* left-handed layout (player setting): spin and autoplay move to the left, mirrored in the thumb zone on phones */
body.lefty .hud>.spinbox{order:-1;flex-direction:row-reverse}
@media (min-width:861px) and (min-aspect-ratio:4/5){body.lefty .hud{grid-template-columns:auto 1fr auto 1fr}}
@media (max-width:860px),(max-aspect-ratio:4/5){
  body.lefty .hud{grid-template-areas:"win bal" "spin bet"}
  body.lefty .hud>.win{text-align:left}body.lefty .hud>.bal{text-align:right}
  body.lefty .spinbox{justify-self:start}body.lefty .betctl{justify-self:end}
}
/* small phones (360–400 px): compact bet and spin controls so the HUD row fits (≈ 310 px of 344) */
@media (max-width:400px){
  .top{gap:6px}.ibtn{width:38px;height:38px}
  .hud{padding:8px 10px;column-gap:8px}
  .betctl{gap:6px}.betctl .meter{min-width:70px}.pm{width:34px;height:34px;font-size:20px}
  .spinbox{gap:8px}.auto{width:46px;height:46px}.auto svg{width:21px;height:21px}
  .spin{--s:72px}
}
/* very small phones (≤340 px, e.g. 320 px wide): reclaim a little more row width so the HUD never overflows —
   tighter gutters, HUD padding, bet gap and spin gap, and a bet meter that sizes to its value (the sub-label wraps
   under it). The −/+ keep their size (flex-shrink:0) with a 44 px tap overlay, so controls stay reachable. */
@media (max-width:340px){
  .game{padding-left:6px;padding-right:6px}
  .top{gap:4px}
  .hud{padding:8px 8px;column-gap:6px}
  .betctl{gap:4px}.betctl .meter{min-width:0}
  .spinbox{gap:6px}
}
/* the bet sub-label ("15 lines · $0.07 per line") on phones and in a short landscape: it runs the whole width of the bet
   control, under the −/+ (they stand beside the label and the value only), so it takes one or two balanced lines
   instead of three or four in the narrow column between the keys; nothing is cut or left out. Subgrid: the meter keeps
   its own box (a skin's plate on it spans the control), its label, value and sub-label sit on the control's grid. The
   −/+ are positioned (shell rule above), so they paint and take taps over the meter's box. Slots only (the table
   shell lays out its own bet control). */
@media (max-width:860px),(max-aspect-ratio:4/5),(max-height:540px) and (min-aspect-ratio:3/2){
  .game:not(.table-game) .betctl{display:grid;grid-template-columns:auto minmax(min-content,1fr) auto;grid-template-rows:auto auto auto;align-items:center;row-gap:0}
  .game:not(.table-game) .betctl>.meter{grid-column:1/-1;grid-row:1/-1;display:grid;grid-template-columns:subgrid;grid-template-rows:subgrid;row-gap:0;min-width:0}
  .game:not(.table-game) .betctl>.meter>span{grid-column:2;grid-row:1}
  .game:not(.table-game) .betctl>.meter>b{grid-column:2;grid-row:2}
  .game:not(.table-game) .betctl>.meter>small{grid-column:1/-1;grid-row:3;text-wrap:balance}
  .game:not(.table-game) .betctl>.pm[data-bet="-1"]{grid-column:1;grid-row:1/3}
  .game:not(.table-game) .betctl>.pm[data-bet="1"]{grid-column:3;grid-row:1/3}
}
/* short landscape (a phone on its side: 844 × 390, 740 × 360, 915 × 412; any window under 540 px tall and at least 3:2
   wide): the HUD can no longer stand under the board — it took 130 px of 390 and pushed a board at its 40 px cell floor
   up over the title and down over the Buy button. Three columns under the header instead: the options (buy, ante; the
   info tablet of a side-tablets skin under them) on the left, the board in the middle — centred on the page, so the
   title over it is centred on both — and the HUD as a column on the right (balance, bet, win, then autoplay + spin in
   the right thumb's reach); left-handed: mirrored. Every skin's HUD layout (bar, plinth, console, corners, side-column,
   side-tablets) takes this one, so the rules carry #game: they must win over a skin's own phone / wide layout rules.
   Decoration (backgrounds, borders, ornaments, sizes of the skin's parts) stays the skin's. The slot shell only. */
@media (max-height:540px) and (min-aspect-ratio:3/2){
  #game.game:not(.table-game){--land-side:clamp(150px,22vw,236px);--land-gap:clamp(8px,1.4vw,14px);
    grid-template-columns:var(--land-side) minmax(0,1fr) var(--land-side);grid-template-rows:auto minmax(0,1fr);column-gap:var(--land-gap);row-gap:4px;
    padding:calc(env(safe-area-inset-top,0px) + 6px) calc(env(safe-area-inset-right,0px) + 8px) calc(env(safe-area-inset-bottom,0px) + 6px) calc(env(safe-area-inset-left,0px) + 8px)}
  #game.game:not(.table-game)>.top{grid-column:1/-1;grid-row:1}
  /* the stage spans the page with the same three columns; the HUD (a grid item of #game) lies over its empty third one,
     positioned above it so the stage's box never takes the HUD's taps */
  #game.game:not(.table-game)>.stage{grid-column:1/-1;grid-row:2;display:grid;grid-template-columns:var(--land-side) minmax(0,1fr) var(--land-side);
    grid-template-rows:minmax(0,1fr) auto minmax(0,auto) minmax(0,1fr);gap:8px var(--land-gap);align-items:center;min-height:0}
  #game.game:not(.table-game) .boardarea{grid-column:2;grid-row:1/-1;align-self:stretch;width:100%;height:auto;min-height:0}
  #game.game:not(.table-game) .side{grid-column:1;width:100%;min-width:0;max-height:100%}
  #game.game:not(.table-game) .side.left{grid-row:2}
  #game.game:not(.table-game) .side.left:not([hidden]){display:flex;flex-direction:column;align-items:stretch;justify-content:center;gap:8px;order:0}
  #game.game:not(.table-game) .side.left .tablet{flex-direction:column;align-items:center;justify-content:center;width:100%;gap:2px;min-height:44px}
  #game.game:not(.table-game) .side.left .tablet small{display:none}
  #game.game:not(.table-game) .side.right{display:none;grid-row:3}
  /* a side-tablets skin's info tablet (#sideR) under the options; on a short screen it scrolls in its own room */
  #game.game.hud-side-tablets .side.right:not(:empty){display:flex;flex-direction:column;gap:8px;visibility:visible;align-self:stretch;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin}
  #game.game:not(.table-game)>.hud{grid-column:3;grid-row:2;align-self:center;justify-self:stretch;width:auto;max-width:none;max-height:100%;margin:0;position:relative;z-index:3;
    display:flex;flex-direction:column;align-items:stretch;justify-content:center;gap:clamp(4px,1.8vh,10px);padding:10px 8px;text-align:center;transform:none}
  #game.game:not(.table-game)>.hud>.meter{position:relative;inset:auto;z-index:auto;text-align:center;min-width:0;transform:none}
  #game.game:not(.table-game)>.hud>.betctl{align-self:center;justify-content:center;justify-self:auto;width:auto;max-width:100%;margin:0;transform:none}
  #game.game:not(.table-game)>.hud>.spinbox{display:flex;flex-direction:row;justify-content:center;align-items:center;gap:10px;order:0;margin:0;transform:none}
  #game.game:not(.table-game)>.hud .spin{--s:clamp(56px,16vh,74px);margin:0}
  #game.game:not(.table-game)>.hud .auto{width:46px;height:46px;margin:0}
  body.lefty #game.game:not(.table-game)>.hud{grid-column:1}
  body.lefty #game.game:not(.table-game) .side{grid-column:3}
  body.lefty #game.game:not(.table-game)>.hud>.spinbox{flex-direction:row-reverse}
}
/* the smallest phones on their side (568–700 px wide: a 150 px HUD column): the bet keys closer to the value */
@media (max-height:540px) and (min-aspect-ratio:3/2) and (max-width:700px){
  #game.game:not(.table-game)>.hud>.betctl{column-gap:4px}
}
/* ambient motes (fx.js setAmbient): CSS only, run by the compositor (no frame loop on the page while idle), in a layer
   over the scene and under the game — never over the board's symbols or the HUD's numbers */
.fx-motes{position:fixed;inset:0;z-index:1;pointer-events:none;overflow:hidden;contain:strict}
.fx-motes>i{position:absolute;left:var(--x);bottom:-24px;width:var(--d);height:var(--d);margin-left:calc(var(--d)/-2);border-radius:50%;opacity:0;
  background:radial-gradient(circle,#fff 0,var(--c) 18%,color-mix(in srgb,var(--c) 33%,transparent) 50%,transparent 70%);
  animation:fx-mote var(--t) linear var(--delay) infinite;will-change:transform,opacity}
@keyframes fx-mote{0%{transform:translate3d(0,0,0);opacity:0}25%{opacity:calc(var(--a,.7)*.7)}50%{opacity:var(--a,.7)}75%{opacity:calc(var(--a,.7)*.7)}100%{transform:translate3d(var(--dx),calc(-1*var(--rise)),0);opacity:0}}
/* the in-game Demo/Cash switch and the no-funds hint (registered players) */
.wswitch{display:inline-flex;gap:2px;margin-left:6px;vertical-align:1px}
.wswitch button{font:inherit;font-size:10px;font-weight:800;letter-spacing:.04em;color:var(--muted);background:transparent;border:1px solid var(--line);border-radius:4px;padding:1px 6px;cursor:pointer}
.wswitch button[aria-pressed="true"]{color:var(--ink-on-accent,var(--bg));background:var(--accent);border-color:var(--accent)}
.wswitch button:disabled{opacity:.45;cursor:not-allowed}
#fundsHint{color:var(--muted)}
#fundsHint a{color:var(--accent)}
/* reduced motion: every animation and transition ends at once — pseudo-elements too (a skin's ::before/::after glows,
   shimmers and ornaments), and none waits on a delay */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;animation-delay:0s!important;transition-duration:.001ms!important;transition-delay:0s!important;scroll-behavior:auto!important}
  .fx-motes{display:none}
}
