/* ================================================================
   Shared theme + shell layout for every game on the platform.
   Game-specific rules live in games/<id>/style.css.
   ================================================================ */
:root, :root[data-theme="dark"]{
  --bg:#0f1720; --panel:#18232f; --panel-2:#24374b; --panel-3:#2f4762; --line:#3c5470;
  --ink:#eef4fa; --muted:#a8bccf; --accent:#f5a623; --ok:#43b96b; --bad:#e0533d; --dev:#a97ce0;
  --btn-ink:#eef4fa; --btn-edge:#4d6b8e; --sea1:#1b4d6d; --sea2:#0c2537;
  --glass:rgba(19,29,40,.94); --shadow:rgba(0,0,0,.55);
  --ok-bg:#243b2c; --ok-edge:#3d6a4c; --warn-bg:#3a2a1c; --warn-edge:#6b4a2a;
  --gold-bg:#3a2f14; --gold-edge:#7a6320; --gold-ink:#f7d98a;
  --radius:12px;
  --font:"Segoe UI",system-ui,-apple-system,Roboto,Helvetica,Arial,sans-serif;
}
/* Light mode. Every colour in the platform comes from these tokens, so the
   whole app (including the board chrome) follows a single attribute flip. */
:root[data-theme="light"]{
  --bg:#eef2f6; --panel:#ffffff; --panel-2:#e6ecf3; --panel-3:#d6e0ea; --line:#c3d0dd;
  --ink:#16212c; --muted:#5b6f82; --accent:#d98407; --ok:#2f8f52; --bad:#c4402d; --dev:#7b4bbd;
  --btn-ink:#16212c; --btn-edge:#a9bbcb; --sea1:#7fb6d6; --sea2:#bcd7e8;
  --glass:rgba(255,255,255,.95); --shadow:rgba(20,40,60,.22);
  --ok-bg:#dff2e5; --ok-edge:#7fbe97; --warn-bg:#fbeedd; --warn-edge:#d9ac70;
  --gold-bg:#fbf1d6; --gold-edge:#d9b95e; --gold-ink:#6b5312;
}
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0; background:var(--bg); color:var(--ink); font-family:var(--font); -webkit-font-smoothing:antialiased;
  /* iOS inflates text inside wide blocks unless this is pinned, which
     silently overflows the one-row build bar. */
  -webkit-text-size-adjust:100%; text-size-adjust:100%;
  /* stop the rubber-band scroll that drags fixed furniture around on iOS */
  overscroll-behavior-y:none}
button{font-family:inherit}
.hidden{display:none !important}
a{color:var(--accent)}

