/* ══════════════════════════════════════════════════════════════
   LET'S GET LIT — dice board

   PERFORMANCE CONTRACT
   Every animation here moves only `transform` or `opacity`.
   No animated blur, no animated box-shadow, no animated width or
   height, no backdrop-filter. Layers get promoted on demand and
   released the moment they stop moving, so text re-rasterises crisp.

   LAYOUT CONTRACT
   The game screen is one grid with three areas — hud / stage / dock.
   Portrait stacks them. Landscape on anything tablet-sized or bigger
   puts the board in a full-height column and folds the hud and dock
   into a side rail, so the board always gets the largest square the
   viewport can give it.
   ══════════════════════════════════════════════════════════════ */

/* ── self-hosted type: no third-party request, works offline ── */
@font-face{
  font-family:'Permanent Marker';font-style:normal;font-weight:400;font-display:swap;
  src:url(fonts/permanent-marker-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Caveat';font-style:normal;font-weight:400 700;font-display:swap;
  src:url(fonts/caveat-latin.woff2) format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:'Caveat';font-style:normal;font-weight:400 700;font-display:swap;
  src:url(fonts/caveat-latin-ext.woff2) format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

:root{
  --ink:#0a0710;
  --chalk:#f6efe2;
  --pink:#ff3f86;
  --cyan:#2fd8e8;
  --lime:#4ded9b;
  --sun:#ffd63d;
  --tang:#ff8a3d;
  --grape:#b06cff;
  --u:6px;
  --hand:'Permanent Marker','Marker Felt','Comic Sans MS',cursive;
  --chalkfont:'Caveat','Bradley Hand',cursive;
  --ui:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --st:env(safe-area-inset-top,0px);
  --sb:env(safe-area-inset-bottom,0px);
  --sl:env(safe-area-inset-left,0px);
  --sr:env(safe-area-inset-right,0px);
  --ease:cubic-bezier(.22,.9,.28,1);
  --pop:cubic-bezier(.2,.9,.3,1.5);
  --pc:var(--chalk);
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{margin:0;padding:0;height:100%;overflow:hidden;background:var(--ink);color:var(--chalk);
  font-family:var(--ui);-webkit-font-smoothing:antialiased;overscroll-behavior:none;touch-action:manipulation}
body{position:fixed;inset:0}
button{font:inherit;color:inherit;background:none;border:none;cursor:pointer}
:focus{outline:none}
:focus-visible{outline:3px solid var(--sun);outline-offset:3px;border-radius:8px}

/* ── ambience: pre-painted gradient sheets that only translate ── */
#haze{position:fixed;inset:-30%;z-index:0;pointer-events:none;contain:strict}
#haze i{position:absolute;inset:0;display:block;opacity:.42;will-change:transform;animation:drift 42s ease-in-out infinite}
#haze i:nth-child(1){background:
  radial-gradient(38% 30% at 22% 24%, rgba(255,63,134,.55), transparent 70%),
  radial-gradient(34% 28% at 78% 72%, rgba(176,108,255,.45), transparent 70%)}
#haze i:nth-child(2){animation-duration:56s;animation-direction:reverse;opacity:.3;background:
  radial-gradient(34% 26% at 74% 18%, rgba(47,216,232,.45), transparent 70%),
  radial-gradient(32% 26% at 26% 82%, rgba(255,138,61,.4), transparent 70%)}
@keyframes drift{0%,100%{transform:translate3d(0,0,0) scale(1)}50%{transform:translate3d(4%,-3%,0) scale(1.14)}}

.hearts{position:fixed;inset:0;z-index:1;pointer-events:none;overflow:hidden;contain:strict}
.hearts span{position:absolute;top:0;left:0;font-size:clamp(13px,2.2vw,22px);color:var(--pink);opacity:.4;
  will-change:transform;animation:floatup linear infinite}
@keyframes floatup{
  from{transform:translate3d(0,108vh,0) rotate(-18deg) scale(.7)}
  to{transform:translate3d(0,-14vh,0) rotate(22deg) scale(1.1)}
}
#fx{position:fixed;inset:0;z-index:90;pointer-events:none}

/* ══════════════════ SCREENS ══════════════════ */
.screen{position:fixed;inset:0;z-index:5;
  padding:calc(14px + var(--st)) calc(14px + var(--sr)) calc(14px + var(--sb)) calc(14px + var(--sl));
  opacity:0;visibility:hidden;
  transition:opacity .4s var(--ease),transform .4s var(--ease),visibility .4s}
.screen.on{opacity:1;visibility:visible}
/* Only the menu screens get the little scale-in. The game screen must never
   sit inside a transformed ancestor: the beams, the card zoom and the cell
   hit-testing all mix getBoundingClientRect() readings with untransformed
   local offsets, and a scaled parent silently skews every one of them. */
.screen.flow:not(.on){transform:scale(.98)}
/* menus scroll if a short viewport cannot hold them; the board never does */
.screen.flow{display:flex;flex-direction:column;align-items:center;justify-content:center;
  overflow-y:auto;overflow-x:hidden;overscroll-behavior:contain}
.screen.flow > *{flex:0 0 auto}

.brand{text-align:center;max-width:min(94vw,900px)}
.brand .l1{font-family:var(--chalkfont);font-size:clamp(38px,11vw,120px);line-height:.85;display:block;transform:rotate(-4deg)}
.brand .l2{font-family:var(--hand);font-size:clamp(44px,15vw,168px);line-height:.92;display:block;
  text-shadow:0 0 30px rgba(255,255,255,.3)}
.brand .rule{display:flex;gap:clamp(6px,1.6vw,14px);justify-content:center;margin:clamp(14px,3vh,26px) 0 0;flex-wrap:wrap}
.tag{font-family:var(--chalkfont);font-size:clamp(17px,3.6vw,26px);color:#cbbfae;
  margin:clamp(14px,3vh,26px) auto clamp(18px,4vh,32px);max-width:44ch;line-height:1.25}
.stack{display:flex;flex-direction:column;gap:14px;width:min(92vw,560px)}
.big{position:relative;border:3px solid var(--chalk);border-radius:18px;padding:clamp(15px,2.4vh,22px) 20px;text-align:left;
  background:rgba(255,255,255,.03);display:flex;align-items:center;gap:16px;
  transition:transform .2s var(--pop),background .2s}
.big::after{content:"";position:absolute;inset:-2px;border-radius:20px;opacity:0;pointer-events:none;
  box-shadow:0 0 34px var(--glow,rgba(255,255,255,.4));transition:opacity .2s}
.big:hover,.big:focus-visible{transform:translateY(-4px) rotate(-.6deg);background:rgba(255,255,255,.08)}
.big:hover::after,.big:focus-visible::after{opacity:1}
.big:active{transform:translateY(0) scale(.985)}
.big .em{font-size:clamp(28px,7vw,40px);line-height:1}
.big b{display:block;font-family:var(--hand);font-size:clamp(19px,4.6vw,28px)}
.big small{display:block;font-family:var(--chalkfont);font-size:clamp(15px,3.4vw,20px);color:#bdb2a3;line-height:1.15;margin-top:2px}
.big{text-decoration:none}
.big.pink{--glow:rgba(255,63,134,.55);border-color:var(--pink)}
.big.pink b{color:var(--pink)}
.big.cyan{--glow:rgba(47,216,232,.5);border-color:var(--cyan)}
.big.cyan b{color:var(--cyan)}
.mini-row{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-top:clamp(18px,4vh,30px)}
.chip{border:2px solid rgba(246,239,226,.35);border-radius:999px;padding:9px 16px;font-family:var(--chalkfont);
  font-size:clamp(15px,3.2vw,19px);color:#cdc2b3;transition:border-color .2s,color .2s,background .2s;min-height:44px;
  display:flex;align-items:center;gap:8px}
.chip:hover,.chip:focus-visible{border-color:var(--chalk);color:var(--chalk)}
.chip[aria-pressed="true"]{background:var(--lime);border-color:var(--lime);color:#08210f;font-weight:700}
.foot{margin:clamp(16px,3vh,28px) auto 0;text-align:center;font-family:var(--chalkfont);
  font-size:clamp(13px,2.8vw,16px);color:#6f6659;padding:0 16px;max-width:60ch}

/* ── player setup ──
   The panel is capped to the screen and the roster is the only part that
   flexes, so the name field and the Start button stay put no matter how
   many people are in the game or how short the viewport is. */
.screen.flow > .panel{flex:0 1 auto}
.panel{width:min(94vw,660px);display:flex;flex-direction:column;gap:14px;margin:auto 0;
  max-height:100%;min-height:0}
.h2{font-family:var(--hand);font-size:clamp(26px,7vw,44px);text-align:center;color:var(--sun);transform:rotate(-1.5deg)}
.namebar{display:flex;gap:10px}
.namebar input{flex:1;min-width:0;background:rgba(255,255,255,.05);border:3px solid rgba(246,239,226,.4);border-radius:14px;
  padding:14px 16px;color:var(--chalk);font-family:var(--chalkfont);font-size:clamp(19px,4.4vw,24px);min-height:52px;
  transition:border-color .2s}
.namebar input::placeholder{color:#7d7367}
.namebar input:focus{border-color:var(--cyan)}
.add{border:3px solid var(--cyan);color:var(--cyan);border-radius:14px;padding:0 20px;font-family:var(--hand);
  font-size:clamp(22px,5vw,28px);min-width:60px;transition:background .18s,color .18s}
.add:hover{background:var(--cyan);color:#04222a}
.roster{list-style:none;margin:0;padding:4px;display:flex;flex-wrap:wrap;gap:10px;overflow-y:auto;
  flex:1 1 auto;min-height:64px;max-height:38dvh;
  align-content:flex-start;justify-content:center;overscroll-behavior:contain}
.roster li{display:flex;align-items:center;gap:10px;border:3px solid var(--pc);border-radius:999px;padding:8px 8px 8px 16px;
  font-family:var(--hand);font-size:clamp(16px,3.8vw,21px);color:var(--pc);animation:pop .3s var(--pop)}
@keyframes pop{from{transform:scale(.4) rotate(-8deg);opacity:0}to{transform:none;opacity:1}}
.roster li button{width:30px;height:30px;border-radius:50%;background:rgba(255,255,255,.1);line-height:1;font-size:17px;
  display:grid;place-items:center}
.roster li button:hover{background:var(--pink)}
.empty{font-family:var(--chalkfont);color:#6f6659;font-size:clamp(16px,3.6vw,20px);text-align:center;padding:18px;border:0}
.bye{font-family:var(--chalkfont);font-size:clamp(22px,6vw,34px);color:#cbbfae;line-height:1.3;text-align:center;
  max-width:24ch;margin:0}
.row2{display:flex;gap:12px}
.btn{flex:1;border:3px solid var(--chalk);border-radius:16px;padding:14px;font-family:var(--hand);
  font-size:clamp(17px,4vw,22px);min-height:54px;transition:background .18s,color .18s,transform .18s var(--pop)}
.btn:hover{background:rgba(255,255,255,.1)}
.btn:active{transform:scale(.97)}
.btn.go{border-color:var(--lime);color:var(--lime)}
.btn.go:hover{background:var(--lime);color:#062615}
.btn.go[disabled]{opacity:.3;pointer-events:none}
.btn.ghost{border-color:rgba(246,239,226,.35);color:#a99e90;flex:0 0 auto;padding:14px 22px}

/* ══════════════════ GAME SCREEN ══════════════════
   One grid, three areas. The stage row is the only flexible one,
   so the board gets every pixel the hud and dock do not need. */
#screen-game{
  display:grid;
  grid-template-areas:"hud" "stage" "dock";
  grid-template-rows:auto minmax(0,1fr) auto;
  gap:clamp(6px,1.4vh,14px);
  padding:calc(8px + var(--st)) calc(10px + var(--sr)) calc(8px + var(--sb)) calc(10px + var(--sl));
}
.hud{grid-area:hud;min-width:0;display:flex;flex-direction:column;gap:8px;justify-content:center}
.hud-top{display:grid;grid-template-columns:44px minmax(0,1fr) 44px;align-items:center;gap:10px;
  width:100%;max-width:1400px;margin:0 auto}
.hud .who{min-width:0;text-align:center}
.hud .who .lbl{font-family:var(--chalkfont);font-size:clamp(12px,2.6vw,16px);color:#7d7367;letter-spacing:.14em;text-transform:uppercase}
.hud .who .nm{font-family:var(--hand);font-size:clamp(20px,5.4vw,34px);color:var(--pc);line-height:1.05;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hud .who .nm.swap{animation:swapin .45s var(--pop)}
@keyframes swapin{from{transform:translate3d(0,14px,0) scale(.82);opacity:0}to{transform:none;opacity:1}}
.icon{width:44px;height:44px;flex:0 0 auto;border:2px solid rgba(246,239,226,.3);border-radius:12px;display:grid;place-items:center;
  font-size:19px;color:#bdb2a3;transition:transform .2s var(--pop),border-color .2s,color .2s}
.icon:hover{border-color:var(--chalk);color:var(--chalk);transform:rotate(-6deg)}
.icon[hidden]{display:none}

/* turn order — dots on a phone, a named list on a wide screen */
.turnlist{list-style:none;margin:0;padding:0;display:flex;gap:9px;justify-content:center;align-items:center;
  flex-wrap:wrap;max-width:100%}
.turnlist:empty{display:none}
.turnlist li{display:flex;align-items:center;gap:9px;min-width:0}
.turnlist .dot{width:10px;height:10px;border-radius:50%;background:var(--pc);opacity:.4;flex:0 0 auto;
  transition:transform .3s var(--pop),opacity .3s}
.turnlist li.now .dot{opacity:1;transform:scale(1.8)}
.turnlist .who2{display:none;font-family:var(--hand);font-size:16px;color:var(--pc);opacity:.55;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.turnlist li.now .who2{opacity:1}

.stage{grid-area:stage;min-width:0;min-height:0;display:grid;place-items:center;position:relative}
.board-wrap{position:relative}
.board{
  --bw:min(88vmin,880px);
  --u:calc(var(--bw)/100);
  position:relative;width:var(--bw);height:var(--bw);display:grid;
  grid-template-columns:.68fr repeat(6,1fr);grid-template-rows:.68fr repeat(6,1fr);
  gap:calc(var(--u)*.28);padding:calc(var(--u)*.6);
  background:radial-gradient(ellipse at 30% 8%,#1b1426 0%,#0a0710 62%);
  border:calc(var(--u)*.36) solid rgba(246,239,226,.85);border-radius:calc(var(--u)*1.4);
  box-shadow:0 26px 70px rgba(0,0,0,.75)}
.corner{display:grid;place-items:center;font-family:var(--chalkfont);font-size:calc(var(--u)*1.4);color:#6f6659;
  line-height:1;text-align:center}
.rail{display:grid;place-items:center}
.rail .die-mini{transition:transform .3s var(--pop)}
.rail.hot .die-mini{transform:scale(1.24) rotate(-8deg)}
.die-mini{width:calc(var(--u)*5);height:calc(var(--u)*5);border:calc(var(--u)*.3) solid var(--dc,var(--cyan));
  border-radius:calc(var(--u)*.7);display:grid;grid-template:repeat(3,1fr)/repeat(3,1fr);padding:calc(var(--u)*.5);
  gap:calc(var(--u)*.14)}
.die-mini i{width:100%;height:100%;border-radius:50%;background:var(--dc,var(--cyan));display:block}

.cell{position:relative;border:calc(var(--u)*.24) solid rgba(246,239,226,.7);border-radius:calc(var(--u)*.5);
  display:grid;place-items:center;padding:calc(var(--u)*.35);overflow:hidden;contain:layout paint;
  transition:transform .22s var(--pop),border-color .22s}
.cell::after{content:"";position:absolute;inset:0;border-radius:inherit;opacity:0;pointer-events:none;
  background:radial-gradient(circle at 50% 50%,color-mix(in srgb,var(--c,#fff) 30%,transparent),transparent 72%);
  transition:opacity .22s}
.cell .in{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:calc(var(--u)*.18);
  text-align:center;width:100%;line-height:.98}
/* --f is measured once per square (see fitCellText) and is the largest type
   that still fits. It is expressed in --u, so the same number holds whether
   the board is 300px on a phone or 1200px on a monitor. */
.cell .t{font-family:var(--hand);color:var(--c,var(--chalk));font-size:calc(var(--u)*var(--f,1.7));
  overflow-wrap:break-word}
.cell .s{font-family:var(--chalkfont);font-weight:700;font-size:calc(var(--u)*var(--f,1.7)*.62);
  color:#cabfb0;line-height:1;overflow-wrap:break-word}
.cell:hover,.cell:focus-visible{transform:scale(1.07);z-index:3;border-color:var(--chalk)}
.cell:hover::after,.cell:focus-visible::after{opacity:1}
.cell:active{transform:scale(.97)}
.cell.hit{border-color:var(--sun);animation:hit .62s var(--ease)}
.cell.hit::after{opacity:1}
@keyframes hit{0%{transform:scale(1)}34%{transform:scale(1.26) rotate(2.5deg)}100%{transform:scale(1)}}
.cell.pickable{border-color:var(--sun)}
.cell.pickable::after{opacity:.45}

/* scan beams — two composited strips instead of twelve glowing cells */
.beam{position:absolute;left:0;top:0;pointer-events:none;opacity:0;border-radius:calc(var(--u)*.4);
  transform-origin:0 0;will-change:transform,opacity}
.beam.h{background:linear-gradient(90deg,transparent,rgba(255,63,134,.55) 22%,rgba(255,214,61,.75) 50%,rgba(255,63,134,.55) 78%,transparent)}
.beam.v{background:linear-gradient(180deg,transparent,rgba(47,216,232,.55) 22%,rgba(255,214,61,.75) 50%,rgba(47,216,232,.55) 78%,transparent)}

/* ── dock ── */
.dock{grid-area:dock;min-width:0;display:flex;align-items:center;justify-content:center;
  gap:clamp(12px,3vw,26px);flex-wrap:wrap}
.cradle{display:flex;gap:clamp(6px,1.6vw,12px)}
.die-flat{width:clamp(34px,8vw,54px);height:clamp(34px,8vw,54px);border-radius:22%;background:#fbf6ec;
  display:grid;grid-template:repeat(3,1fr)/repeat(3,1fr);padding:13%;gap:5%;
  box-shadow:0 4px 14px rgba(0,0,0,.5)}
.die-flat i{background:var(--dot,#ff3f86);border-radius:50%;display:block}
.die-flat.pulse{animation:diepulse .5s var(--pop)}
@keyframes diepulse{0%{transform:scale(1)}45%{transform:scale(1.22) rotate(-7deg)}100%{transform:scale(1)}}
.throw{position:relative;border:4px solid var(--sun);border-radius:999px;color:var(--sun);
  padding:clamp(11px,2vh,17px) clamp(22px,5.5vw,46px);font-family:var(--hand);font-size:clamp(18px,4.6vw,28px);
  min-height:58px;transition:transform .16s var(--pop),background .2s,color .2s}
.throw::after{content:"";position:absolute;inset:-4px;border-radius:999px;box-shadow:0 0 30px rgba(255,214,61,.45);
  opacity:.55;pointer-events:none;transition:opacity .2s}
.throw:hover{background:var(--sun);color:#241a00}
.throw:hover::after{opacity:1}
.throw:active{transform:scale(.95)}
.throw[disabled]{opacity:.4;pointer-events:none}
.throw .kbd{display:block;font-family:var(--ui);font-size:10px;letter-spacing:.16em;opacity:.7;margin-top:1px}
@media (hover:none){.throw .kbd{display:none}}

/* ══════════════════════════════════════════════════════
   WIDE LANDSCAPE — the board takes the full height and the
   hud + dock fold into a side rail. Kicks in for laptop, desktop,
   tablet landscape and any phone held sideways with room to spare.
   ══════════════════════════════════════════════════════ */
@media (orientation:landscape) and (min-width:700px){
  #screen-game{
    grid-template-areas:"stage hud" "stage dock";
    grid-template-columns:minmax(0,1fr) clamp(200px,23vw,340px);
    grid-template-rows:minmax(0,1fr) minmax(0,1fr);
    column-gap:clamp(12px,2.2vw,32px);
    row-gap:clamp(10px,2vh,20px);
    padding:calc(12px + var(--st)) calc(16px + var(--sr)) calc(12px + var(--sb)) calc(16px + var(--sl));
  }
  .hud{align-self:end;gap:12px;
    border:2px solid rgba(246,239,226,.16);border-radius:20px;background:rgba(255,255,255,.035);
    padding:clamp(12px,1.8vh,20px) clamp(12px,1.4vw,18px)}
  .hud .who .nm{white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere;
    font-size:clamp(22px,2.4vw,36px)}
  .hud .who .lbl{font-size:clamp(12px,.9vw,15px)}
  .turnlist{flex-direction:column;align-items:stretch;gap:4px;flex-wrap:nowrap;
    overflow-y:auto;overscroll-behavior:contain;max-height:min(34vh,300px);
    border-top:2px dashed rgba(246,239,226,.16);padding-top:10px}
  .turnlist li{padding:5px 10px;border-radius:10px;border:2px solid transparent;gap:10px}
  .turnlist li.now{border-color:var(--pc);background:rgba(255,255,255,.05)}
  .turnlist .who2{display:block}

  .dock{align-self:start;flex-direction:column;gap:clamp(12px,2vh,20px);
    border:2px solid rgba(246,239,226,.16);border-radius:20px;background:rgba(255,255,255,.035);
    padding:clamp(12px,1.8vh,20px) clamp(12px,1.4vw,18px)}
  .cradle{gap:clamp(10px,1vw,16px)}
  .die-flat{width:clamp(40px,4.2vw,62px);height:clamp(40px,4.2vw,62px)}
  .throw{width:100%;padding:clamp(12px,1.8vh,18px) 10px;font-size:clamp(19px,1.9vw,30px)}
}

/* ── short landscape: a phone on its side ──
   Stacked menus do not fit in 390px of height, and the casualty is always
   the control at the bottom — on the setup screen that was the Start button,
   pushed clean off the fold. So the menus turn side by side and use the width
   the device actually has. */
@media (orientation:landscape) and (max-height:540px) and (min-width:640px){
  .screen.menu{
    display:grid;
    grid-template-columns:1fr minmax(0,clamp(260px,42vw,440px));
    grid-template-areas:"brand stack" "brand chips";
    grid-template-rows:auto auto;
    align-content:center;justify-items:center;align-items:center;
    column-gap:clamp(16px,3vw,44px);row-gap:10px}
  .screen.menu .brand{grid-area:brand;align-self:center}
  .screen.menu .stack{grid-area:stack;width:100%}
  .screen.menu .mini-row{grid-area:chips;margin-top:0}
  .screen.menu .tag,.screen.menu .foot{display:none}
  .big{padding:11px 16px;gap:12px}
  .big small{font-size:15px}
}

@media (orientation:landscape) and (max-height:430px){
  .tag{display:none}
  .brand .l2{font-size:clamp(34px,9vw,68px)}
  .brand .l1{font-size:clamp(26px,6vw,48px)}
  .foot{display:none}
  .icon{width:38px;height:38px;font-size:16px}
  .hud-top{grid-template-columns:38px minmax(0,1fr) 38px}
  .throw{min-height:46px}
  .turnlist{max-height:22vh}
  .h2{font-size:clamp(20px,4.4vw,30px)}
  .panel{gap:9px}
  .namebar input{min-height:44px;padding:9px 14px}
  .btn{min-height:46px;padding:10px}
}

/* ══════════════════ THE DICE ARENA ══════════════════ */
#dim{position:fixed;inset:0;z-index:20;background:#05030a;opacity:0;visibility:hidden;
  transition:opacity .45s var(--ease),visibility .45s}
#dim.on{opacity:.78;visibility:visible}

/* The exit is deliberately quicker than it looks like it needs to be. The
   board's landing sequence — beams, cell hit, confetti — starts 260ms after
   close() is called, and while this is still fading, its whole preserve-3d
   subtree (two dice, twelve faces, shadows) has to composite through a group
   opacity. Finishing inside that 260ms keeps the two off each other. */
.arena{position:fixed;inset:0;z-index:30;visibility:hidden;opacity:0;touch-action:none;
  perspective:1100px;perspective-origin:50% 50%;transition:opacity .22s var(--ease),visibility .22s;
  --padx:26px;--pady:26px}
.arena.on{visibility:visible;opacity:1}

/* the table is a centred rectangle, not the whole screen — so a
   throw on a 32-inch monitor feels the same as one on a phone */
.wall{position:absolute;pointer-events:none;opacity:.16;background:var(--chalk);transition:opacity .5s ease-out}
.wall.n,.wall.s{left:var(--padx);right:var(--padx);height:3px}
.wall.e,.wall.w{top:var(--pady);bottom:var(--pady);width:3px}
.wall.n{top:calc(var(--pady) - 3px)}
.wall.s{bottom:calc(var(--pady) - 3px)}
.wall.w{left:calc(var(--padx) - 3px)}
.wall.e{right:calc(var(--padx) - 3px)}
.wall.lit{opacity:.95;transition:opacity .04s}
.corner-mark{position:absolute;width:26px;height:26px;border:3px solid var(--sun);opacity:.35;pointer-events:none}
.cm1{top:var(--pady);left:var(--padx);border-right:0;border-bottom:0}
.cm2{top:var(--pady);right:var(--padx);border-left:0;border-bottom:0}
.cm3{bottom:var(--pady);left:var(--padx);border-right:0;border-top:0}
.cm4{bottom:var(--pady);right:var(--padx);border-left:0;border-top:0}

.ripple{position:absolute;left:0;top:0;width:70px;height:70px;margin:-35px 0 0 -35px;border-radius:50%;
  border:3px solid var(--chalk);opacity:0;pointer-events:none;will-change:transform,opacity}

.dshadow{position:absolute;left:0;top:0;width:var(--D);height:var(--D);border-radius:50%;pointer-events:none;
  background:radial-gradient(circle,rgba(0,0,0,.72),rgba(0,0,0,.28) 52%,transparent 72%);will-change:transform,opacity}
.die3d{position:absolute;left:0;top:0;width:var(--D);height:var(--D);transform-style:preserve-3d;pointer-events:none;
  will-change:transform}
/* backface-visibility matters more here than it looks. Every face is rotated
   into place and then pushed outward, so its front always points away from the
   cube's centre and the three facing away from the camera can never be seen —
   but without this they are still rasterised, gradient, border and all. Culling
   them took the worst frame when the table opens from 24.9ms to 8.8ms. */
.die3d .face{position:absolute;inset:0;border-radius:15%;background:linear-gradient(150deg,#fffdf7,#ece3d3);
  border:2px solid rgba(20,12,30,.85);display:grid;grid-template:repeat(3,1fr)/repeat(3,1fr);padding:13%;gap:5%;
  box-shadow:inset 0 0 18px rgba(80,60,40,.22);backface-visibility:hidden}
/* Flat pips, deliberately. An inset shadow on each of the 42 pips costs a blur
   pass apiece and measured a whole dropped frame every time the table opens
   (worst frame 25.1ms -> 16.6ms without it) for a 2px detail nobody can see at
   dice size. The rail dice and the dock dice have always drawn flat pips, so
   this matches them rather than departing from anything. */
.die3d .face i{background:var(--dot,#ff3f86);border-radius:50%;display:block}
.f1{transform:translateZ(var(--h))}
.f2{transform:rotateY(90deg) translateZ(var(--h))}
.f3{transform:rotateY(180deg) translateZ(var(--h))}
.f4{transform:rotateY(-90deg) translateZ(var(--h))}
.f5{transform:rotateX(90deg) translateZ(var(--h))}
.f6{transform:rotateX(-90deg) translateZ(var(--h))}

.arena-hint{position:absolute;left:50%;top:calc(var(--pady) + 26px);transform:translateX(-50%);text-align:center;
  font-family:var(--chalkfont);font-size:clamp(17px,4vw,24px);color:#9a8f80;pointer-events:none;
  transition:opacity .35s;max-width:min(80vw,520px);line-height:1.2}
.arena-hint b{color:var(--sun);font-family:var(--hand);display:block;font-size:clamp(19px,4.6vw,28px)}
.arena-hint.gone{opacity:0}
.arena-out{position:absolute;right:calc(var(--padx) + 4px);top:calc(var(--pady) + 4px);width:46px;height:46px;
  border-radius:50%;border:2px solid rgba(246,239,226,.35);color:#bdb2a3;display:grid;place-items:center;font-size:18px;
  pointer-events:auto;transition:transform .2s var(--pop);background:rgba(10,7,16,.5)}
.arena-out:hover{transform:rotate(90deg)}
.arena-res{position:absolute;left:50%;bottom:calc(var(--pady) + 34px);transform:translate3d(-50%,20px,0) scale(.8);
  font-family:var(--hand);font-size:clamp(22px,6vw,38px);color:var(--sun);opacity:0;pointer-events:none;
  transition:transform .45s var(--pop),opacity .35s;white-space:nowrap}
.arena-res.on{opacity:1;transform:translate3d(-50%,0,0) scale(1)}

/* ══════════════════ ZOOM SHEET ══════════════════ */
#scrim{position:fixed;inset:0;z-index:40;background:rgba(5,3,9,.74);opacity:0;visibility:hidden;
  transition:opacity .35s var(--ease),visibility .35s}
#scrim.on{opacity:1;visibility:visible}
.sheet{position:fixed;z-index:50;left:50%;top:50%;width:min(92vw,620px);max-height:min(86dvh,780px);
  transform:translate(-50%,-50%);border-radius:26px;border:5px solid var(--c,var(--chalk));
  background:linear-gradient(170deg,#14101d,#0a0710);padding:clamp(18px,4vw,32px);
  display:flex;flex-direction:column;gap:clamp(10px,2vh,16px);visibility:hidden;overflow:hidden;
  box-shadow:0 40px 90px rgba(0,0,0,.8)}
.sheet.on{visibility:visible}
.sheet .badge{display:flex;align-items:center;gap:8px;justify-content:center;font-family:var(--chalkfont);
  font-size:clamp(14px,3vw,17px);color:#8b8073;letter-spacing:.1em;text-transform:uppercase;flex:0 0 auto}
.sheet .badge .d{display:inline-grid;grid-template:repeat(3,1fr)/repeat(3,1fr);width:26px;height:26px;
  border:2px solid #8b8073;border-radius:6px;padding:3px;gap:1px}
.sheet .badge .d i{background:#8b8073;border-radius:50%}
.sheet .title{font-family:var(--hand);font-size:clamp(30px,8.5vw,58px);line-height:.95;text-align:center;
  color:var(--c,var(--chalk));flex:0 0 auto}
.sheet .sub{font-family:var(--chalkfont);font-weight:700;font-size:clamp(19px,4.6vw,26px);text-align:center;
  color:#d8cdbd;line-height:1.1;flex:0 0 auto}
.sheet .how{font-family:var(--ui);font-size:clamp(14px,3.5vw,18px);line-height:1.5;color:#a89d8f;text-align:center;
  border-top:2px dashed rgba(246,239,226,.18);padding-top:clamp(10px,2vh,16px);overflow:auto;flex:1 1 auto;min-height:0;
  overscroll-behavior:contain}
.sheet .how b{color:var(--chalk)}
.sheet .actions{display:flex;gap:10px;flex:0 0 auto}
.sheet .actions .btn{border-color:var(--c,var(--chalk));color:var(--c,var(--chalk))}
.sheet .actions .btn:hover{background:var(--c,var(--chalk));color:#0a0710}
.sheet .whofor{font-family:var(--hand);text-align:center;font-size:clamp(16px,4vw,22px);color:var(--pc);flex:0 0 auto}
/* on a wide, short screen the sheet reads better as two columns */
@media (orientation:landscape) and (min-width:820px) and (max-height:620px){
  .sheet{width:min(92vw,880px);display:grid;grid-template-columns:1fr 1fr;
    grid-template-areas:"badge how" "title how" "sub how" "whofor how" "act act";
    align-content:center;gap:8px clamp(18px,3vw,30px)}
  .sheet .badge{grid-area:badge}
  .sheet .title{grid-area:title}
  .sheet .sub{grid-area:sub}
  .sheet .whofor{grid-area:whofor}
  .sheet .how{grid-area:how;border-top:0;border-left:2px dashed rgba(246,239,226,.18);
    padding-top:0;padding-left:clamp(16px,2.4vw,26px);text-align:left;align-self:stretch}
  .sheet .actions{grid-area:act;margin-top:8px}
}

#toast{position:fixed;left:50%;bottom:calc(104px + var(--sb));transform:translate3d(-50%,18px,0);z-index:80;
  background:#1b1426;border:3px solid var(--tc,var(--sun));color:var(--tc,var(--sun));border-radius:999px;
  padding:11px 22px;font-family:var(--hand);font-size:clamp(15px,3.6vw,20px);opacity:0;
  transition:opacity .3s,transform .3s var(--ease);pointer-events:none;max-width:88vw;text-align:center}
#toast.on{opacity:1;transform:translate3d(-50%,0,0)}
@media (orientation:landscape) and (min-width:700px){
  #toast{bottom:calc(26px + var(--sb))}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.01ms !important;animation-iteration-count:1 !important;transition-duration:.1s !important}
  #haze i,.hearts span{animation:none !important}
}