/* ---------- buttons ---------- */
.btn{
  background:var(--panel-3); color:var(--btn-ink);
  border:1px solid var(--btn-edge); border-bottom-color:rgba(0,0,0,.25);
  padding:11px 14px; border-radius:10px; cursor:pointer;
  font-size:14px; font-weight:700; letter-spacing:.2px; line-height:1.25;
  box-shadow:0 1px 0 rgba(255,255,255,.06) inset, 0 2px 6px rgba(0,0,0,.35);
  transition:.13s background,.13s border-color,.1s transform;
}
.btn:hover:not(:disabled){background:var(--panel-2); border-color:var(--accent)}
.btn:active:not(:disabled){transform:translateY(1px); box-shadow:none}
.btn:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
.btn.primary{background:linear-gradient(#f7b13c,#e79312); color:#2a1d02; border-color:#b87a06}
.btn.primary:hover:not(:disabled){background:linear-gradient(#ffc257,#f2a222)}
.btn.good{background:linear-gradient(#4ec97a,#2f9d55); color:#05230f; border-color:#237a41}
.btn.good:hover:not(:disabled){background:linear-gradient(#63dc8d,#3bb265)}
.btn.dev{background:linear-gradient(#b98ce8,#8d5cc9); color:#1c0c2e; border-color:#7444ad}
.btn.dev:hover:not(:disabled){background:linear-gradient(#c9a2f2,#9d6cd9)}
.btn.ghost{background:var(--panel-2); border-color:var(--line)}
.btn.sm{padding:7px 11px; font-size:12.5px}
.cost{display:block; font-size:10.5px; font-weight:600; color:var(--muted); margin-top:3px}
/* disabled LAST so it beats the variant gradients at equal specificity */
.btn:disabled{background:var(--panel-2); background-image:none; color:var(--muted);
  border-color:var(--line); box-shadow:none; cursor:not-allowed; opacity:1}
.btn:disabled .cost{color:var(--muted)}
.btn:disabled .ico{opacity:.45}

input[type=text]{background:var(--bg); border:1px solid var(--line); color:var(--ink);
  padding:11px 12px; border-radius:10px; font-size:14px; width:100%}
select{background:var(--bg); border:1px solid var(--line); color:var(--ink);
  padding:9px 11px; border-radius:10px; font-size:14px; font-family:inherit}
.card{background:var(--panel); border:1px solid var(--line); border-radius:var(--radius);
  padding:18px; margin-top:16px}
h1,h2,h3{margin:0 0 10px}
h1{font-size:26px} h2{font-size:17px}
h3{font-size:12.5px; text-transform:uppercase; letter-spacing:1px; color:var(--muted)}
.muted{color:var(--muted); font-size:13px; line-height:1.5}
.row{display:flex; gap:10px; align-items:center; flex-wrap:wrap}
.col{display:flex; flex-direction:column; gap:10px}
.ico{display:inline-block; vertical-align:middle; flex:none}
.pill{font-size:11px; padding:3px 9px; border-radius:999px; background:var(--panel-2);
  color:var(--muted); text-transform:uppercase; letter-spacing:.8px}
.swatch{width:14px;height:14px;border-radius:4px;border:1px solid rgba(0,0,0,.5); flex:none}
.hubLink{font-size:12px; text-decoration:none; color:var(--muted); font-weight:700}
.hubLink:hover{color:var(--accent)}

/* ============================================================
   LOBBY
   ============================================================ */
#lobby{max-width:980px; margin:0 auto; padding:24px 18px 60px}
.brand{display:flex; align-items:center; gap:12px; margin-bottom:6px}
.brand .dot{width:26px;height:30px;background:var(--accent);
  clip-path:polygon(50% 0,100% 25%,100% 75%,50% 100%,0 75%,0 25%)}
.brand .sp{margin-left:auto}
.lobby-grid{display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-top:20px}
@media(max-width:760px){.lobby-grid{grid-template-columns:1fr}}
.lobby-grid .card{margin-top:0}
#qrBox{display:flex; gap:16px; align-items:center; margin-top:14px; flex-wrap:wrap}
#qrBox canvas{background:#fff; padding:8px; border-radius:10px}
.roomcode{font-family:ui-monospace,Consolas,monospace; font-size:20px; letter-spacing:2px;
  color:var(--accent); word-break:break-all}
.joinurl{font-family:ui-monospace,Consolas,monospace; font-size:11px; color:var(--muted);
  word-break:break-all; margin-top:8px}
#copyBtn{margin-top:9px}
#fileWarn{margin-top:10px}
.plist{list-style:none; margin:10px 0 0; padding:0; display:flex; flex-direction:column; gap:7px}
.plist li{display:flex; align-items:center; gap:9px; background:var(--panel-2);
  padding:9px 11px; border-radius:9px; font-size:14px}
.badge{margin-left:auto; font-size:11px; color:var(--muted); text-transform:uppercase; letter-spacing:.7px}
.plist .kickmini{margin-left:auto}
#status{margin-top:14px; font-size:13px; color:var(--muted); min-height:18px}
.optrow{display:flex; align-items:center; gap:14px; margin-bottom:10px; flex-wrap:wrap}
.optrow > span:first-child{font-size:12.5px; color:var(--muted);
  text-transform:uppercase; letter-spacing:.8px; min-width:110px}
.seg{display:flex; border:1px solid var(--line); border-radius:10px; overflow:hidden; width:fit-content}
.seg button{background:var(--panel-2); color:var(--muted); border:0; border-right:1px solid var(--line);
  padding:9px 15px; font-size:13.5px; font-weight:700; cursor:pointer}
.seg button:last-child{border-right:0}
.seg button.on{background:var(--accent); color:#2a1d02}
.mapinfo{font-size:12.5px; color:var(--muted); margin-top:6px; line-height:1.5}
/* multi-select chips for lobby options */
.chipset{display:flex; gap:6px; flex-wrap:wrap}
.chipset button{background:var(--panel-2); color:var(--muted); border:1px solid var(--line);
  border-radius:9px; padding:8px 12px; font-size:12.5px; font-weight:700; cursor:pointer;
  display:inline-flex; align-items:center; gap:5px}
.chipset button.on{background:var(--ok); color:#05230f; border-color:#237a41}

/* ============================================================
   GAME SHELL
   The board fills the stage; the action bar floats as an island
   over the bottom of it rather than as a full-width strip.
   ============================================================ */
#game{
  display:grid;
  grid-template-columns:1fr 360px;
  grid-template-areas:"board side";
  /* 100vh on iOS is the tallest the viewport ever gets, so the bottom of the
     page hides behind Safari's toolbar. dvh tracks the visible area. */
  height:100vh; height:100dvh; position:relative;
}
#boardWrap{grid-area:board; position:relative; overflow:hidden;
  /* --table-bg is the cosmetic table theme (common/support.js) */
  background:var(--table-bg, radial-gradient(circle at 50% 40%,var(--sea1),var(--sea2)));
  display:flex; align-items:center; justify-content:center; min-height:50vh}
#boardSlot{width:100%; height:100%; display:flex; align-items:center; justify-content:center;
  padding-bottom:92px}
#side{grid-area:side; background:var(--panel); border-left:1px solid var(--line);
  display:flex; flex-direction:column; overflow-y:auto}
.sidehead{display:flex; align-items:center; gap:10px; flex-wrap:wrap}
#headSlot{display:flex; align-items:center; gap:8px}

/* ---- the floating island ---- */
/* One row: turn marker, then the build cards. Nothing wraps on desktop. */
/* The prompt and the dice ride together above the board. */
#topbar{position:absolute; left:0; right:360px; top:14px; z-index:6;
  display:flex; align-items:center; justify-content:center; gap:14px; pointer-events:none}
#diceSlot{pointer-events:auto}

/* Sits OUTSIDE #boardWrap on purpose: a controller hides the board but must
   keep its controls. */
#islandBar{
  position:absolute; left:0; right:360px; bottom:16px; margin:0 auto; width:fit-content;
  display:flex; align-items:center; gap:12px; justify-content:center;
  max-width:calc(100% - 388px);
  background:var(--glass); -webkit-backdrop-filter:blur(9px); backdrop-filter:blur(9px);
  border:1px solid var(--line); border-radius:18px;
  padding:9px 14px; box-shadow:0 12px 34px var(--shadow);
  z-index:4; overflow-x:auto;
}
.bb-turn{display:flex; align-items:center; gap:8px; font-weight:800; font-size:14px}
.bb-sep{width:1px; align-self:stretch; background:var(--line)}
#barSlot{display:flex; align-items:center; gap:12px; flex-wrap:wrap}
/* The prompt floats over the top of the board, clear of the pieces. */
#hint{pointer-events:none;
  background:var(--glass); border:1px solid var(--accent);
  color:var(--accent); font-weight:800; font-size:13px; line-height:1.35;
  padding:8px 16px; border-radius:999px; box-shadow:0 6px 20px var(--shadow);
  max-width:min(560px,86vw); text-align:center; pointer-events:none}
.timer{font-family:ui-monospace,Consolas,monospace; font-weight:800; font-size:14px;
  background:var(--panel-2); padding:2px 8px; border-radius:7px}
.timer.low{background:var(--bad); color:#fff}

@media(max-width:900px){
  /* Every piece of furniture gets its own row. Left to auto-placement the
     dice landed on top of the build bar. */
  #game{grid-template-columns:1fr;
    grid-template-areas:"top" "board" "bar" "side";
    grid-template-rows:auto auto auto 1fr; height:auto}
  #topbar{grid-area:top}
  #boardWrap{grid-area:board; max-height:58vh}
  #islandBar{grid-area:bar}
  #side{grid-area:side}
  #boardSlot{padding-bottom:0; max-height:58vh}
  #boardSlot > *{max-height:58vh}
  #islandBar{position:static; max-width:none; width:100%;
    border-radius:0; border-left:0; border-right:0; justify-content:flex-start}
  #topbar{position:static; right:auto; flex-wrap:wrap; padding:10px 12px 0;
    justify-content:flex-start}
  #hint{max-width:none}
}

/* ============================================================
   VIEW MODES
   ============================================================ */
/* shared screen: this device IS the board — no sidebar, no controls */
body.view-screen #side{display:none}
body.view-screen #game{grid-template-columns:1fr; grid-template-areas:"board"}
body.view-screen #barSlot,
body.view-screen .bb-sep{display:none}
body.view-screen .bb-turn{font-size:21px}
body.view-screen .bb-hint{font-size:17px; max-width:none}
body.view-screen #boardSlot{padding-bottom:150px; padding-top:78px}
body.view-screen #topbar{right:0; top:auto; bottom:92px}
body.view-screen #hint{font-size:18px; padding:12px 26px}
body.view-screen #islandBar{right:0;
  bottom:calc(16px + env(safe-area-inset-bottom))}
body.view-screen #screenStrip{
  display:flex !important; position:absolute; left:0; right:0; top:0;
  gap:10px; padding:12px 16px; justify-content:center; flex-wrap:wrap; z-index:3}
body.view-screen .strip{display:flex; align-items:center; gap:8px; font-size:15px; font-weight:700;
  background:var(--glass); border:1px solid var(--line); border-radius:12px; padding:8px 13px}
body.view-screen .strip.active{border-color:var(--accent); box-shadow:0 0 0 2px rgba(245,166,35,.35)}
body.view-screen .strip.gone{opacity:.4}
body.view-screen .strip .s{color:var(--muted); font-size:12.5px; font-weight:600}
body.view-screen #toasts{top:78px}
body.view-screen .toast{font-size:17px; padding:13px 20px; max-width:min(620px,86vw)}

/* controller: a player's own phone while a shared screen is running */
body.view-controller #game{grid-template-columns:1fr; grid-template-areas:"top" "side";
  grid-template-rows:auto 1fr; height:100vh; height:100dvh}
body.view-controller #topbar{grid-area:top}
body.view-controller #side{grid-area:side}
/* Controller: the board appears only when the game says this player has
   to point at it (placing, or moving the robber). */
body.view-controller #boardWrap{display:none}
body.view-controller #topbar{right:0; position:static; padding:10px 12px 0; justify-content:flex-start}
body.view-controller.show-board #boardWrap{display:flex; height:52vh; margin-bottom:6px}
body.view-controller.show-board #game{grid-template-areas:"top" "board" "side";
  grid-template-rows:auto auto 1fr}
body.view-controller.show-board #boardSlot{padding-bottom:0}
body.view-controller #hint{position:static}
/* Room for the pinned bar, plus the home indicator underneath it. */
body.view-controller #side{border-left:0;
  padding-bottom:calc(178px + env(safe-area-inset-bottom))}
body.view-controller #islandBar{position:fixed; left:0; right:0; bottom:0;
  width:auto; max-width:none; border-radius:0; border-left:0; border-right:0;
  padding-bottom:calc(9px + env(safe-area-inset-bottom));
  padding-left:calc(14px + env(safe-area-inset-left));
  padding-right:calc(14px + env(safe-area-inset-right))}

/* ============================================================
   PANELS
   ============================================================ */
.sec{padding:13px 15px; border-bottom:1px solid var(--line)}
.sec.scroll{overflow-y:auto; flex:1; min-height:110px}

/* players panel — bigger type so the stats are readable at a glance */
.pcard{display:flex; align-items:center; gap:9px; padding:10px 11px; border-radius:10px;
  background:var(--panel-2); margin-bottom:7px; font-size:14.5px; font-weight:700}
.pcard.active{outline:2px solid var(--accent)}
.pcard.gone{opacity:.45}
.pcard .pname{white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:40%}
.pcard .stats{margin-left:auto; color:var(--ink); font-size:13px; text-align:right;
  line-height:1.6; font-weight:700}
.kickmini{padding:4px 8px; font-size:11px; margin-left:6px}
.tag{display:inline-block; font-size:10px; font-weight:800; padding:2px 6px; border-radius:5px;
  background:var(--accent); color:#2a1d02; letter-spacing:.4px}
.tag.army{background:var(--dev); color:#1c0c2e}
#logPanel{font-size:12.5px; line-height:1.55; color:var(--muted)}
#logPanel div{padding:3px 0; border-bottom:1px solid rgba(255,255,255,.05)}
#logPanel b{color:var(--ink)}
#banner{position:absolute; inset:auto 0 0 0; background:rgba(245,166,35,.95); color:#2a1d02;
  padding:10px 14px; font-weight:800; text-align:center; font-size:14px; z-index:5}
#voteBox{background:var(--warn-bg); border:1px solid var(--warn-edge); border-radius:10px; padding:11px; margin-top:10px}
.votetitle{font-weight:800; font-size:13.5px; margin-bottom:4px}

/* ---------- toasts ---------- */
#toasts{position:absolute; top:14px; left:50%; transform:translateX(-50%);
  display:flex; flex-direction:column; gap:8px; align-items:center; pointer-events:none; z-index:6}
.toast{background:var(--glass); border:1px solid var(--line); border-left:4px solid var(--muted);
  color:var(--ink); padding:10px 16px; border-radius:10px; font-size:13.5px; font-weight:700;
  box-shadow:0 6px 20px rgba(0,0,0,.5); animation:toastIn .25s ease-out;
  max-width:min(430px,80vw); display:flex; align-items:center; gap:8px}
.toast b{color:#fff}
.toast.gain{border-left-color:var(--ok)}
.toast.steal{border-left-color:var(--bad)}
.toast.devc{border-left-color:var(--dev)}
.toast.bonus,.toast.win{border-left-color:var(--accent)}
.toast.trade{border-left-color:#3d8ce0}
.toast.fade{opacity:0; transition:opacity .4s}
@keyframes toastIn{from{opacity:0; transform:translateY(-10px)}to{opacity:1; transform:none}}

/* ---------- stepper modal ---------- */
/* modal and sheet sit above the chat/voice dock (z 60), which would otherwise cover their buttons */
#modal{position:fixed; inset:0; background:rgba(6,12,18,.78); display:flex; align-items:center;
  justify-content:center; z-index:66; padding:18px}
.modalbox{background:var(--panel); border:1px solid var(--line); border-radius:14px; padding:20px;
  width:min(430px,100%); box-shadow:0 20px 60px rgba(0,0,0,.6)}
.modalbox h2{margin-bottom:4px}
.mrow{display:flex; align-items:center; gap:10px; background:var(--panel-2); border-radius:9px;
  padding:8px 11px; margin-top:7px; font-size:13.5px; font-weight:700}
.mrow .mlabel{text-transform:capitalize}
.mrow .have{margin-left:auto; color:var(--muted); font-size:11.5px; font-weight:600}
.mcount{font-size:16px; font-weight:800; min-width:18px; text-align:center}
.stepper{display:flex; align-items:center; gap:6px; font-size:12px; color:var(--muted)}
.stepper button{width:26px;height:26px;border-radius:7px;border:1px solid #4d6b8e;
  background:var(--panel-3); color:var(--ink); font-weight:800; cursor:pointer; font-size:14px; line-height:1}
.stepper .v{min-width:16px; text-align:center; font-weight:800; color:var(--ink)}
.actions{display:grid; grid-template-columns:1fr 1fr; gap:8px; margin-top:10px}
.actions .wide{grid-column:1/-1}

/* ---------- info sheet ---------- */
#sheet{position:fixed; inset:0; background:rgba(6,12,18,.8); display:flex; align-items:center;
  justify-content:center; z-index:70; padding:18px}
.sheetbox{background:var(--panel); border:1px solid var(--line); border-radius:16px;
  width:min(760px,100%); max-height:88vh; display:flex; flex-direction:column;
  box-shadow:0 24px 70px rgba(0,0,0,.65)}
.sheethead{display:flex; align-items:center; gap:12px; padding:16px 18px 10px}
.sheethead h2{margin:0; flex:1}
.sheettabs{display:flex; gap:6px; padding:0 18px 12px; border-bottom:1px solid var(--line); flex-wrap:wrap}
.sheettabs button{background:var(--panel-2); color:var(--muted); border:1px solid var(--line);
  border-radius:9px; padding:8px 14px; font-size:13px; font-weight:700; cursor:pointer}
.sheettabs button.on{background:var(--accent); color:#2a1d02; border-color:#b87a06}
.sheetbody{padding:16px 18px; overflow-y:auto; font-size:13.5px; line-height:1.6; color:var(--ink)}
.sheetbody h3{margin:16px 0 8px; color:var(--accent)}
.sheetbody h3:first-child{margin-top:0}
.sheetbody p{margin:0 0 10px; color:var(--muted)}
.sheetbody ul{margin:0 0 12px; padding-left:20px; color:var(--muted)}
.sheetbody li{margin-bottom:5px}
.sheetbody code{background:var(--panel-2); padding:1px 5px; border-radius:4px; font-size:12px}
.sheetfoot{padding:12px 18px 16px; border-top:1px solid var(--line); display:flex;
  justify-content:flex-end; gap:8px}
.sheetfoot:empty{display:none; padding:0; border:0}
.statgrid{width:100%; border-collapse:collapse; font-size:13px}
.statgrid td{padding:6px 8px; border-bottom:1px solid rgba(255,255,255,.06)}
.statgrid td:first-child{color:var(--muted)}
.statgrid td:last-child{text-align:right; font-weight:800}
.statgrid th{padding:6px 8px; text-align:left; color:var(--accent); font-size:11.5px;
  text-transform:uppercase; letter-spacing:.8px; border-bottom:1px solid var(--line)}
.fulllog{max-height:52vh; overflow-y:auto; font-size:12.5px; line-height:1.6; color:var(--muted)}
.fulllog div{padding:4px 0; border-bottom:1px solid rgba(255,255,255,.05)}
.fulllog b{color:var(--ink)}

/* ============================================================
   HUB (index.html)
   ============================================================ */
#hub{max-width:980px; margin:0 auto; padding:32px 18px 60px}
.hubgrid{display:grid; grid-template-columns:repeat(auto-fill,minmax(260px,1fr)); gap:16px; margin-top:22px}
.gamecard{display:block; text-decoration:none; color:inherit; background:var(--panel-2);
  border:1px solid var(--line); border-radius:var(--radius); padding:16px; transition:.15s;
  text-align:left; font-family:inherit; cursor:pointer; width:100%}
.gamecard:hover:not(:disabled){border-color:var(--accent); transform:translateY(-2px)}
.gamecard.on{border-color:var(--accent); box-shadow:0 0 0 2px rgba(245,166,35,.3)}
.gamecard:disabled{opacity:.55; cursor:not-allowed}
.gamecard h2{color:var(--ink)}
.gamecard h2{font-size:18px; margin-bottom:6px}
.gamecard .meta{font-size:11.5px; color:var(--muted); text-transform:uppercase; letter-spacing:.8px; margin-top:10px}


/* ---------- streamer privacy: hide the room id / link / QR ---------- */
#qrBox.blurred canvas,
#qrBox.blurred .roomcode,
#qrBox.blurred .joinurl{filter:blur(9px); user-select:none}
#qrBox.blurred .qrmeta::after{content:attr(data-hidden)}

/* ---------- per-option info bubbles ---------- */
.infodot{display:inline-flex; align-items:center; justify-content:center;
  width:16px; height:16px; margin-left:6px; border-radius:50%;
  background:var(--panel-3); color:var(--ink); border:1px solid var(--line);
  font-size:10px; font-weight:800; font-style:normal; cursor:help; line-height:1; padding:0}
.infodot:hover{background:var(--accent); color:#2a1d02; border-color:var(--accent)}
#tip{position:fixed; z-index:200; max-width:290px; background:var(--panel);
  border:1px solid var(--accent); border-radius:10px; padding:10px 13px;
  font-size:12.5px; line-height:1.5; color:var(--ink); box-shadow:0 10px 30px var(--shadow)}


/* ---------- lobby: keep the QR buttons on one tidy line ---------- */
.qrmeta{min-width:0}
.qrmeta .row{gap:8px; flex-wrap:wrap; align-items:stretch}
.qrmeta .row .btn{margin:0; flex:0 0 auto}
#copyBtn{margin-top:0}

/* ---------- pick your colour ---------- */
.colorpick{display:inline-flex; gap:4px; margin-left:8px}
.cdot{width:17px; height:17px; border-radius:50%; border:2px solid transparent;
  cursor:pointer; padding:0; box-shadow:0 0 0 1px rgba(0,0,0,.35) inset}
.cdot.on{border-color:var(--ink); transform:scale(1.15)}
.cdot.taken{opacity:.28; cursor:not-allowed}

/* ---------- custom seconds box next to a segmented control ---------- */
.secbox{max-width:88px; padding:8px 10px !important; text-align:center}

/* ================= setup: option cards ================= */
/* Each setting reads as a card with its explanation underneath, so a table
   can scan the whole rule set at once instead of hunting through tooltips. */
.optgroup{margin:18px 0 8px; font-size:11.5px; font-weight:800; letter-spacing:1.4px;
  text-transform:uppercase; color:var(--muted); border-top:1px solid var(--line); padding-top:12px}
.optgroup:first-child{border-top:0; margin-top:4px}
.optgrid{display:grid; gap:12px; grid-template-columns:repeat(auto-fit, minmax(215px, 1fr))}
.optcard{background:var(--panel-2); border:1px solid var(--line); border-radius:12px;
  padding:11px 12px; display:flex; flex-direction:column; gap:7px}
.optcard .optlabel{font-size:12px; font-weight:700; letter-spacing:.5px;
  text-transform:uppercase; color:var(--muted)}
.optcard select, .optcard .optnum{width:100%}
.optnum{background:var(--bg); border:1px solid var(--line); color:var(--ink);
  padding:8px 10px; border-radius:9px; font:inherit; font-weight:700}
.opthelp{margin:0; font-size:11.5px; line-height:1.45; color:var(--muted); opacity:.85}
.opthelp.sub{opacity:.7; border-left:2px solid var(--line); padding-left:7px}
.optcard.toggle{gap:5px}
.optcard.toggle.on{border-color:var(--accent)}
.optcheck{display:flex; align-items:center; gap:9px; cursor:pointer}
.optcheck input{width:17px; height:17px; accent-color:var(--accent); cursor:pointer}
.optcard .seg{width:100%}
.optcard .seg button{flex:1}

/* live board preview + reroll */
.previewbox{display:flex; flex-direction:column; align-items:center; gap:10px;
  background:var(--panel-2); border:1px solid var(--line); border-radius:14px;
  padding:14px; margin-bottom:14px}
#optionPreview svg{max-width:100%; height:auto; display:block}

/* ================= chat dock ================= */
#chatDock{position:fixed; right:14px; bottom:14px; z-index:60; width:min(320px, calc(100vw - 28px));
  display:flex; flex-direction:column; align-items:flex-end; gap:8px; pointer-events:none}
#chatDock > *{pointer-events:auto}
#chatToggle{background:var(--panel-3); color:var(--ink); border:1px solid var(--line);
  border-radius:999px; padding:9px 16px; font:inherit; font-weight:800; font-size:12px;
  letter-spacing:.8px; text-transform:uppercase; cursor:pointer;
  box-shadow:0 6px 18px rgba(0,0,0,.3); display:flex; align-items:center; gap:8px}
#chatToggle:hover{border-color:var(--accent)}
#chatUnread{background:var(--bad); color:#fff; font-style:normal; font-size:11px;
  min-width:18px; height:18px; border-radius:9px; display:grid; place-items:center; padding:0 5px}
#chatPanel{width:100%; background:var(--panel); border:1px solid var(--line);
  border-radius:14px; padding:10px; display:flex; flex-direction:column; gap:8px;
  box-shadow:0 10px 30px rgba(0,0,0,.35)}
#chatLog{max-height:210px; overflow-y:auto; display:flex; flex-direction:column; gap:5px}
.cline{display:flex; align-items:baseline; gap:6px; font-size:12.5px; line-height:1.4}
.cline .swatch{width:9px; height:9px; border-radius:50%; flex:none; align-self:center}
.cline b{color:var(--muted); font-size:11.5px; flex:none}
.cline span:last-child{word-break:break-word}
.cline.me span:last-child{color:var(--accent)}
#chatQuick{display:flex; flex-wrap:wrap; gap:5px}
.qchip{background:var(--panel-2); border:1px solid var(--line); color:var(--muted);
  border-radius:999px; padding:4px 10px; font:inherit; font-size:11.5px; cursor:pointer}
.qchip:hover{border-color:var(--accent); color:var(--ink)}
#chatEntry{gap:6px}
#chatInput{flex:1; min-width:0}

/* a seat being held open for someone who dropped */
.badge.away{color:var(--accent)}
.pcard.away, .strip.away{opacity:.72}

/* In a game the dock has to dodge the furniture: the side panel on a wide
   screen, and the island build bar on a narrow one. */
/* lifted clear of the island bar — with the voice pill beside chat it reached the bar's buttons */
#game:not(.hidden) ~ #chatDock{bottom:88px; right:376px}
body.view-screen #game:not(.hidden) ~ #chatDock{right:14px; bottom:104px}
/* a controller is all side panel, with the build bar pinned to the bottom */
body.view-controller #game:not(.hidden) ~ #chatDock{right:14px;
  bottom:calc(84px + env(safe-area-inset-bottom))}
/* On a phone in full view nothing is pinned to the bottom of the screen,
   so the dock can sit in the corner — only a controller needs the lift. */
@media (max-width:900px){
  #game:not(.hidden) ~ #chatDock{right:14px; bottom:14px}
  body.view-controller #game:not(.hidden) ~ #chatDock{
    bottom:calc(84px + env(safe-area-inset-bottom))}
}

/* a spectator in the lobby roster */
.plist li.spec{opacity:.78}
.swatch.ghost{background:transparent; border:1px dashed var(--line)}

/* ============================================================
   SMALL-SCREEN / iOS HARDENING
   ============================================================ */
/* In the two full-screen play modes nothing but the side panel should
   scroll. Letting the document scroll is what makes iOS Safari's toolbar
   slide in and out and drag `position:fixed` furniture with it — which is
   why the build bar would not stay at the bottom of the screen. */
body.view-controller, body.view-screen{position:fixed; inset:0; overflow:hidden}
body.view-controller #side{overflow-y:auto; -webkit-overflow-scrolling:touch}

/* The one-row build bar scrolls sideways when it must. Fade the trailing
   edge so it is obvious there is more, and hide the scrollbar itself. */
#islandBar{scrollbar-width:none; overscroll-behavior-x:contain;
  scroll-snap-type:x proximity}
#islandBar::-webkit-scrollbar{display:none}
#islandBar > *{scroll-snap-align:start}

/* A soft fade at the trailing edge, so a bar that continues off-screen
   looks like it continues rather than like it ends. */
#islandBar::after{content:""; position:sticky; right:0; flex:0 0 18px; align-self:stretch;
  margin-left:-18px; pointer-events:none;
  background:linear-gradient(to right, transparent, var(--glass))}

/* On a phone the chat pill shrinks to an icon so it covers as little of the
   panel as possible; the label is only worth its width on a big screen. */
@media (max-width:560px){
  #chatToggle{position:relative; padding:0; width:46px; height:46px; border-radius:50%;
    justify-content:center; gap:0; font-size:19px}
  #chatToggle > span{display:none}
  #chatToggle::before{content:"\1F4AC "}
  #chatUnread{position:absolute; top:-3px; right:-3px}
  #chatDock{align-items:flex-end}
}
/* never let the seat label stack the build bar three lines high */
.bb-turn{white-space:nowrap}

/* ============================================================
   BOTS, ROOM SCOREBOARD, THIS-DEVICE SETTINGS
   ============================================================ */
.plist li.botrow{background:linear-gradient(90deg, rgba(169,124,224,.16), var(--panel-2) 60%)}
.botlvl{padding:5px 8px; font-size:12.5px; margin-left:6px}
.boardtbl td:last-child{text-align:center}
.boardtbl tr.me td{background:rgba(245,166,35,.1)}
.boardtbl .bygame{text-align:left !important; font-weight:600 !important}
.boardtbl .bygame .pill{font-size:10px; padding:2px 7px}
.recent{display:flex; flex-wrap:wrap; gap:6px}
.recent .pill{text-transform:none; letter-spacing:.2px; font-size:11.5px}
.devicebar{display:flex; flex-wrap:wrap; align-items:center; gap:10px 14px; margin-top:12px;
  font-size:13px; color:var(--muted)}
.devicebar .devlabel{font-size:11.5px; font-weight:800; letter-spacing:1px; text-transform:uppercase}
.devicebar input[type=range]{width:110px; accent-color:var(--accent)}
.seg.sm button{padding:6px 11px; font-size:12px}

/* ============================================================
   FX — celebrations and sting, all short-lived overlay nodes
   ============================================================ */
#fxLayer{position:fixed; inset:0; pointer-events:none; z-index:80; overflow:hidden}
.fx-burst{position:absolute; left:50%; top:38%; transform:translate(-50%,-50%);
  display:flex; flex-direction:column; align-items:center; gap:4px; text-align:center;
  animation:fxBurst 1.8s cubic-bezier(.2,1.4,.4,1) forwards; white-space:nowrap}
.fx-burst b{font-size:clamp(34px, 8vw, 72px); font-weight:900; letter-spacing:1px; line-height:1.05;
  color:#fff; -webkit-text-stroke:2px rgba(0,0,0,.35);
  text-shadow:0 4px 0 rgba(0,0,0,.25), 0 0 32px var(--fxglow, rgba(245,166,35,.8))}
.fx-burst i{font-style:normal; font-size:clamp(14px, 3vw, 20px); font-weight:800; color:#fff;
  background:rgba(0,0,0,.45); padding:4px 12px; border-radius:999px}
.fx-burst.good{--fxglow:rgba(67,185,107,.9)}
.fx-burst.bad{--fxglow:rgba(224,83,61,.95)}
.fx-burst.bad b{color:#ffd9d2}
.fx-burst.epic{--fxglow:rgba(245,166,35,1)}
.fx-burst.epic b{background:linear-gradient(180deg,#fff6d8,#f5a623); -webkit-background-clip:text; background-clip:text; color:transparent}
.fx-burst.relief{--fxglow:rgba(61,140,224,.9)}
.fx-burst.info{--fxglow:rgba(255,255,255,.55)}
.fx-burst.info b{font-size:clamp(26px, 6vw, 48px)}
.fx-burst.calm{animation:fxFade 1.6s ease forwards}
@keyframes fxBurst{
  0%{opacity:0; transform:translate(-50%,-50%) scale(.3) rotate(-6deg)}
  18%{opacity:1; transform:translate(-50%,-50%) scale(1.12) rotate(2deg)}
  30%{transform:translate(-50%,-50%) scale(1) rotate(0)}
  78%{opacity:1; transform:translate(-50%,-56%) scale(1)}
  100%{opacity:0; transform:translate(-50%,-70%) scale(.96)}}
@keyframes fxFade{0%{opacity:0} 15%{opacity:1} 80%{opacity:1} 100%{opacity:0}}
.fx-conf{position:absolute; top:-14px; width:9px; height:14px; border-radius:2px;
  animation-name:fxFall; animation-timing-function:cubic-bezier(.3,.5,.6,1); animation-fill-mode:forwards}
@keyframes fxFall{
  0%{transform:translate(0,0) rotate(0); opacity:1}
  85%{opacity:1}
  100%{transform:translate(var(--dx), 104vh) rotate(var(--rot)); opacity:0}}
.fx-flash{position:absolute; inset:0; animation:fxFlash .9s ease-out forwards}
.fx-flash.good{box-shadow:inset 0 0 90px 22px rgba(67,185,107,.55)}
.fx-flash.bad{box-shadow:inset 0 0 110px 30px rgba(224,83,61,.6)}
.fx-flash.gold{box-shadow:inset 0 0 110px 30px rgba(245,166,35,.6)}
.fx-flash.calm{box-shadow:inset 0 0 90px 20px rgba(120,140,160,.35)}
@keyframes fxFlash{0%{opacity:0} 20%{opacity:1} 100%{opacity:0}}
.fx-float{position:absolute; transform:translate(-50%,-50%); font-weight:900; font-size:18px;
  color:#fff; text-shadow:0 2px 6px rgba(0,0,0,.6); white-space:nowrap;
  animation:fxRise 1.4s ease-out forwards; display:flex; align-items:center; gap:4px}
.fx-float.good{color:#bff3cf} .fx-float.bad{color:#ffc4b8} .fx-float.gold{color:#ffe3a3}
@keyframes fxRise{0%{opacity:0; transform:translate(-50%,-30%) scale(.7)}
  20%{opacity:1; transform:translate(-50%,-60%) scale(1.1)}
  100%{opacity:0; transform:translate(-50%,-190%) scale(1)}}
.fx-pulse{animation:fxPulse .85s ease-out}
@keyframes fxPulse{0%{box-shadow:0 0 0 0 rgba(245,166,35,.85)} 100%{box-shadow:0 0 0 18px rgba(245,166,35,0)}}
/* The shake lives in fx.js now: it is driven frame by frame so its power can
   scale with what just happened, instead of being one fixed keyframe. */

/* ============================================================
   VOICE — a second pill beside the chat one, and its panel
   ============================================================ */
.dockbtns{display:flex; gap:8px; justify-content:flex-end; align-items:center}
#voiceToggle{background:var(--panel-3); color:var(--ink); border:1px solid var(--line);
  border-radius:999px; padding:9px 14px; font:inherit; font-weight:800; font-size:12px;
  letter-spacing:.8px; text-transform:uppercase; cursor:pointer; box-shadow:0 6px 18px rgba(0,0,0,.3);
  display:flex; align-items:center; gap:7px}
#voiceToggle:hover{border-color:var(--accent)}
#voiceToggle.live{border-color:var(--ok); box-shadow:0 0 0 2px rgba(67,185,107,.4), 0 6px 18px rgba(0,0,0,.3)}
.vccount{background:var(--ok); color:#05230f; font-style:normal; font-size:11px; min-width:18px; height:18px;
  border-radius:9px; display:grid; place-items:center; padding:0 5px}
#voicePanel{width:100%; background:var(--panel); border:1px solid var(--line); border-radius:14px; padding:12px;
  display:flex; flex-direction:column; gap:9px; box-shadow:0 10px 30px rgba(0,0,0,.35)}
#voicePanel p{margin:0}
#voicePanel .wide{width:100%}
.vclist{display:flex; flex-direction:column; gap:6px; max-height:230px; overflow-y:auto}
.vcrow{display:flex; align-items:center; gap:7px; font-size:12.5px; flex-wrap:wrap; min-height:26px}
.vcdot{width:10px; height:10px; border-radius:50%; background:var(--line); flex:none; transition:background .1s, box-shadow .1s}
.vcdot.talking{background:var(--ok); box-shadow:0 0 0 3px rgba(67,185,107,.35)}
.vcwait{font-size:11px}
.vcctl{margin-left:auto; display:flex; gap:5px; align-items:center}
.vcctl input[type=range]{width:70px; accent-color:var(--accent)}
.vcctl .btn{padding:3px 7px}
.vcbtns{gap:8px}
.vctalk{user-select:none; -webkit-user-select:none; touch-action:none; -webkit-touch-callout:none; padding:16px}
.vctalk.down{background:linear-gradient(#4ec97a,#2f9d55); color:#05230f; border-color:#237a41}
.vcbadge{font-size:11px; margin-left:5px; border-radius:6px; padding:1px 3px; transition:box-shadow .1s, background .1s}
.vcbadge.talking{background:rgba(67,185,107,.35); box-shadow:0 0 0 2px var(--ok)}
.vcbadge.mu{opacity:.7}
.flair{font-size:14px; line-height:1}
.supstar{font-size:11px}
@media (max-width:560px){
  #voiceToggle{width:46px; height:46px; padding:0; border-radius:50%; justify-content:center; font-size:19px; position:relative}
  #voiceToggle .vclabel{display:none}
  #voiceToggle .vccount{position:absolute; top:-3px; right:-3px}
}

/* ============================================================
   SUPPORT & COSMETICS
   ============================================================ */
/* The Support button is the one warm thing in the header: bubble-gum pink,
   a heart that beats now and then, a sheen when you point at it. Noticed,
   never nagging — the beat is slow and stops with reduced motion. */
.btn.supbtn{background:linear-gradient(#ff9bc9,#f25b9f); color:#3d0722; border-color:#c63e7e;
  text-shadow:0 1px 0 rgba(255,255,255,.28); position:relative; overflow:hidden;
  box-shadow:0 1px 0 rgba(255,255,255,.35) inset, 0 2px 8px rgba(242,91,159,.35)}
.btn.supbtn:hover:not(:disabled){background:linear-gradient(#ffb0d4,#f86eab); border-color:#a82e67;
  box-shadow:0 1px 0 rgba(255,255,255,.4) inset, 0 4px 14px rgba(242,91,159,.5)}
.btn.supbtn::after{content:""; position:absolute; inset:0; pointer-events:none; transform:translateX(-130%);
  background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.5) 50%,transparent 62%)}
.btn.supbtn:hover:not(:disabled)::after{transition:transform .6s cubic-bezier(.16,.9,.3,1); transform:translateX(130%)}
.supheart{display:inline-block; color:#fff; transform-origin:50% 62%;
  filter:drop-shadow(0 1px 0 rgba(120,10,60,.5)); animation:supBeat 3.2s ease-in-out 1.5s infinite}
@keyframes supBeat{0%,72%,100%{transform:scale(1)} 77%{transform:scale(1.3)} 82%{transform:scale(.94)} 87%{transform:scale(1.16)} 93%{transform:scale(1)}}
html[data-motion="reduced"] .supheart{animation:none}
.btn.supbtn{white-space:nowrap; flex-shrink:0}
@media (max-width:480px){
  .supbtn .suplabel{display:none}          /* on a phone the heart says it */
  .btn.supbtn{padding:7px 10px; font-size:14px}
}

/* the three claim steps, in the Support tab */
.supclaim{margin:2px 0 16px; padding:12px 14px 10px; border:1px solid rgba(242,91,159,.5);
  border-radius:13px 11px 14px 12px; background:linear-gradient(160deg,rgba(255,111,174,.13),transparent 58%), var(--panel-2)}
.sheetbody .supclaim h3{margin-top:0; color:#f25b9f}
.supsteps{margin:4px 0 12px; padding-left:22px}
.supsteps li{margin:7px 0; line-height:1.45}
.supsteps li::marker{font-weight:800; color:#f25b9f}
.suptagrow{display:inline-flex; gap:8px; align-items:center; flex-wrap:wrap; margin:2px 0 0 4px; vertical-align:middle}
.suptag{font-family:ui-monospace,Consolas,monospace; font-size:14.5px; font-weight:800; letter-spacing:1.2px; color:var(--ink);
  background:var(--panel); border:1.5px dashed #f25b9f; border-radius:8px 7px 9px 7px; padding:4px 9px; user-select:all}
.btn.copied, .btn.copied:hover:not(:disabled){border-color:var(--ok); color:var(--ok)}
.supclaimbtn.busy:disabled{background:var(--panel-3); color:var(--ink); cursor:progress}
.supclaim .opthelp{margin-top:10px}
#supMine{flex:1; min-width:200px; font-family:ui-monospace,Consolas,monospace; font-size:12px}
.roombadge{display:inline-block; margin:-2px 0 6px; font-size:12px; font-weight:800; letter-spacing:.4px;
  background:var(--gold-bg); color:var(--gold-ink); border:1px solid var(--gold-edge); border-radius:999px; padding:4px 11px}
.supgrid{display:grid; grid-template-columns:repeat(auto-fill,minmax(118px,1fr)); gap:8px; margin-bottom:6px}
.supgrid.flair{grid-template-columns:repeat(auto-fill,minmax(52px,1fr))}
.suptile{position:relative; display:flex; flex-direction:column; gap:6px; align-items:center; background:var(--panel-2);
  border:2px solid var(--line); border-radius:12px; padding:8px; cursor:pointer; color:var(--ink); font:inherit;
  font-size:12px; font-weight:700; text-align:center}
.suptile:hover{border-color:var(--muted)}
.suptile.on{border-color:var(--accent); box-shadow:0 0 0 2px rgba(245,166,35,.3)}
.suptile.locked{opacity:.55}
.supsw{width:100%; height:44px; border-radius:8px; border:1px solid rgba(0,0,0,.3)}
.supemoji{font-size:24px; line-height:1.2; min-height:29px}
.suplock{position:absolute; top:4px; right:6px; font-style:normal; font-size:12px}
.supstatus{background:var(--panel-2); border:1px solid var(--line); border-radius:10px; padding:9px 12px; margin-bottom:12px; font-weight:700}
.supstatus.on{background:var(--gold-bg); border-color:var(--gold-edge); color:var(--gold-ink)}
.supstatus.room{background:var(--ok-bg); border-color:var(--ok-edge)}
.supnote{margin-top:10px !important; font-weight:700; color:var(--ink) !important}
.supdev{margin-top:18px; padding-top:12px; border-top:1px dashed var(--line)}
#supCode{flex:1; min-width:200px; font-family:ui-monospace,Consolas,monospace; font-size:12px}
.sheetbody a.btn{text-decoration:none; display:inline-block}

/* ============================================================
   MOTION + MATERIAL — the polish pass.

   One set of easings, so every moving thing in the app moves the same
   way; a paper grain and a vignette, so the table reads as a surface
   rather than a div; and slightly-off geometry (a degree of tilt, a
   corner radius that is not quite symmetric) so nothing looks stamped
   out by a machine.
   ============================================================ */
:root{
  --ease-snap:cubic-bezier(.2,1.5,.35,1);   /* overshoots a touch: presses and pops */
  --ease-out:cubic-bezier(.16,.9,.3,1);     /* settles: sweeps and slides */
  --dur-1:.12s; --dur-2:.22s; --dur-3:.36s;
  /* a faint grain, generated in the stylesheet itself — no image files */
  --grain:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.38'/%3E%3C/svg%3E");
}

/* ---- buttons: press them and they press back ---- */
.btn{
  border-radius:11px 10px 12px 10px;        /* hand-cut, not machine-cut */
  transition:transform var(--dur-1) var(--ease-snap), background .13s, border-color .13s, box-shadow .13s;
}
.btn:hover:not(:disabled){transform:translateY(-1px)}
.btn:active:not(:disabled){transform:translateY(1px) scale(.97); box-shadow:0 1px 2px rgba(0,0,0,.4)}
.btn.primary{position:relative; overflow:hidden}
.btn.primary::after{
  content:""; position:absolute; inset:0; pointer-events:none; transform:translateX(-130%);
  background:linear-gradient(105deg,transparent 38%,rgba(255,255,255,.45) 50%,transparent 62%);
}
.btn.primary:hover:not(:disabled)::after{transition:transform .55s var(--ease-out); transform:translateX(130%)}
.seg button{transition:background .14s, color .14s, transform var(--dur-1) var(--ease-snap)}
.seg button:active{transform:scale(.96)}
.seg button.on{box-shadow:inset 0 -2px 0 rgba(0,0,0,.2)}
.qchip:active, .chipset button:active{transform:scale(.95)}

/* ---- the table: grain and a vignette, under everything ---- */
#boardWrap::after{
  content:""; position:absolute; inset:0; pointer-events:none; z-index:0;
  background:var(--grain), radial-gradient(ellipse at 50% 45%, transparent 55%, rgba(0,0,0,.34) 100%);
  background-size:140px 140px, cover; opacity:.5; mix-blend-mode:soft-light;
}
#boardSlot, #screenStrip, #toasts, #banner{position:relative; z-index:1}

/* ---- cards and panels: sticker shadows, a little tilt ---- */
.card, .sheetbox, .modalbox, #chatPanel, #voicePanel{
  box-shadow:0 1px 0 rgba(255,255,255,.05) inset, 0 10px 26px rgba(0,0,0,.28);
}
.pcard, .optcard, .sc-seat, .pf-card{border-radius:12px 11px 13px 11px}
.sec h3::after{
  content:""; display:block; width:26px; height:2px; margin-top:5px; border-radius:2px;
  background:linear-gradient(90deg,var(--accent),transparent);
}

/* ---- toasts and overlays: spring in, never slide dully ---- */
@keyframes toastIn{
  0%{opacity:0; transform:translateY(-16px) scale(.9) rotate(-1.2deg)}
  60%{opacity:1; transform:translateY(2px) scale(1.02) rotate(.4deg)}
  100%{opacity:1; transform:none}
}
.toast{animation:toastIn .34s var(--ease-snap); border-radius:11px 10px 12px 10px}
@keyframes popIn{
  0%{opacity:0; transform:translateY(14px) scale(.95)}
  100%{opacity:1; transform:none}
}
.sheetbox, .modalbox{animation:popIn .26s var(--ease-snap)}
#sheet, #modal{-webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px)}
.sheettabs button{transition:transform var(--dur-1) var(--ease-snap), background .14s}
.sheettabs button:active{transform:scale(.96)}

/* ---- the effect layers ---- */
#fxCanvas{position:fixed; inset:0; pointer-events:none; z-index:82}
.fx-ring{
  position:absolute; width:16px; height:16px; margin:-8px 0 0 -8px; border-radius:50%;
  border:2px solid rgba(245,166,35,.9); animation:fxRing .6s var(--ease-out) forwards;
}
@keyframes fxRing{to{transform:scale(7); opacity:0; border-width:1px}}
.fx-turnsweep{
  position:absolute; inset:-20% -40%; pointer-events:none;
  background:linear-gradient(105deg,transparent 42%,rgba(255,255,255,.17) 50%,transparent 58%);
  animation:fxTurnSweep .78s var(--ease-out) forwards;
}
@keyframes fxTurnSweep{from{transform:translateX(-55%)} to{transform:translateX(55%)}}
/* hit-stop: the world holds still for a beat, a shade brighter */
.fx-flash.good{box-shadow:inset 0 0 calc(90px * var(--fxstrength,1)) calc(22px * var(--fxstrength,1)) rgba(67,185,107,.55)}
.fx-flash.bad{box-shadow:inset 0 0 calc(110px * var(--fxstrength,1)) calc(30px * var(--fxstrength,1)) rgba(224,83,61,.6)}
.fx-flash.gold{box-shadow:inset 0 0 calc(110px * var(--fxstrength,1)) calc(30px * var(--fxstrength,1)) rgba(245,166,35,.6)}
.fx-burst{animation:fxBurst2 1.8s cubic-bezier(.2,1.4,.4,1) forwards}
@keyframes fxBurst2{
  0%{opacity:0; transform:translate(-50%,-50%) scale(.3) rotate(calc(var(--tilt,0deg) * -2))}
  18%{opacity:1; transform:translate(-50%,-50%) scale(1.14) rotate(var(--tilt,0deg))}
  30%{transform:translate(-50%,-50%) scale(1) rotate(calc(var(--tilt,0deg) * .5))}
  78%{opacity:1; transform:translate(-50%,-56%) scale(1) rotate(calc(var(--tilt,0deg) * .5))}
  100%{opacity:0; transform:translate(-50%,-72%) scale(.96) rotate(0deg)}
}
.fx-float{animation:fxRise2 1.4s var(--ease-out) forwards}
@keyframes fxRise2{
  0%{opacity:0; transform:translate(-50%,-30%) scale(.7)}
  18%{opacity:1; transform:translate(-50%,-64%) scale(1.14)}
  100%{opacity:0; transform:translate(calc(-50% + var(--drift,0px)),-200%) scale(1)}
}

/* ---- room state: offline, install, update ---- */
.netchip{
  display:inline-flex; align-items:center; gap:6px; font-size:11.5px; font-weight:800; letter-spacing:.4px;
  background:var(--warn-bg); color:var(--accent); border:1px solid var(--warn-edge);
  border-radius:999px; padding:4px 11px;
}
#updateBar{
  position:fixed; left:50%; top:14px; transform:translateX(-50%); z-index:90;
  display:flex; align-items:center; gap:10px; font-size:13px; font-weight:700;
  background:var(--glass); border:1px solid var(--accent); border-radius:999px;
  padding:8px 10px 8px 16px; box-shadow:0 10px 30px var(--shadow); animation:popIn .3s var(--ease-snap);
}

/* ---- motion preferences win over all of the above ---- */
html[data-motion="off"] *,
html[data-motion="off"] *::before,
html[data-motion="off"] *::after{animation:none !important; transition:none !important}
html[data-motion="off"] #fxCanvas{display:none}
html[data-motion="reduced"] .btn.primary::after,
html[data-motion="reduced"] .fx-turnsweep{display:none}
@media (prefers-reduced-motion: reduce){
  .btn.primary::after, .fx-turnsweep{display:none}
  .toast, .sheetbox, .modalbox{animation-duration:.01s}
}

/* entering a game, and coming back out, should feel like a cut with intent */
#game:not(.hidden){animation:gameIn .3s var(--ease-out)}
#lobby:not(.hidden){animation:gameIn .24s var(--ease-out)}
@keyframes gameIn{from{opacity:0} to{opacity:1}}

/* ============================================================
   ROUND TWO — fixes and table manners
   ============================================================ */

/* the camera moves the table; the page itself never scrolls under a shake */
.fx-freeze{transform:scale(1.012) !important; filter:brightness(1.16) contrast(1.05); transition:none}
.fx-freeze *{animation-play-state:paused !important}
#side{overflow-x:hidden}
@media (min-width:901px){ body.in-game{overflow:hidden} }

/* ---- terminating actions look like what they are ---- */
.btn.danger{background:linear-gradient(#3b1c18,#2c1411); color:#ffab9c; border-color:#8e3a2c; border-bottom-color:#5c2118}
.btn.danger:hover:not(:disabled){background:linear-gradient(#4c211b,#381814); border-color:#e0533d; color:#ffc7bc}
.btn.danger.solid{background:linear-gradient(#e86a55,#c4402d); color:#fff; border-color:#9a3021}
.btn.danger.solid:hover:not(:disabled){background:linear-gradient(#f07d69,#d24c38); color:#fff}
:root[data-theme="light"] .btn.danger{background:linear-gradient(#fff1ee,#fbe0da); color:#a3301f; border-color:#e3a497}
:root[data-theme="light"] .btn.danger:hover:not(:disabled){background:#fbd6cd; border-color:#c4402d; color:#8a2213}
:root[data-theme="light"] .btn.danger.solid{background:linear-gradient(#e86a55,#c4402d); color:#fff; border-color:#9a3021}

/* ---- card headers breathe: their buttons no longer sit on the next edge ---- */
.card > .row:first-child{margin-bottom:14px; row-gap:8px}
.card > .row:first-child h3{margin:0}

/* ---- a setting that only matters while another one is on ---- */
.optrow{transition:opacity .2s, filter .2s}
.optrow.dim{opacity:.36; pointer-events:none; filter:saturate(.35)}

/* ---- names: flair in front, supporter star behind ---- */
.flair{margin-right:5px; font-size:15px; line-height:1}
.supstar{cursor:help; margin-left:4px; display:inline-block; transition:transform .2s var(--ease-snap)}
.supstar:hover{transform:scale(1.35) rotate(-10deg)}

/* ---- places, when a table plays on after the first winner ---- */
.badge.medal{font-size:15px; margin-left:4px}
.podium{display:flex; flex-direction:column; gap:6px; margin-bottom:16px}
.pod{display:flex; align-items:center; gap:10px; background:var(--panel-2); border:1px solid var(--line);
  border-radius:12px 11px 13px 11px; padding:8px 12px; font-size:14px}
.pod .medal{font-size:22px; line-height:1}
.pod.p1{border-color:var(--gold-edge); background:var(--gold-bg); color:var(--gold-ink); font-size:15.5px}

/* ---- the ask dialog ---- */
.askbox{position:fixed; inset:0; z-index:96; display:flex; align-items:center; justify-content:center; padding:18px;
  background:rgba(6,10,16,.7); -webkit-backdrop-filter:blur(4px); backdrop-filter:blur(4px)}
.askcard{width:min(400px,100%); background:var(--panel); border:1px solid var(--line); border-radius:18px 16px 19px 16px;
  padding:22px 20px 18px; text-align:center; box-shadow:0 24px 60px rgba(0,0,0,.55); animation:popIn .26s var(--ease-snap)}
.askcard.danger{border-color:#8e3a2c; box-shadow:0 0 0 1px rgba(224,83,61,.25), 0 24px 60px rgba(0,0,0,.55)}
.askicon{font-size:40px; line-height:1; margin-bottom:8px; display:inline-block; animation:askWobble .5s var(--ease-snap)}
@keyframes askWobble{0%{transform:rotate(-14deg) scale(.6)} 60%{transform:rotate(6deg) scale(1.1)} 100%{transform:none}}
.askcard h2{margin:0 0 8px; font-size:19px}
.askcard p{margin:0 0 14px; color:var(--muted); font-size:13.5px; line-height:1.5}
.askstep{font-size:11px; font-weight:800; letter-spacing:1px; text-transform:uppercase; color:var(--bad); margin:-4px 0 12px}
.askrow{display:grid; grid-template-columns:1fr 1fr; gap:10px}

/* ---- the guided tour ---- */
.tourbox{position:fixed; inset:0; z-index:95}
.tour-hole{position:fixed; border-radius:14px; pointer-events:none;
  box-shadow:0 0 0 9999px rgba(6,10,16,.66), 0 0 0 3px var(--accent);
  transition:left .3s var(--ease-out), top .3s var(--ease-out), width .3s var(--ease-out), height .3s var(--ease-out);
  animation:tourGlow 1.6s ease-in-out infinite}
.tour-hole.off{left:50%; top:50%; width:0; height:0; box-shadow:0 0 0 9999px rgba(6,10,16,.72); animation:none}
@keyframes tourGlow{50%{box-shadow:0 0 0 9999px rgba(6,10,16,.66), 0 0 0 7px rgba(245,166,35,.5)}}
.tour-card{position:fixed; width:min(350px, calc(100vw - 24px)); background:var(--panel); color:var(--ink);
  border:1px solid var(--accent); border-radius:16px 14px 17px 14px; padding:14px 16px 12px;
  box-shadow:0 18px 50px rgba(0,0,0,.55); animation:popIn .25s var(--ease-snap)}
.tour-card h3{color:var(--accent); margin:2px 0 6px; font-size:14px}
.tour-card p{margin:0 0 12px; font-size:13.5px; line-height:1.55}
.tour-step{font-size:10.5px; font-weight:800; letter-spacing:1px; color:var(--muted)}
.tour-row{display:flex; align-items:center; gap:8px}
.tour-row .sp{flex:1}

/* ---- spotlight: a card held up for the whole table ---- */
.fx-spot{position:absolute; left:50%; top:46%; transform:translate(-50%,-50%); display:flex; flex-direction:column;
  align-items:center; gap:10px; max-width:92vw; animation:spotIn .5s var(--ease-snap)}
.fx-spot.out{animation:spotOut .38s ease-in forwards}
.fx-spot.calm{animation:none}
@keyframes spotIn{0%{opacity:0; transform:translate(-50%,-40%) scale(.6) rotate(-8deg)} 100%{opacity:1; transform:translate(-50%,-50%)}}
@keyframes spotOut{to{opacity:0; transform:translate(-50%,-56%) scale(.94)}}
.fx-spot-card{filter:drop-shadow(0 20px 40px rgba(0,0,0,.6)); transform:rotate(-2deg)}
.fx-spot-cap{font-size:clamp(18px,3.4vw,26px); font-weight:900; color:#fff; text-align:center;
  background:rgba(0,0,0,.66); padding:7px 18px; border-radius:999px; text-shadow:0 2px 6px rgba(0,0,0,.6)}
.fx-spot-cap.bad{box-shadow:0 0 0 2px rgba(224,83,61,.8), 0 0 30px rgba(224,83,61,.45)}
.fx-spot-lines{display:flex; flex-direction:column; gap:5px; align-items:center}
.fx-spot-lines > div{background:rgba(24,8,6,.86); color:#ffd9d2; font-weight:800; font-size:14.5px; padding:6px 14px;
  border-radius:10px; animation:spotLine .35s var(--ease-snap)}
.fx-spot-lines > div b{color:#fff}
@keyframes spotLine{from{opacity:0; transform:translateY(-6px) scale(.95)} to{opacity:1; transform:none}}

/* calling time on a game that has stopped going anywhere */
.wrapbtn{width:100%; margin-top:4px}

/* on a desktop table the side panel takes the right edge: centre the spotlight over the board */
@media (min-width:901px){ body.in-game.view-full .fx-spot{left:calc(50% - 180px)} }
