/* ===========================================================================
   THE TABLE — the approved desktop design.
   This is ~/888/kk-layout-mockup/layouts.css, copied and then SCOPED: every
   selector is prefixed with .kkt-root, and the mockup's `body.lab` anchor
   becomes that container.
   Nothing else is edited. Do not rewrite these rules — PORTING-SPEC.md is
   explicit that this file is the design, not a description of it.

   Scoping is not cosmetic. Six class names collide with ui/style.css —
   .armed .fresh .hidden .on .sub .wide — and the mockup has already lost an
   afternoon twice to exactly this kind of collision between two sheets on one
   page. Under .kkt-root neither sheet can reach the other's elements.

   The three variables below come from the mockup's own style.css, which is NOT
   copied (it is the old page's sheet); layouts.css consumes them. Everything
   else it uses is either defined in ui/style.css or set inline by the JS.
   =========================================================================== */
.kkt-root {
  --gold-dim: #8a7325;
  --muted: #9c8fbf;
  --panel-2: #2a2040;
}

.kkt-root /* ==========================================================================
   KK — five player-board layouts,
.kkt-root side by side with the real table behind so
   each one is judged on what it leaves visible as well as how it reads.
   Shared tokens come from style.css; everything here is layout-specific.
   ========================================================================== */

body.lab {overflow:hidden}.kkt-root #lab-stage {position:relative;width:100vw;height:calc(100vh - 50px);padding:14px}.kkt-root #lab-table {position:absolute;inset:14px;border:2px solid var(--edge);border-radius:26px;
  background:radial-gradient(120% 90% at 50% 40%,#1b1429 0%,#14101d 70%,#0e0b16 100%);
  display:flex;flex-direction:column;align-items:center;justify-content:flex-start;
  gap:14px;padding-top:30px;overflow:hidden}.kkt-root .tablerow {display:flex;align-items:center;gap:18px}.kkt-root #boardwrap {position:relative;flex:0 0 auto;line-height:0;
  transition:max-height .3s cubic-bezier(.2,.8,.25,1)}.kkt-root /* ---- THE DECK,
.kkt-root beside the board ---------------------------------------- */
#deckcol {position:relative;flex:0 0 96px;display:flex;flex-direction:column;gap:12px;line-height:1.2}.kkt-root .deckslot {position:relative;text-align:center}.kkt-root .deckslot.is-empty .dnum {display:none}.kkt-root .dlbl {font-size:8px;letter-spacing:.06em;color:var(--muted);margin-bottom:3px;white-space:nowrap}.kkt-root .dcard {width:84px;border-radius:7px;border:1px solid #7a6a3e;display:block;margin:0 auto;
  box-shadow:0 4px 12px rgba(0,0,0,.7)}.kkt-root .dcard.repelled {border-color:#8e4a5c;filter:grayscale(.5)}.kkt-root .dnum {position:absolute;right:4px;bottom:3px;font-size:9px;background:rgba(8,6,12,.85);
  border-radius:6px;padding:0 5px;color:var(--ink)}.kkt-root #deck-draw.drawing .dcard {animation:decknudge .4s ease}
@keyframes decknudge{50%{transform:translateY(-5px) rotate(-2deg)}}.kkt-root #lab-board {height:500px;aspect-ratio:3913/1957;object-fit:fill;border-radius:8px;opacity:.9;
  box-shadow:0 10px 40px rgba(0,0,0,.7)}.kkt-root #lab-host {position:absolute;left:14px;right:14px;bottom:14px;z-index:10}.kkt-root /* the control strip */
/* kept clear of BOTH tabs: the amulets ride the mat's top-left corner and the
   dragon its top-right,
.kkt-root so the panel lives in the strip above them. */
/* One compact band across the top. It clears the AMULETS tab (mat top-left)
   and the DRAGON tab (mat top-right),
.kkt-root which a side panel never could. */
#labbar {position:fixed;top:50px;left:0;right:0;z-index:200;display:none;
  align-items:center;gap:18px;flex-wrap:wrap;
  padding:6px 14px;background:rgba(16,12,26,.97);border-bottom:1px solid var(--edge);
  font-size:10px}.kkt-root #labbar.show {display:flex}.kkt-root #labbar.hide {display:none}.kkt-root .lbg {display:flex;align-items:center;gap:4px}.kkt-root .lbg > span {color:var(--muted);letter-spacing:.14em;margin-right:3px}.kkt-root .lbg button {background:var(--panel);border:1px solid var(--edge);color:var(--ink);
  border-radius:6px;padding:3px 8px;cursor:pointer;font-family:inherit;font-size:10px;
  letter-spacing:.04em}.kkt-root .lbg button.on {background:var(--gold);border-color:var(--gold);color:#1b1206;font-weight:bold}.kkt-root /* ==========================================================================
   SHARED PIECES — used by more than one layout
   ========================================================================== */
.L {position:relative;color:var(--ink)}.kkt-root .L .who {display:flex;align-items:center;gap:9px;flex:0 0 auto}.kkt-root .L .name {white-space:nowrap}.kkt-root .L .name {font-size:14px;letter-spacing:.08em;color:var(--acc)}.kkt-root .L .sub {font-size:11px;color:var(--muted)}.kkt-root .L .collapse {background:var(--panel);border:1px solid var(--edge);color:var(--ink);
  border-radius:8px;height:26px;padding:0 11px;cursor:pointer;font-size:14px;font-family:inherit}.kkt-root .L .collapse:hover {border-color:var(--gold);color:var(--gold)}.kkt-root /* --- THE DIE — a true d8 in three-quarter view -------------------------- */
.d8 {width:var(--dz,42px);height:var(--dz,42px);flex:0 0 auto;
  filter:drop-shadow(0 4px 6px rgba(0,0,0,.75))}.kkt-root .d8 svg {width:100%;height:100%;display:block;overflow:visible}.kkt-root .d8.last svg {filter:drop-shadow(0 0 9px var(--gold))}.kkt-root /* --- DICE,
.kkt-root three presentations ------------------------------------------ */
.dicew {position:relative;display:flex;flex-direction:column;align-items:center;gap:9px}.kkt-root .dgrid {display:grid;grid-template-columns:repeat(3,var(--dz,42px));gap:var(--dgap,8px);
  position:relative;z-index:2}.kkt-root .labslot {width:var(--dz,42px);height:var(--dz,42px)}.kkt-root .dlabel {font-size:9px;letter-spacing:.2em;color:var(--muted)}.kkt-root .dlabel b {color:var(--gold);font-size:12px}.kkt-root /* LOOSE — no container at all; the dice are jostled and cast their own shadow */
.dicew {--dgap:7px}.kkt-root .dgrid {padding:4px}.kkt-root .oppview {display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:9px 12px;border-radius:14px;background:rgba(0,0,0,.22);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.05)}.kkt-root .oppcap {font-size:8px;letter-spacing:.2em;color:var(--muted)}.kkt-root .oppdice {display:flex;gap:4px;flex-wrap:wrap;max-width:210px;justify-content:center}.kkt-root .oppdice .d8 {--dz:26px;filter:drop-shadow(0 2px 3px rgba(0,0,0,.7))}.kkt-root .dicew.opp .dlabel {font-size:8px}.kkt-root .dgrid .d8 {filter:drop-shadow(0 6px 7px rgba(0,0,0,.85))}.kkt-root /* --- ACTION BUTTONS,
.kkt-root three designs -------------------------------------- */
.verbs {display:flex;flex-direction:column;gap:7px;padding-bottom:0}.kkt-root .vb {cursor:pointer;font-family:inherit;background:none;border:none;padding:0;
  display:flex;flex-direction:row;align-items:center;gap:9px;transition:transform .14s}.kkt-root .vb:hover {transform:translateY(-2px)}.kkt-root .vi {display:block;background:var(--vc);
  -webkit-mask:var(--ico) center/contain no-repeat;mask:var(--ico) center/contain no-repeat}.kkt-root .vl {font-size:10px;letter-spacing:.12em;line-height:1.2;text-align:left;
  color:color-mix(in srgb,var(--vc) 80%,#fff)}.kkt-root /* 1 PLATE */
.vb {padding:6px 13px 6px 9px;border-radius:13px;min-width:150px;
  background:linear-gradient(180deg,rgba(255,255,255,.07),rgba(0,0,0,.3));
  border:1px solid color-mix(in srgb,var(--vc) 45%,transparent);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.12),0 5px 16px rgba(0,0,0,.55)}.kkt-root .vi {width:46px;height:46px;filter:drop-shadow(0 0 11px color-mix(in srgb,var(--vc) 55%,transparent))}.kkt-root .vb:hover {border-color:var(--vc);box-shadow:0 0 0 1px var(--vc),0 0 28px -8px var(--vc)}.kkt-root /* --- ACTION POINTS ------------------------------------------------------- */
.apwrap {display:flex;align-items:flex-start;gap:10px}.kkt-root .apl {font-size:9px;letter-spacing:.2em;color:var(--muted);padding-top:4px}.kkt-root .apgrid {display:flex;flex-direction:column;gap:7px}.kkt-root .apwrap {align-items:center}.kkt-root .aprow {display:flex;gap:7px;justify-content:flex-start}.kkt-root .ap {position:relative;width:22px;height:22px;border-radius:50%;border:2px solid #6d6288;flex:0 0 auto}.kkt-root .ap.on {background:var(--good);border-color:#a8f0bd;box-shadow:0 0 9px -2px var(--good)}.kkt-root .ap.bonus {border-color:var(--gold)}.kkt-root .ap.bonus.on {background:var(--gold);border-color:#ffe08a;box-shadow:0 0 9px -2px var(--gold)}.kkt-root /* a SPENT point is TICKED OFF — it was used,
.kkt-root not forbidden */
.ap.spent {background:rgba(111,220,140,.13);border-color:rgba(111,220,140,.5);
  box-shadow:none;color:var(--good);display:grid;place-items:center}.kkt-root .ap.spent.bonus {background:rgba(242,201,76,.13);border-color:rgba(242,201,76,.55);
  color:var(--gold)}.kkt-root .ap.spent svg {width:15px;height:15px;display:block}.kkt-root /* --- KROWN — the printed art exactly as drawn,
.kkt-root nothing behind it --------- */
.khero {display:flex;flex-direction:column;align-items:center;gap:5px;flex:0 0 auto;
  padding-bottom:6px}.kkt-root /* the crown art casts a shadow — keep it off the caption below */
.khero .krown {margin-bottom:14px}.kkt-root .kskin {display:flex;align-items:center;justify-content:center;gap:9px;font-size:10px;
  color:var(--muted);letter-spacing:.06em}.kkt-root .kskin button {background:none;border:1px solid var(--edge);color:var(--ink);border-radius:6px;
  width:20px;height:20px;line-height:1;cursor:pointer;font-family:inherit;padding:0}.kkt-root .kskin button:hover {border-color:var(--gold);color:var(--gold)}.kkt-root .kmax {position:absolute;top:7px;right:7px;width:24px;height:24px;border-radius:7px;
  background:rgba(10,7,18,.82);border:1px solid var(--gold-dim);color:var(--gold);
  font-family:inherit;font-size:12px;line-height:1;cursor:pointer;opacity:0;transition:opacity .14s;
  z-index:4;display:grid;place-items:center}.kkt-root .krown:hover .kmax {opacity:1}.kkt-root .kmax:hover {background:var(--gold);color:#1b1206}.kkt-root
/* An opponent's Krown is a thumbnail on someone else's panel — a control that
   only appears on hover is a control nobody finds. Theirs is always on. */
.o-krown .kmax {opacity:.85;width:20px;height:20px;font-size:10px;top:4px;right:4px}.kkt-root .o-krown .kmax:hover {opacity:1}.kkt-root /* the Krown alone,
.kkt-root centre screen */
.kv {position:absolute;inset:0;z-index:300;display:grid;place-items:center;
  background:rgba(6,4,12,.86);backdrop-filter:blur(3px);opacity:0;transition:opacity .2s;
  pointer-events:none}.kkt-root .kv.in {opacity:1}.kkt-root .kv.pinned {pointer-events:auto;cursor:zoom-out}.kkt-root .kv-box {display:flex;flex-direction:column;align-items:center;gap:12px;
  transform:scale(.9);transition:transform .24s cubic-bezier(.2,1.2,.35,1)}.kkt-root .kv.in .kv-box {transform:scale(1)}.kkt-root .kv-krown {position:relative;width:min(62vw,740px);aspect-ratio:340/234;
  box-shadow:0 30px 80px rgba(0,0,0,.9),0 0 90px -20px var(--matrim,#f2c94c);border-radius:16px}.kkt-root .kv-krown img {width:100%;height:100%;display:block;border-radius:16px}.kkt-root .kv-krown .gem {width:64px;height:64px}.kkt-root .kv-name {font-size:16px;letter-spacing:.3em;color:var(--gold)}.kkt-root .kv-sub {font-size:11px;letter-spacing:.24em;color:var(--muted)}.kkt-root .krown {position:relative;width:var(--kw,300px);aspect-ratio:340/234;flex:0 0 auto;
  border-radius:12px;overflow:hidden;box-shadow:0 10px 26px rgba(0,0,0,.8)}.kkt-root .krown img {width:100%;height:100%;display:block}.kkt-root .gem {position:absolute;width:var(--kgz,30px);height:var(--kgz,30px);transform:translate(-50%,-50%)}.kkt-root .gem svg {width:100%;height:100%;display:block}.kkt-root .kcount {font-size:12px;letter-spacing:.14em;color:var(--gold)}.kkt-root .kcount i {font-style:normal;opacity:.6}.kkt-root .kfav {font-size:10px;letter-spacing:.08em}.kkt-root .kfav.off {color:var(--bad)}.kkt-root .kfav.on {color:var(--good)}.kkt-root /* --- THE HAND — one arc; cards 7..12 ride IN FRONT of the first six ------ */
.handcol {display:flex;flex-direction:column;justify-content:flex-end;align-items:center;
  gap:14px;min-width:0;flex:1 1 auto}.kkt-root .handwrap {display:flex;flex-direction:column;align-items:center;min-width:0;
  justify-content:flex-end;width:100%}.kkt-root /* clip-path trims only left and right,
.kkt-root so a card tilted at the end of the arc
   keeps its corners instead of being cut off by the container */
.arc {position:relative;width:100%;display:flex;justify-content:center;align-items:flex-end;
  padding-bottom:6px;min-height:60px;clip-path:inset(-600px -26px -40px -26px)}.kkt-root .emptyhand {align-self:center;font-size:14px;letter-spacing:.02em;color:#cfc3ec;
  background:rgba(10,7,18,.5);
  border:1px dashed #6b5a99;border-radius:12px;padding:22px 34px}.kkt-root .arc .c {position:absolute;bottom:14px;height:var(--ch,152px);aspect-ratio:160/224;border-radius:9px;
  border:1px solid #8a7746;box-shadow:0 10px 26px rgba(0,0,0,.8);cursor:pointer;
  transform-origin:50% 50%;transition:transform .22s cubic-bezier(.2,.9,.3,1),box-shadow .18s}.kkt-root .arc .c img {width:100%;height:100%;object-fit:cover;image-rendering:pixelated;display:block;
  border-radius:8px}.kkt-root .arc .c.back {filter:brightness(.82) saturate(.88)}.kkt-root .arc .c.back:hover {filter:none}.kkt-root .arc .c:hover {transform:var(--t) translateY(-22px) scale(1.1)!important;z-index:300!important;
  filter:none;box-shadow:0 18px 42px rgba(0,0,0,.9),0 0 24px -6px var(--gold)}.kkt-root /* ⇅ moves a card between the front and back rows */
/* re-sorting sweeps the hand rather than snapping it */
.arc.resorting .c {transition:transform .46s cubic-bezier(.3,.9,.3,1)}.kkt-root .arc.resorting .c {transform:var(--t) translateY(-14px) rotate(0deg)!important}.kkt-root .handtools {display:flex;flex-direction:column;gap:7px;flex:0 0 auto;align-items:center}.kkt-root .htrow {display:flex;gap:8px;justify-content:center}.kkt-root .htool {display:flex;align-items:center;gap:7px;background:rgba(20,14,34,.92);
  border:1px solid var(--edge);color:var(--ink);border-radius:10px;padding:7px 12px;
  font-size:10px;letter-spacing:.1em;cursor:pointer;font-family:inherit;transition:all .14s}.kkt-root .htool .ti {width:16px;height:16px;flex:0 0 auto}.kkt-root .htool:hover {border-color:var(--gold);color:var(--gold);transform:translateY(-1px)}.kkt-root /* --- a card lifted out of the hand to be read --------------------------- */
#cardview {position:fixed;inset:0;z-index:400;display:grid;place-items:center;
  opacity:0;transition:opacity .22s}.kkt-root #cardview.in {opacity:1}.kkt-root #cardview.hidden {display:none}.kkt-root .cv-back {position:absolute;inset:0;background:rgba(6,4,12,.82);backdrop-filter:blur(3px)}.kkt-root .cv-card {position:relative;transform:scale(.82);transition:transform .26s cubic-bezier(.2,1.2,.35,1);
  max-height:90vh}.kkt-root #cardview.wide:not(.split) .cv-grid {max-height:82vh;overflow-y:auto;padding-right:10px}.kkt-root #cardview.in .cv-card {transform:scale(1)}.kkt-root .cv-card > img {height:80vh;border-radius:16px;border:2px solid var(--gold);
  box-shadow:0 26px 70px rgba(0,0,0,.9),0 0 60px -14px var(--gold)}.kkt-root .cv-grid {display:grid;grid-template-columns:repeat(6,1fr);gap:14px;max-width:92vw;width:100%}.kkt-root .cv-grid.g3 {grid-template-columns:repeat(3,1fr);gap:14px}.kkt-root .cv-grid img {width:100%;border-radius:10px;border:1px solid #8a7746;
  box-shadow:0 12px 30px rgba(0,0,0,.8)}.kkt-root .cv-cap {margin-bottom:14px;text-align:center;font-size:13px;letter-spacing:.3em;color:var(--gold)}.kkt-root /* GATHERING — the six Gathering cards beside your hand,
.kkt-root board out of the way */
.cv-split {display:flex;align-items:flex-start;gap:34px;width:96vw;max-width:96vw;
  height:86vh}.kkt-root /* each side scrolls on its own,
.kkt-root so a big hand is never trimmed at the bottom */
.cv-half {flex:1;min-width:0;height:100%;display:flex;flex-direction:column}.kkt-root .cv-half .cv-grid {overflow-y:auto;overflow-x:hidden;flex:1;min-height:0;
  padding:2px 10px 10px 2px;align-content:start}.kkt-root /* the board half is square: size it by HEIGHT so it always fits the overlay */
.cv-half.board {align-items:center}.kkt-root .cv-half.board .bhalf {flex:0 1 auto;width:auto;height:100%;max-width:100%;margin:0 auto}.kkt-root /* a discreet scrollbar rather than the platform default */
.cv-half .cv-grid::-webkit-scrollbar {width:9px}.kkt-root .cv-half .cv-grid::-webkit-scrollbar-track {background:rgba(255,255,255,.05);border-radius:6px}.kkt-root .cv-half .cv-grid::-webkit-scrollbar-thumb {background:var(--gold-dim);border-radius:6px}.kkt-root .cv-half .cv-grid::-webkit-scrollbar-thumb:hover {background:var(--gold)}.kkt-root /* the real printed art of that half of the board,
.kkt-root not a bare grid */
.bhalf {position:relative;width:100%;aspect-ratio:1957/1957;border-radius:12px;overflow:hidden;
  box-shadow:0 14px 40px rgba(0,0,0,.8)}.kkt-root .bhimg {position:absolute;top:0;height:100%;width:200%;max-width:none;object-fit:fill}.kkt-root .bhalf.gather .bhimg {left:0}.kkt-root .bhalf.kraft  .bhimg {left:-100%}.kkt-root .bslot {position:absolute;border-radius:4px;overflow:hidden;box-shadow:0 3px 10px rgba(0,0,0,.6)}.kkt-root .bslot img {width:100%;height:100%;object-fit:cover;display:block}.kkt-root .bzone {position:absolute;display:flex;align-items:center;justify-content:center;gap:6px;
  flex-wrap:wrap;border-radius:10px}.kkt-root .bzone .kd {--dz:52px;filter:drop-shadow(0 3px 7px rgba(0,0,0,.95))}.kkt-root .cv-rule {width:1px;align-self:stretch;background:linear-gradient(transparent,var(--gold-dim),transparent)}.kkt-root /* ==========================================================================
   THE MAT — tabs clipped ABOVE the top edge,
.kkt-root avatar inside it
   ========================================================================== */
/* collapsing slides the mat away so the whole Krafting area is readable */
/* The mat's tones are sampled from the chosen Krown's own artwork,
.kkt-root so picking a
   different Krown re-tints the whole player board to match it. */
.LX {position:relative;margin-top:88px;padding:16px 24px 12px;
  transition:transform .3s cubic-bezier(.2,.8,.25,1),background .4s,border-color .4s;
  border-radius:34px 34px 20px 20px;
  background:
    radial-gradient(120% 90% at 50% -10%,color-mix(in srgb,var(--matrim,#f2c94c) 18%,transparent),transparent 55%),
    linear-gradient(180deg,var(--mat1,#3a2c58),var(--mat2,#241b3a) 45%,var(--mat3,#16111f));
  border:1px solid color-mix(in srgb,var(--matrim,#6b57a0) 42%,#6b57a0);
  box-shadow:inset 0 2px 0 rgba(255,255,255,.14),inset 0 0 70px rgba(0,0,0,.55),
             0 -14px 60px rgba(0,0,0,.7)}.kkt-root .LX.is-collapsed {transform:translateY(calc(100% - 52px))}.kkt-root .LX.is-collapsed .xg,
.kkt-root .LX.is-collapsed .tab {opacity:0;pointer-events:none;transition:opacity .18s}.kkt-root .LX::before {content:"";position:absolute;left:0;right:0;top:0;height:46px;
  border-radius:34px 34px 0 0;pointer-events:none;
  background:linear-gradient(180deg,rgba(255,255,255,.10),transparent)}.kkt-root .tab {position:absolute;bottom:100%;padding:6px 14px 10px;border-radius:16px 16px 0 0;
  background:linear-gradient(180deg,#4a3a72,#3a2c58);
  border:1px solid #6b57a0;border-bottom:none;
  box-shadow:0 -8px 22px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.12);
  transition:padding .18s}.kkt-root /* clicking the label opens and shuts the tab */
.tab .tl {display:flex;align-items:center;gap:7px;background:none;border:none;padding:2px 0 6px;
  font-family:inherit;font-size:9px;letter-spacing:.22em;color:var(--muted);cursor:pointer;
  width:100%}.kkt-root .tab .tl:hover {color:var(--gold)}.kkt-root .tab .tl b {font-size:10px;color:var(--gold)}.kkt-root .tab .tl i {font-style:normal;color:var(--gold);font-size:10px}.kkt-root .tab.shut {padding-bottom:5px}.kkt-root .tab.shut .tl {padding-bottom:0}.kkt-root .tab-amu .tl {justify-content:flex-start}.kkt-root /* the dragon is anchored right,
.kkt-root so its explanation opens leftwards */
.tab-drg .tl {justify-content:flex-end;flex-direction:row-reverse}.kkt-root .crestmini {font-size:13px;letter-spacing:0}.kkt-root /* AMULETS — label on top,
.kkt-root tokens below it,
.kkt-root aligned left,
.kkt-root wrapping as they grow */
.tab-amu {left:26px}.kkt-root .amurow {display:flex;flex-wrap:nowrap;gap:6px}.kkt-root .amu {position:relative;width:44px;border-radius:6px;overflow:visible;cursor:pointer;
  background:none;border:none;padding:0;transition:transform .13s}.kkt-root .amu .art {width:100%;display:block;border-radius:6px;border:1px solid #6b5a8e;
  /* THE MAT MUST KNOW ITS HEIGHT BEFORE THE ART DECODES. reserveHostSpace()
     measures the top of the mat to work out how tall the board may be; these
     tabs carried no intrinsic size, so until they decoded the mat was 30px
     short, the board was capped 30px too tall, and when the art landed the
     ResizeObserver corrected it — as an animated slide from 942px to 867px
     wide, dragging every percentage-positioned thing on the board with it.
     That is the jump between Stefano's two screenshots. */
  aspect-ratio:360/620}.kkt-root .amu:hover {transform:translateY(-4px);z-index:40}.kkt-root .amu:hover .art {box-shadow:0 0 0 2px var(--gold),0 8px 18px rgba(0,0,0,.7)}.kkt-root /* hovering an amulet names the free action it grants,
.kkt-root with that action's icon */
.amutip {position:absolute;bottom:calc(100% + 9px);left:50%;transform:translateX(-50%);
  background:#120d1f;border:1px solid var(--gold-dim);border-radius:10px;padding:7px 11px;
  display:flex;flex-direction:column;gap:5px;opacity:0;pointer-events:none;transition:opacity .12s;
  white-space:nowrap;box-shadow:0 10px 26px rgba(0,0,0,.8);z-index:60}.kkt-root .amu:hover .amutip {opacity:1}.kkt-root .atrow {display:flex;align-items:center;gap:8px}.kkt-root .ati {width:19px;height:19px;background:var(--vc);flex:0 0 auto;
  -webkit-mask:var(--ico) center/contain no-repeat;mask:var(--ico) center/contain no-repeat}.kkt-root .atl {font-size:11px;color:var(--ink)}.kkt-root .atany {font-size:8px;letter-spacing:.2em;color:var(--gold)}.kkt-root /* DRAGON — a crest,
.kkt-root its name,
.kkt-root then the blessing and the curse each marked */
.tab-drg {right:26px;max-width:420px}.kkt-root .drgbody {display:flex;align-items:flex-start;gap:12px}.kkt-root /* A dark disc with a gold rim: an emoji on gold vanishes. (Placeholder until
   Ernestas supplies proper dragon icons.) */
.drgcrest {width:42px;height:42px;flex:0 0 auto;border-radius:50%;display:grid;place-items:center;
  font-size:21px;background:radial-gradient(70% 70% at 38% 30%,#2a2040,#100b1c);
  box-shadow:inset 0 0 0 2px var(--gold),inset 0 3px 10px rgba(0,0,0,.8),
             0 5px 14px rgba(0,0,0,.7)}.kkt-root .drgtxt {display:flex;flex-direction:column;gap:3px}.kkt-root .drgname {font-size:13px;letter-spacing:.16em;color:var(--gold)}.kkt-root .drgline {display:flex;align-items:center;gap:7px;font-size:11px;line-height:1.3}.kkt-root .drgline .m {width:17px;height:17px;border-radius:5px;display:grid;place-items:center;
  font-size:10px;flex:0 0 auto}.kkt-root .drgline.bless {color:#b6f0c8}.kkt-root .drgline.bless .m {background:rgba(111,220,140,.18);color:var(--good);
  box-shadow:inset 0 0 0 1px rgba(111,220,140,.45)}.kkt-root .drgline.curse {color:#ffc0c0}.kkt-root .drgline.curse .m {background:rgba(255,107,107,.16);color:var(--bad);
  box-shadow:inset 0 0 0 1px rgba(255,107,107,.45)}.kkt-root .mat-id {position:absolute;left:26px;top:14px;z-index:6}.kkt-root .LX .who {display:flex;align-items:center;gap:9px}.kkt-root .LX .av {width:30px;height:30px;border-radius:50%;display:grid;place-items:center;
  font-size:16px;background:#221c30;border:2px solid var(--acc)}.kkt-root .LX .name {font-size:14px;letter-spacing:.08em;color:var(--acc);white-space:nowrap}.kkt-root .LX .collapse {position:absolute;right:22px;top:14px;z-index:6;
  background:rgba(20,14,34,.9);border:1px solid var(--edge);color:var(--ink);
  border-radius:8px;height:26px;padding:0 11px;cursor:pointer;font-size:14px;font-family:inherit}.kkt-root .LX .collapse:hover {border-color:var(--gold);color:var(--gold)}.kkt-root /* The four blocks are spread across the full width; the hand takes the middle
   and stays centred in it,
.kkt-root so a short hand leaves even margins rather than one
   large hole. Every block hugs its own height,
.kkt-root so the mat is never taller than
   its tallest content. */
/* EVERY block is anchored to ONE baseline — the bottom of PLAY & RESOLVE.
   Before this the Krown,
.kkt-root the dice,
.kkt-root the hand tools and the rail each ended on a
   different line. */
.xg {display:flex;align-items:flex-end;justify-content:space-between;gap:26px;padding-top:24px}.kkt-root .khero,
.kkt-root .console {flex:0 0 auto}.kkt-root .verbs {flex:0 0 auto}.kkt-root /* The dice start on the same top line as the Krown and the cards; extra action
   points are added BELOW the three green ones and never move that line. */
.console {display:flex;flex-direction:column;align-items:center;gap:12px;
  align-self:flex-start}.kkt-root .krown {--kw:250px;--kgz:33px}

/* ==========================================================================
   YOUR TURN — the action buttons breathe so the first thing you notice is
   that you have to choose an action, and the action point about to be spent
   breathes with them, on the same beat.
   ========================================================================== */
@keyframes vbreathe{
  0%,100%{box-shadow:inset 0 1px 0 rgba(255,255,255,.12),0 5px 16px rgba(0,0,0,.55)}
  50%    {box-shadow:inset 0 1px 0 rgba(255,255,255,.12),0 5px 16px rgba(0,0,0,.55),
          0 0 0 1px var(--vc),0 0 24px -6px var(--vc)}
}
@keyframes apbreathe{
  0%,100%{box-shadow:0 0 9px -2px var(--good)}
  50%    {box-shadow:0 0 0 4px rgba(111,220,140,.28),0 0 18px 0 var(--good)}
}.kkt-root .myturn .vb {animation:vbreathe 2.2s ease-in-out infinite}.kkt-root .myturn .vb:nth-child(2) {animation-delay:.06s}.kkt-root .myturn .vb:nth-child(3) {animation-delay:.12s}.kkt-root .myturn .vb:nth-child(4) {animation-delay:.18s}.kkt-root .myturn .ap.next {animation:apbreathe 2.2s ease-in-out infinite}.kkt-root /* the fly is out: everything beats faster */
.nagging .myturn .vb {animation-duration:.85s}.kkt-root .nagging .myturn .ap.next {animation-duration:.85s}.kkt-root /* ==========================================================================
   THE FLY — an idle nudge. It wanders on a smooth wiggle; the swatter waits on
   the right,
.kkt-root clear of the action rail.
   ========================================================================== */
.idlefly {position:absolute;left:0;top:0;width:22px;height:22px;z-index:180;
  pointer-events:none;opacity:0;transition:opacity .5s;will-change:transform}.kkt-root .idlefly.in {opacity:1}.kkt-root .fly-body {position:relative;width:22px;height:22px;transform:translate(-50%,-50%)}.kkt-root .fly-core {position:absolute;left:6px;top:7px;width:11px;height:8px;border-radius:60% 40% 45% 55%;
  background:linear-gradient(160deg,#4a4458,#14111c 70%);
  box-shadow:0 1px 2px rgba(0,0,0,.8),inset -1px -1px 2px rgba(255,255,255,.18)}.kkt-root .fly-core::after {content:"";position:absolute;left:-3px;top:1.5px;width:4px;height:4px;
  border-radius:50%;background:#2a2334;box-shadow:inset -1px -1px 1px rgba(255,255,255,.25)}.kkt-root .fly-wing {position:absolute;top:2px;width:9px;height:5px;border-radius:60% 70% 40% 50%;
  background:rgba(214,226,255,.42);box-shadow:inset 0 0 2px rgba(255,255,255,.5)}.kkt-root .fly-wing.l {left:3px;transform-origin:100% 100%;animation:wingl .09s linear infinite}.kkt-root .fly-wing.r {left:10px;transform-origin:0% 100%;animation:wingr .09s linear infinite}
@keyframes wingl{0%,100%{transform:rotate(-18deg) scaleY(1)}50%{transform:rotate(-52deg) scaleY(.55)}}
@keyframes wingr{0%,100%{transform:rotate(18deg) scaleY(1)}50%{transform:rotate(52deg) scaleY(.55)}}.kkt-root /* clear of BOTH the action rail (bottom right of the mat) and the DRAGON tab
   (top right of the mat): it waits out on the empty right edge of the table */
.flyswat {position:absolute;right:18px;top:30%;z-index:190;display:flex;flex-direction:column;
  align-items:center;gap:3px;background:rgba(16,12,26,.94);border:1px solid var(--edge);
  border-radius:14px;padding:8px 10px 6px;cursor:pointer;font-family:inherit;
  opacity:0;transform:translateY(8px);transition:opacity .3s,transform .3s,border-color .15s}.kkt-root .flyswat.in {opacity:1;transform:none}.kkt-root .flyswat svg {width:34px;height:46px;display:block}.kkt-root .flyswat span {font-size:8px;letter-spacing:.2em;color:var(--muted)}.kkt-root .flyswat:hover {border-color:var(--gold)}.kkt-root .flyswat:hover span {color:var(--gold)}.kkt-root .flyswat:active {transform:translateY(2px) rotate(-6deg)}
/* the swat itself: a quick whack as the fly bolts */
@keyframes swung{0%{transform:rotate(0)}25%{transform:rotate(-26deg) translateX(-6px)}
  60%{transform:rotate(12deg)}100%{transform:rotate(0)}}.kkt-root .flyswat.swung svg {animation:swung .42s cubic-bezier(.3,1.4,.4,1)}.kkt-root /* ==========================================================================
   OPPONENTS — the same mat language as your own board,
.kkt-root compacted,
.kkt-root and tinted
   by THEIR Krown. An opponent PUSHES the table aside rather than covering it.
   ========================================================================== */
/* AN OPEN PANEL MUST NEVER COVER THE BOARD. The table is given the room that is
   left over and the board SHRINKS TO FIT it — scaling by a guess could still
   overlap,
.kkt-root and pushing alone cropped it. */
#lab-table {transition:padding .3s cubic-bezier(.2,.8,.25,1)}.kkt-root #lab-board {height:auto;max-height:var(--kkt-board-max, 500px);max-width:100%;width:auto;display:block;
  transition:max-height .3s cubic-bezier(.2,.8,.25,1)}.kkt-root /* the top strip is only ~200px tall,
.kkt-root so the board keeps most of its size */
#lab-stage.push-top   #lab-table {padding-top:214px}.kkt-root #lab-stage.push-left  #lab-table {padding-left:330px}.kkt-root #lab-stage.push-right #lab-table {padding-right:330px}.kkt-root /* the board shrinks as well as shifts — the deck column made the row too wide
   for a push alone,
.kkt-root so a side panel was eating the Krafting */
.kkt-root .tablerow {min-width:0}.kkt-root #boardwrap {flex:0 1 auto;min-width:0}.kkt-root /* your own bar always stays clear of an open side rail,
.kkt-root so its ↑ is reachable */
#lab-host {transition:left .3s cubic-bezier(.2,.8,.25,1),right .3s cubic-bezier(.2,.8,.25,1)}.kkt-root #lab-stage.push-left  #lab-host {left:326px}.kkt-root #lab-stage.push-right #lab-host {right:326px}.kkt-root /* ---- things drawn ON the board ---- */
.bscrim {position:absolute;top:0;bottom:0;background:rgba(8,6,14,.74);opacity:0;
  pointer-events:none;transition:opacity .25s;z-index:3;border-radius:8px}.kkt-root .s-gather {left:0;width:49.7%}.kkt-root .s-kraft {right:0;width:50.3%}.kkt-root #boardwrap.dim-gather .s-gather {opacity:1}.kkt-root #boardwrap.dim-kraft  .s-kraft {opacity:1}.kkt-root #hi-slots,
.kkt-root #hi-zones {position:absolute;inset:0;z-index:4;pointer-events:none}.kkt-root .hi {position:absolute;border-radius:8px}
@keyframes hipulse{0%,100%{box-shadow:0 0 0 2px rgba(122,215,255,.6),0 0 20px -4px rgba(122,215,255,.8)}
  50%{box-shadow:0 0 0 5px rgba(122,215,255,1),0 0 34px 0 rgba(122,215,255,.6)}}
@keyframes hipulsegold{0%,100%{box-shadow:0 0 0 2px rgba(242,201,76,.7),0 0 22px -4px rgba(242,201,76,.85)}
  50%{box-shadow:0 0 0 6px rgba(242,201,76,1),0 0 38px 0 rgba(242,201,76,.65)}}.kkt-root .hi.live {animation:hipulse 1.1s ease-in-out infinite}.kkt-root .hi.pick {animation:hipulsegold 1s ease-in-out infinite}.kkt-root /* the caption belongs to the box it labels: it can never be wider than it */
.hi .tag {position:absolute;left:50%;bottom:-11px;transform:translateX(-50%);
  max-width:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  background:rgba(12,9,20,.96);border:1px solid var(--gold);color:var(--gold);font-size:9px;
  letter-spacing:.06em;padding:2px 7px;border-radius:8px;box-sizing:border-box}.kkt-root /* one shape for every highlight — a rounded rectangle,
.kkt-root cyan for a live
   option and gold for the one taken */
.hi.retr {animation:hipulsegold 1s ease-in-out infinite}.kkt-root /* --- the collapsed seat token ------------------------------------------- */
/* one shape for every player,
.kkt-root and the token slides INWARD on hover — the way
   its board will open — with an arrow saying so */
.oseat {position:absolute;z-index:60;display:flex;align-items:center;gap:9px;cursor:pointer;
  background:rgba(18,13,30,.94);border:1px solid var(--edge);border-radius:10px;
  padding:7px 12px;font-family:inherit;
  transition:transform .18s cubic-bezier(.2,.8,.25,1),border-color .16s,box-shadow .16s}.kkt-root .oseat:hover {border-color:var(--acc);box-shadow:0 0 0 1px var(--acc),0 6px 18px rgba(0,0,0,.6)}.kkt-root .s-dir {font-size:13px;color:var(--acc-ink,var(--acc));opacity:.55;transition:opacity .16s}.kkt-root .oseat:hover .s-dir {opacity:1}.kkt-root .oseat.acting {border-color:var(--acc);box-shadow:0 0 0 1px var(--acc),0 0 26px -6px var(--acc)}.kkt-root .s-av {width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font-size:16px;
  background:#221c30;border:2px solid var(--acc)}.kkt-root .s-name {font-size:12px;letter-spacing:.08em;color:var(--acc-ink,var(--ink))}.kkt-root .s-k {font-size:11px;font-weight:bold;color:#140f1e;background:var(--acc);
  padding:1px 8px;border-radius:10px}.kkt-root .oseat-top {top:10px;left:50%;transform:translateX(-50%)}.kkt-root .oseat-top:hover {transform:translateX(-50%) translateY(9px)}.kkt-root /* The side tokens are ROTATED to run down their own edge. Rotating about the
   CENTRE left them floating 70px inboard (half the difference between the
   token's width and its height),
.kkt-root so they are rotated about the corner instead
   and sit flush against the edge with no padding at all. */
.oseat-left {left:0;top:52px;transform-origin:0 0;
  transform:rotate(90deg) translateY(-100%);
  transition:left .18s cubic-bezier(.2,.8,.25,1),border-color .16s,box-shadow .16s}.kkt-root .oseat-left:hover {left:11px}.kkt-root .oseat-right {right:0;top:52px;transform-origin:100% 0;
  transform:rotate(-90deg) translateY(-100%);
  transition:right .18s cubic-bezier(.2,.8,.25,1),border-color .16s,box-shadow .16s}.kkt-root .oseat-right:hover {right:11px}.kkt-root .oseat-left,
.kkt-root .oseat-right {border-radius:0 10px 10px 0}.kkt-root .oseat-right {border-radius:10px 0 0 10px}.kkt-root /* rotated,
.kkt-root the avatar and the arrow would lie on their side — stand them up */
.oseat-left .s-av,
.kkt-root .oseat-left .s-k,
.kkt-root .oseat-left .s-dir {transform:rotate(-90deg)}.kkt-root .oseat-right .s-av,
.kkt-root .oseat-right .s-k,
.kkt-root .oseat-right .s-dir {transform:rotate(90deg)}.kkt-root /* --- the open board ------------------------------------------------------ */
.opp {position:absolute;z-index:70;padding:12px 16px;
  background:
    radial-gradient(120% 90% at 50% -10%,color-mix(in srgb,var(--matrim) 16%,transparent),transparent 55%),
    linear-gradient(180deg,var(--mat1),var(--mat2) 45%,var(--mat3));
  border:1px solid color-mix(in srgb,var(--matrim) 42%,#6b57a0);
  box-shadow:0 18px 50px rgba(0,0,0,.75)}.kkt-root .opp.acting {box-shadow:0 0 0 2px var(--acc),0 0 40px -10px var(--acc),0 18px 50px rgba(0,0,0,.75)}.kkt-root .opp-top {top:0;left:44px;right:44px;border-radius:0 0 22px 22px;padding-top:8px}.kkt-root /* the strip is short,
.kkt-root so its header shares the top line with the panels */
.opp-top .o-head {position:absolute;top:10px;left:18px;right:18px;margin:0;z-index:2}.kkt-root .opp-top .o-body {padding-top:26px}.kkt-root .opp-top .o-shut {margin-left:auto}.kkt-root /* only one board is open at a time,
.kkt-root so a rail can take the WHOLE height —
   the same way the top strip takes the whole width */
.opp-left {left:0;top:0;bottom:0;width:310px;border-radius:0 22px 22px 0;overflow:hidden}.kkt-root .opp-right {right:0;top:0;bottom:0;width:310px;border-radius:22px 0 0 22px;overflow:hidden}.kkt-root .o-head {display:flex;align-items:center;gap:10px;margin-bottom:10px}.kkt-root .o-av {width:28px;height:28px;border-radius:50%;display:grid;place-items:center;font-size:15px;
  background:#221c30;border:2px solid var(--acc)}.kkt-root .o-name {font-size:13px;letter-spacing:.1em;color:var(--acc-ink,var(--acc))}.kkt-root .o-turn {font-size:8px;letter-spacing:.2em;color:#140f1e;background:var(--acc);
  padding:2px 8px;border-radius:9px}.kkt-root .o-shut {margin-left:auto;background:rgba(20,14,34,.9);border:1px solid var(--edge);color:var(--ink);
  border-radius:8px;height:24px;padding:0 10px;cursor:pointer;font-size:13px;font-family:inherit}.kkt-root .o-shut:hover {border-color:var(--gold);color:var(--gold)}.kkt-root /* TOP = one row; SIDES = one column. Same panels,
.kkt-root same order. */
.opp-top .o-body {display:flex;align-items:center;justify-content:space-around;gap:18px}.kkt-root .opp-left .o-body,
.kkt-root .opp-right .o-body {display:flex;flex-direction:column;
  justify-content:space-evenly;gap:6px;height:calc(100% - 46px);min-height:0}.kkt-root .opp-left .o-body > *,
.kkt-root .opp-right .o-body > * {flex:0 0 auto}.kkt-root /* the crown's shadow must not fall on the count beneath it */
.o-krown .krown {margin-bottom:10px}.kkt-root .opp-left .o-krown .krown,
.kkt-root .opp-right .o-krown .krown {width:196px}.kkt-root .opp-left .o-drg,
.kkt-root .opp-right .o-drg {max-width:280px;align-self:center}.kkt-root .opp-left .o-amurow,
.kkt-root .opp-right .o-amurow {max-width:260px}.kkt-root .o-lbl {font-size:8px;letter-spacing:.2em;color:var(--muted);text-align:center}.kkt-root .o-lbl b {color:var(--gold);font-size:11px}.kkt-root .o-krown {display:flex;flex-direction:column;align-items:center;gap:3px;flex:0 0 auto}.kkt-root .o-krown .krown {width:184px;--kgz:24px;position:relative;aspect-ratio:1240/858;
  border-radius:9px;overflow:hidden;box-shadow:0 6px 16px rgba(0,0,0,.7)}.kkt-root .o-kcount {font-size:11px;letter-spacing:.12em;color:var(--gold)}.kkt-root .o-kcount i {font-style:normal;opacity:.6}.kkt-root .o-fav {font-size:8px;letter-spacing:.12em;color:var(--good)}.kkt-root .o-dice {display:flex;flex-direction:column;align-items:center;gap:5px}.kkt-root /* tidy,
.kkt-root not jostled: an opponent's supply is information,
.kkt-root not a toy */
.o-dicerow {display:flex;flex-wrap:wrap;gap:4px;justify-content:center;max-width:170px}.kkt-root .o-dicerow .d8 {--dz:26px;filter:drop-shadow(0 2px 3px rgba(0,0,0,.8))}.kkt-root .o-acts {display:flex;flex-direction:column;align-items:center;gap:5px}.kkt-root .o-aprow {display:flex;gap:6px}.kkt-root .o-acts .ap {width:17px;height:17px}.kkt-root .o-acts .ap.spent svg {width:11px;height:11px}.kkt-root .o-cards {display:flex;flex-direction:column;align-items:center;gap:5px}.kkt-root .o-cardrow {display:flex}.kkt-root .o-card {width:34px;aspect-ratio:160/224;border-radius:4px;overflow:hidden;border:1px solid #554a2c;
  margin-left:-13px;box-shadow:0 3px 8px rgba(0,0,0,.7)}.kkt-root .o-card:first-child {margin-left:0}.kkt-root .o-card img {width:100%;height:100%;object-fit:cover;display:block}.kkt-root .o-amu {display:flex;flex-direction:column;align-items:center;gap:5px}.kkt-root .o-amurow {display:flex;gap:4px;flex-wrap:wrap;justify-content:center;max-width:180px}.kkt-root .o-amurow .amu {width:26px}.kkt-root .o-drg {display:flex;align-items:flex-start;gap:9px;max-width:290px}.kkt-root .o-drgcrest {width:32px;height:32px;flex:0 0 auto;border-radius:50%;display:grid;place-items:center;
  font-size:16px;background:radial-gradient(70% 70% at 38% 30%,#2a2040,#100b1c);
  box-shadow:inset 0 0 0 2px var(--gold),0 4px 10px rgba(0,0,0,.7)}.kkt-root .o-drgname {font-size:10px;letter-spacing:.14em;color:var(--gold)}.kkt-root .o-kcount {color:var(--acc-ink,var(--gold))}.kkt-root .o-drgline {display:flex;align-items:flex-start;gap:5px;font-size:9px;line-height:1.35}.kkt-root .o-drgline .m {flex:0 0 auto}.kkt-root .o-drgline.bless {color:#b6f0c8}.kkt-root .o-drgline.curse {color:#ffc0c0}.kkt-root /* what a player is doing right now,
.kkt-root on their own board */
.o-doing {display:flex;align-items:center;gap:9px;margin-left:14px;padding:4px 12px 4px 8px;
  border-radius:10px;background:rgba(0,0,0,.34);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--acc) 45%,transparent);
  animation:doingin .3s cubic-bezier(.2,1.3,.4,1)}
@keyframes doingin{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}.kkt-root .o-doing img {width:24px;height:24px;flex:0 0 auto}.kkt-root .o-doing span {font-size:11px;color:#d9cff0;letter-spacing:.04em}.kkt-root .o-doing b {color:var(--acc-ink,var(--acc));letter-spacing:.12em;margin-right:2px}.kkt-root .mat-id .o-doing {margin-left:12px}.kkt-root .mat-id {display:flex;align-items:center}.kkt-root /* the simulation hides the control strip so the table is judged on its own */
#lab-stage.sim ~ #labbar,
.kkt-root #labbar.simhide {display:none}.kkt-root .lbg .sim {background:var(--gold);border-color:var(--gold);color:#1b1206;font-weight:bold;
  letter-spacing:.1em;padding:4px 12px}.kkt-root /* ==========================================================================
   THE ACTION FEED — every player's actions are reported in ONE place,
.kkt-root under
   the board,
.kkt-root so there is only ever one spot to look at.
   ========================================================================== */
/* directly under the board,
.kkt-root centred on it */
#actionfeed {flex:0 0 auto;z-index:120;display:flex;justify-content:center;
  pointer-events:none;opacity:0;transition:opacity .2s;min-height:44px}.kkt-root #actionfeed.on {opacity:1}.kkt-root .af-row {display:flex;align-items:center;gap:12px;padding:8px 20px 8px 10px;border-radius:30px;
  background:rgba(14,10,24,.95);border:1px solid color-mix(in srgb,var(--acc-ink) 45%,transparent);
  box-shadow:0 10px 30px rgba(0,0,0,.8),0 0 26px -10px var(--acc-ink);
  animation:afin .3s cubic-bezier(.2,1.3,.4,1)}
@keyframes afin{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}.kkt-root .af-av {width:28px;height:28px;border-radius:50%;display:grid;place-items:center;font-size:15px;
  background:#221c30;border:2px solid var(--acc-ink)}.kkt-root .af-who {font-size:12px;letter-spacing:.1em;color:var(--acc-ink)}.kkt-root .af-icon {width:24px;height:24px}.kkt-root .af-verb {font-size:12px;letter-spacing:.14em;color:var(--gold)}.kkt-root .af-what {font-size:12px;color:#cfc2ea}.kkt-root /* ==========================================================================
   THE ACTION STAGE — what an action LOOKS like,
.kkt-root not just what it is called.
   The active piece is always parked over the half the action has greyed out,
.kkt-root so it can never sit on top of a live target.
   ========================================================================== */
#actstage {position:absolute;inset:0;z-index:150;pointer-events:none}.kkt-root #b-cards,
.kkt-root #b-dice,
.kkt-root #daystone {position:absolute;inset:0;z-index:2;pointer-events:none}.kkt-root /* THE Day Stone */
.daystone {position:absolute;width:2.1%;aspect-ratio:1;transform:translate(-50%,-50%) rotate(45deg);
  border-radius:18%;background:radial-gradient(circle at 35% 30%,#ffe9a8,var(--gold) 60%,#b8860f);
  border:2px solid #fff5cf;box-shadow:0 0 16px 0 rgba(242,201,76,.8),0 3px 7px rgba(0,0,0,.7);
  transition:left .45s cubic-bezier(.3,.9,.3,1),top .45s cubic-bezier(.3,.9,.3,1)}.kkt-root .as-die {position:absolute;width:132px;height:132px;opacity:0;
  transform:translate(-50%,-50%) scale(.4);
  transition:transform .32s cubic-bezier(.2,1.4,.4,1),opacity .25s;
  filter:drop-shadow(0 10px 28px rgba(0,0,0,.9))}.kkt-root .as-die.in {opacity:1;transform:translate(-50%,-50%) scale(1)}.kkt-root .as-die svg {width:100%;height:100%;display:block}
@keyframes asshake{0%{transform:translate(-50%,-50%) rotate(-9deg) scale(1.04)}
  25%{transform:translate(-50%,-50%) rotate(8deg) scale(.96)}
  50%{transform:translate(-50%,-50%) rotate(-6deg) scale(1.05)}
  75%{transform:translate(-50%,-50%) rotate(7deg) scale(.97)}
  100%{transform:translate(-50%,-50%) rotate(-9deg) scale(1.04)}}.kkt-root .as-die.rolling {animation:asshake .4s linear infinite}.kkt-root .as-card {position:absolute;width:206px;opacity:0;transform:translate(-50%,-50%) scale(.5) rotate(-12deg);
  transition:transform .36s cubic-bezier(.2,1.3,.4,1),opacity .28s}.kkt-root .as-card.in {opacity:1;transform:translate(-50%,-50%) scale(1) rotate(-3deg)}.kkt-root .as-card img {width:100%;display:block;border-radius:12px;border:2px solid var(--gold);
  box-shadow:0 18px 48px rgba(0,0,0,.9),0 0 40px -10px var(--gold)}.kkt-root .as-cap {position:absolute;transform:translate(-50%,0);white-space:nowrap;opacity:0;
  transition:opacity .25s;font-size:15px;letter-spacing:.2em;font-weight:bold;
  text-shadow:0 2px 14px #000}.kkt-root .as-cap.in {opacity:1}.kkt-root .as-cap.toxic {color:var(--bad)}.kkt-root .as-cap.instant {color:var(--gold)}.kkt-root /* WHAT THE CARD DOES — under the card,
.kkt-root over the greyed-out half,
.kkt-root on its own
   backing so it is readable. Two lines or more as needed. */
/* THE STEP PANEL — a card's effects offered as buttons: use one,
.kkt-root the other,
.kkt-root both,
.kkt-root or neither. Under the card,
.kkt-root on the half the action has greyed out. */
.as-steps {position:absolute;bottom:3%;transform:translateX(-50%);
  width:min(360px,46%);opacity:0;transition:opacity .25s;pointer-events:auto;
  background:rgba(10,7,18,.95);border:1px solid var(--gold-dim);border-radius:14px;
  padding:11px 13px 12px;box-shadow:0 12px 30px rgba(0,0,0,.85)}.kkt-root .as-steps.in {opacity:1}.kkt-root .as-step {display:flex;gap:7px;align-items:stretch}.kkt-root .as-go {flex:1;font-family:inherit;font-size:11px;letter-spacing:.07em;line-height:1.3;
  padding:8px 10px;border-radius:9px;cursor:pointer;text-align:left;
  background:linear-gradient(180deg,var(--panel-2),var(--panel));
  border:1px solid var(--gold-dim);color:var(--gold);transition:all .13s}.kkt-root .as-go:hover {border-color:var(--gold);box-shadow:0 0 0 1px var(--gold)}.kkt-root .as-skip {width:30px;border-radius:9px;cursor:pointer;font-family:inherit;font-size:12px;
  background:var(--panel);border:1px solid var(--edge);color:var(--muted)}.kkt-root .as-skip:hover {border-color:var(--bad);color:var(--bad)}.kkt-root .as-step.armed .as-go {background:var(--gold);color:#1b1206;border-color:var(--gold);
  box-shadow:0 0 22px -6px var(--gold)}.kkt-root .as-step.done .as-go {color:var(--good);border-color:rgba(111,220,140,.5);
  background:rgba(111,220,140,.1);cursor:default}.kkt-root .as-step.done .as-skip,
.kkt-root .as-step.skipped .as-skip {display:none}.kkt-root .as-step.skipped .as-go {opacity:.4;text-decoration:line-through;cursor:default}.kkt-root .as-done {width:100%;margin-top:10px;padding:7px 0;border-radius:9px;cursor:pointer;
  font-family:inherit;font-size:10px;letter-spacing:.2em;
  background:var(--panel-2);border:1px solid var(--edge);color:var(--ink)}.kkt-root .as-done:hover {border-color:var(--gold);color:var(--gold)}.kkt-root /* the branching choices: Menace 1's direction,
.kkt-root Menace 3's second roll */
.as-choice {display:flex;gap:7px;align-items:center;margin-top:9px;flex-wrap:wrap}.kkt-root .as-choice > span {font-size:9px;letter-spacing:.18em;color:var(--muted);width:100%}.kkt-root .as-dir {flex:1;padding:7px 8px;border-radius:9px;cursor:pointer;font-family:inherit;
  font-size:10px;letter-spacing:.08em;background:var(--gold);border:1px solid var(--gold);
  color:#1b1206}.kkt-root .as-dir.ghost {background:var(--panel);color:var(--ink);border-color:var(--edge)}.kkt-root .as-dir:hover {filter:brightness(1.12)}.kkt-root /* a die that can be chosen for the armed effect */
.bdot.pickable {cursor:pointer;animation:hipulsegold 1s ease-in-out infinite;border-radius:50%}.kkt-root /* a die in flight between Factions,
.kkt-root and a card off the deck */
.diefly {position:fixed;z-index:400;pointer-events:none;
  filter:drop-shadow(0 0 18px rgba(242,201,76,.8)) drop-shadow(0 8px 16px rgba(0,0,0,.9))}.kkt-root .diefly svg {width:100%;height:100%;display:block}.kkt-root .cardfly {position:fixed;z-index:400;pointer-events:none}.kkt-root .cardfly img {width:100%;height:100%;display:block;border-radius:7px;
  border:1px solid var(--gold);box-shadow:0 12px 30px rgba(0,0,0,.9)}.kkt-root .hi.landed {animation:none;box-shadow:0 0 0 4px var(--gold),0 0 40px 0 rgba(242,201,76,.6);
  transition:box-shadow .6s}.kkt-root .lccrowd {width:100%;margin-top:9px;padding:8px 0;border-radius:9px;cursor:pointer;
  font-family:inherit;font-size:10px;letter-spacing:.14em;background:var(--panel-2);
  border:1px solid var(--edge);color:var(--ink)}.kkt-root .lccrowd:hover {border-color:var(--gold);color:var(--gold)}.kkt-root .as-effect {position:absolute;bottom:4%;transform:translateX(-50%);
  width:min(340px,44%);text-align:center;opacity:0;transition:opacity .25s;
  background:rgba(10,7,18,.92);border:1px solid var(--gold-dim);border-radius:12px;
  padding:9px 14px;box-shadow:0 10px 26px rgba(0,0,0,.8)}.kkt-root .as-effect.in {opacity:1}.kkt-root /* one line per effect; the joiner sits between them,
.kkt-root so a two-part card reads
   as two parts rather than one sentence wrapped wherever it ran out of room */
.as-line {font-size:12px;line-height:1.35;letter-spacing:.06em;color:var(--gold)}.kkt-root .as-join {font-size:9px;letter-spacing:.24em;color:var(--muted);margin:4px 0 3px;
  display:flex;align-items:center;gap:8px;justify-content:center}.kkt-root .as-join::before,
.kkt-root .as-join::after {content:"";height:1px;flex:1;
  background:linear-gradient(90deg,transparent,var(--gold-dim),transparent)}.kkt-root /* a die on its way home to its owner */
.diehome {position:fixed;z-index:400;pointer-events:none;
  filter:drop-shadow(0 6px 14px rgba(0,0,0,.9))}.kkt-root .diehome svg {width:100%;height:100%;display:block}.kkt-root .bdot.retr-target {animation:hipulsegold 1s ease-in-out infinite;border-radius:50%}.kkt-root /* the retrieve row in the card lab */
.lctitle2 {margin:16px 0 8px;font-size:9px;letter-spacing:.22em;color:var(--muted);
  text-align:center;display:flex;align-items:center;gap:9px}.kkt-root .lctitle2::before,
.kkt-root .lctitle2::after {content:"";height:1px;flex:1;
  background:linear-gradient(90deg,transparent,var(--edge),transparent)}.kkt-root .lcrow {display:grid;grid-template-columns:repeat(4,1fr);gap:8px}.kkt-root .lcret {padding:7px 0;border-radius:9px;font-family:inherit;font-size:10px;letter-spacing:.1em;
  cursor:pointer;background:var(--panel-2);color:var(--acc);
  border:1px solid color-mix(in srgb,var(--acc) 45%,transparent)}.kkt-root .lcret:hover {border-color:var(--acc);box-shadow:0 0 0 1px var(--acc)}.kkt-root /* the table mid-game */
.bcard {position:absolute;border-radius:5px;overflow:hidden;box-shadow:0 3px 10px rgba(0,0,0,.7)}.kkt-root .bcard img {width:100%;height:100%;object-fit:cover;display:block}.kkt-root .bdot {position:absolute;width:5.2%;aspect-ratio:1;transform:translate(-50%,-50%);
  filter:drop-shadow(0 2px 4px rgba(0,0,0,.85))}.kkt-root .bdot svg {width:100%;height:100%;display:block}.kkt-root /* ==========================================================================
   TOXIC REPEL — the die was too toxic for any card to bear,
.kkt-root so the card it
   lands on is swallowed by a green cloud and a fresh one is dealt in.
   ========================================================================== */
.toxcloud {position:absolute;z-index:8;pointer-events:none;border-radius:10px;
  overflow:visible}.kkt-root .toxcloud i {position:absolute;border-radius:50%;
  background:radial-gradient(circle at 36% 32%,#b6ff8a,#4fbf3a 45%,rgba(30,90,20,0) 72%);
  opacity:0;animation:puff 1.9s cubic-bezier(.25,.7,.35,1) forwards;
  mix-blend-mode:screen;filter:blur(1px)}
@keyframes puff{
  0%  {opacity:0;transform:translate(-50%,-50%) scale(.2)}
  22% {opacity:.95;transform:translate(-50%,-50%) scale(1)}
  66% {opacity:.8; transform:translate(-50%,-50%) scale(1.25)}
  100%{opacity:0;  transform:translate(-50%,-50%) scale(1.5)}
}
/* the card itself curls up and goes */
@keyframes toxgo{
  0%  {filter:none;transform:none;opacity:1}
  25% {filter:hue-rotate(80deg) saturate(2.2) brightness(.85)}
  55% {filter:hue-rotate(95deg) saturate(2.6) brightness(.7);
       transform:rotate(-4deg) scale(.96)}
  100%{filter:hue-rotate(95deg) saturate(3) brightness(.4);
       transform:rotate(-12deg) scale(.62) translateY(14px);opacity:0}
}.kkt-root .bcard.toxed {animation:toxgo 1.7s cubic-bezier(.4,0,.7,1) forwards;z-index:9}
/* and the replacement is dealt in */
@keyframes toxnew{from{opacity:0;transform:translateY(-26px) scale(.82) rotate(6deg)}
  to{opacity:1;transform:none}}.kkt-root .bcard.fresh {animation:toxnew .55s cubic-bezier(.2,1.2,.35,1)}.kkt-root .toxword {position:absolute;left:50%;top:-4%;transform:translate(-50%,-50%);z-index:10;
  font-size:13px;letter-spacing:.2em;font-weight:bold;color:#8dff6a;white-space:nowrap;
  text-shadow:0 0 14px rgba(80,230,60,.9),0 2px 8px #000;opacity:0;
  animation:toxword 1.9s ease-out forwards}
@keyframes toxword{0%{opacity:0;transform:translate(-50%,-50%) scale(.7)}
  18%{opacity:1;transform:translate(-50%,-50%) scale(1)}
  75%{opacity:1}100%{opacity:0;transform:translate(-50%,-90%) scale(1)}}.kkt-root /* ==========================================================================
   THE NINE CARDS — a tester. Its selectors are namespaced (#lab-cards,
.kkt-root .lc*)
   because this page also loads style.css for the shared header,
.kkt-root and that sheet
   carries the other mockup's card lab under the same names.
   ========================================================================== */
/* ==========================================================================
   THE NINE CARDS — a tester. Every Faction has the same nine,
.kkt-root so the picker
   shows one Faction's set and each one plays its own effect on the board.
   ========================================================================== */
/* flex + margin:auto rather than place-items:center — a centred grid item that
   is taller than its container clips at the TOP,
.kkt-root which is unreachable. */
#lab-cards {position:fixed;inset:0;z-index:500;display:flex;overflow:auto;padding:16px;
  background:rgba(6,4,12,.86);backdrop-filter:blur(3px);opacity:0;transition:opacity .22s}.kkt-root #lab-cards.in {opacity:1}.kkt-root /* All nine must be visible at once,
.kkt-root so the box is sized from the VIEWPORT
   HEIGHT: a card is 540x756,
.kkt-root so three rows need 4.35x the card width plus the
   title,
.kkt-root the labels and the padding. */
.lcbox {position:relative;margin:auto;padding:16px 20px;border-radius:20px;
  --cw:calc((88vh - 180px) / 4.35);
  width:min(620px, 92vw, calc(var(--cw) * 3 + 36px));
  background:linear-gradient(180deg,#2b2142,#1a1428 60%,#141020);
  border:1px solid #5a4a86;box-shadow:0 30px 80px rgba(0,0,0,.9);
  transform:scale(.94);transition:transform .24s cubic-bezier(.2,1.2,.35,1)}.kkt-root #lab-cards.in .lcbox {transform:scale(1)}.kkt-root .lctitle {font-size:10px;letter-spacing:.16em;color:var(--gold);text-align:center;
  margin:0 34px 14px}.kkt-root .lcgrid {display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}.kkt-root .lccard {display:flex;flex-direction:column;align-items:center;gap:5px;cursor:pointer;
  background:none;border:none;padding:0;font-family:inherit;width:100%;
  transition:transform .14s}.kkt-root .lccard:hover {transform:translateY(-5px)}.kkt-root .lccard img {width:100%;border-radius:9px;border:1px solid #8a7746;display:block;
  box-shadow:0 10px 26px rgba(0,0,0,.75);transition:box-shadow .14s}.kkt-root .lccard:hover img {box-shadow:0 14px 34px rgba(0,0,0,.9),0 0 22px -6px var(--gold)}.kkt-root .lcn {font-size:10px;letter-spacing:.18em;color:var(--gold)}.kkt-root .lce {font-size:8px;line-height:1.3;color:#b9abd6;text-align:center}.kkt-root .lcx {position:absolute;top:12px;right:14px;width:28px;height:28px;border-radius:8px;
  background:var(--panel);border:1px solid var(--edge);color:var(--ink);cursor:pointer;
  font-family:inherit}.kkt-root .lcx:hover {border-color:var(--gold);color:var(--gold)}

/* ---------------------------------------------------------------------------
   MOUNTING. The mockup owned the whole page; here the design sits inside the
   arcade's #table-wrap, under its header. It takes the viewport below that
   header and nothing wider, so the stage cannot push a horizontal scrollbar
   onto the page the way it did on first mount.
   --------------------------------------------------------------------------- */
.kkt-root {
  position: absolute; inset: 0;
  overflow: hidden;
  background: var(--bg, #12101a);
  z-index: 5;
}
.kkt-root #lab-stage { position: absolute; inset: 0; overflow: hidden; }
body.kkt-on #app { padding-left: 0; }
body.kkt-on { overflow: hidden; }

/* --- the seat toggle, the version Stefano picked -------------------------- */
.kkt-root .kkt-toggle,
.kkt-root .kkt-toggle-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 21px; height: 21px;
  font-size: 11px; line-height: 1;
  color: #16121f;
  background: var(--acc, #e072c2);
  border: none; border-radius: 5px;
  box-shadow: 0 1px 3px rgba(0,0,0,.6);
  transition: transform .12s ease, filter .12s ease;
}
.kkt-root .oseat:hover .kkt-toggle,
.kkt-root .kkt-toggle-btn:hover { filter: brightness(1.15); transform: scale(1.08); }
/* A side seat is rotated to run down its edge; the arrow means something in
   SCREEN space, so it is counter-rotated back. */
.kkt-root .oseat-left  .kkt-toggle { transform: rotate(-90deg); }
.kkt-root .oseat-right .kkt-toggle { transform: rotate(90deg); }
.kkt-root .oseat-left:hover  .kkt-toggle { transform: rotate(-90deg) scale(1.08); }
.kkt-root .oseat-right:hover .kkt-toggle { transform: rotate(90deg) scale(1.08); }

/* --- Gathering cards sit as if dealt by hand ------------------------------ */
.kkt-root #b-cards .bcard img {
  transform-origin: 50% 50%;
  transform: rotate(var(--tilt, 0deg));
  transition: transform .14s ease;
}
.kkt-root #b-cards .bcard:hover img { transform: rotate(0deg) scale(1.015); }

/* Transparent hit areas over the printed Faction wedges — ALLOCATE needs a
   target on the board itself. Positioned in percentages of the art like every
   other overlay. */
.kkt-root #kkt-zonehits { position: absolute; inset: 0; pointer-events: none; }
.kkt-root .kzhit {
  position: absolute; pointer-events: auto; cursor: pointer;
  border-radius: 5px;
  transition: box-shadow .12s ease, background .12s ease;
}
.kkt-root .kzhit:hover {
  background: rgba(242,201,76,.08);
  box-shadow: inset 0 0 0 2px rgba(242,201,76,.55);
}

/* --- the prompt bar ------------------------------------------------------
   layouts.html kept the prompt in its own #topbar. The arcade page supplies the
   header instead, so the design carries its own bar just under it — otherwise
   every "rolled a 3, now click a Gathering card" was written to an element that
   is not on the page. */
.kkt-root #kkt-promptbar {
  /* A ROW OF THE PAGE, NOT A PANEL FLOATING OVER IT. It was an inset box with
     its own rounded gold outline, which drew a frame around a space and then
     hung that space over the table — so it covered the top seat's chip and the
     game began underneath it. It is a band now: edge to edge, flush under the
     header, square, and the gold line that used to run under the header is its
     own bottom border. Everything else on the table is pushed below it by its
     measured height (--kkt-bar-h, set in kkt-view.js reserveHostSpace). */
  position: absolute; top: 0; left: 0; right: 0;
  justify-content: center;
  z-index: 60;
  display: flex; align-items: center; gap: 14px;
  padding: 7px 18px;
  background: linear-gradient(180deg, #221c33, #16121f);
  border: 0; border-bottom: 1px solid var(--gold-dim, #8a7325); border-radius: 0;
  box-shadow: 0 6px 20px rgba(0,0,0,.45);
  font: 700 12px/1.3 'Courier New', Courier, monospace;
  color: #f1ead9; letter-spacing: .03em;
}
.kkt-root #kkt-cancel {
  flex: 0 0 auto; cursor: pointer;
  background: #3a1620; color: #ffb4b4;
  border: 1px solid #77323f; border-radius: 7px;
  padding: 4px 9px; font: 700 9.5px/1 'Courier New', Courier, monospace;
  letter-spacing: .09em;
}
.kkt-root #kkt-cancel:hover { border-color: #e0685c; color: #fff; }
.kkt-root #kkt-cancel.hidden { display: none; }

/* The top seat sits under the prompt bar rather than across it. */
/* (Removed: `.oseat-top {top:52px}` and `.opp-top {top:46px}`. Nudging the
   opponent furniture down to clear the prompt bar moved it WITHOUT moving the
   board, so the top seat came to lie across the Gathering art and an open top
   board ran 16px into the table. The bar's height is now reserved on the stage
   instead — see --kkt-bar-h below — so the mockup's own geometry holds.) */

/* The canvas page's own controls are re-shown by the game whenever an action
   starts, so hiding them once at mount does not hold — they need a rule.
   The design carries its own prompt bar and its own END THIS ACTION. */
body.kkt-on #btn-endcluster,
body.kkt-on #mp-rail,
body.kkt-on #zoom-gathering-tools,
body.kkt-on #hand-quad,
body.kkt-on #actionbar,
body.kkt-on #board { display: none !important; }

/* --- PLAYED, in its printed rectangle ------------------------------------
   The middle of the Krafting is printed as a dashed rectangle around an orange
   diamond; that is where played cards land. Positioned in percentages of the
   art like every other overlay. */
.kkt-root #kkt-played {
  position: absolute; left: 67.6%; top: 29.5%; width: 14.8%; height: 41%;
  /* ABOVE the Faction hit layer: the pile sits in the middle of the Krafting,
     under a wedge's click area, so a hover meant for it was landing on the
     wedge and the peek never opened. */
  z-index: 9; pointer-events: auto;
  display: flex; align-items: center; justify-content: center;
}
/* …but an EMPTY pile is not a target and must not steal a wedge's clicks. */
.kkt-root #kkt-played.is-empty { pointer-events: none; }
.kkt-root #kkt-played img {
  width: 100%; height: 100%; object-fit: contain; display: block;
  border-radius: 4px; filter: drop-shadow(0 3px 9px rgba(0,0,0,.65));
}
.kkt-root .kkt-played-lbl {
  position: absolute; left: 50%; bottom: 2%; transform: translateX(-50%);
  padding: 2px 7px 2.5px;
  font: 700 8.5px/1 'Courier New', Courier, monospace;
  letter-spacing: .12em; color: #f4ecd8;
  background: rgba(12,10,20,.88);
  border: 1px solid #3a3150; border-radius: 4px; white-space: nowrap;
}
.kkt-root .kkt-played-n {
  position: absolute; top: 2%; right: 2%;
  min-width: 18px; padding: 2px 5px;
  font: 700 10px/1.3 'Courier New', Courier, monospace;
  text-align: center; color: #12101a; background: #f2c94c;
  border-radius: 9px; box-shadow: 0 1px 4px #000a;
}

/* --- the board's cards and dice must be CLICKABLE ------------------------
   layouts.css sets `#b-cards,#b-dice,#daystone { pointer-events:none }`. In the
   mockup that is correct: its Gathering cards are decorative, because its demo
   script drove every action and nobody ever clicked one.

   In a live game they are the targets. Influencing a card, retrieving a die —
   both are a click on this layer. With pointer-events off, every click fell
   through to the board IMAGE underneath, which is why a rolled die could not be
   placed on anything.

   The LAYER stays transparent to the mouse so the printed board still shows
   through the gaps; the cards and dice themselves opt back in. */
.kkt-root #b-cards .bcard { pointer-events: auto; cursor: pointer; }
.kkt-root #b-dice .bdot[data-die-id] { pointer-events: auto; cursor: pointer; }

/* One deterministic click target per Gathering slot, above the card art, any
   die resting on it and the pulsing highlight — all three share that rectangle,
   so which one took a click depended on stacking order. */
.kkt-root #kkt-slothits { position: absolute; inset: 0; z-index: 8; pointer-events: none; }
.kkt-root .kslothit {
  position: absolute; pointer-events: auto; cursor: pointer;
  border-radius: 6px;
  transition: box-shadow .1s ease;
}
.kkt-root .kslothit:hover { box-shadow: inset 0 0 0 3px rgba(242,201,76,.75); }
/* A die on a card must still be clickable for RETRIEVE, so it sits above. */
.kkt-root #b-dice { z-index: 9; }

/* Empty, the printed diamond shows through — only the label and the count sit
   on top. An <img src=""> renders as a broken-image icon, so the element is
   hidden outright rather than blanked. */
.kkt-root #kkt-played.is-empty img { display: none; }
.kkt-root #kkt-played img[hidden] { display: none; }

/* The printed board is laid out ABOVE your own board, never under it.
   #lab-host floats at the bottom with z-index 10 and #lab-table had no bottom
   padding, so the board ran beneath it and the lower half of the bottom row of
   Gathering cards was unclickable — slots 3-5 dead, 0-2 fine.
   --kkt-host-h is measured from the host itself, because its height changes as
   it opens and collapses. */
/* (no bottom padding: the board keeps its size and your board overlays it,
   stepping aside when you act — see kkt-adapter.js) */

/* --- your own board must not swallow the table underneath it ---------------
   #lab-host is an absolutely-positioned full-width box at the bottom of the
   stage with z-index 10. Its BOX covers the lower part of the printed board
   even when the mat inside it is collapsed — so the bottom row of Gathering
   cards (slots 3-5) was unclickable below its midline while the top row was
   fine. Exactly the reported symptom.

   The box stops taking clicks; the mat inside it takes them as before. Nothing
   moves and nothing is resized — the board keeps its full size and your board
   still overlays it, which is the design. */
.kkt-root #lab-host { pointer-events: none; }
.kkt-root #lab-host > * { pointer-events: auto; }

/* --- one top line across your board --------------------------------------
   .xg bottom-aligns its blocks, so as Power Krystals accumulate the Krown grows
   and the whole block slides DOWN relative to the dice, the hand and the
   actions. They should all hang from the same top line whatever the Krown is
   carrying. */
.kkt-root .xg { align-items: flex-start; }
.kkt-root .xg > * { align-self: flex-start; }


/* The swatter is parked directly ABOVE the deck — the one column with clear
   space over it. Absolute, anchored to the column's own top edge, so it can
   appear and disappear without shifting the three piles. */



/* --- YOUR BOARD IS ALWAYS ON TOP -----------------------------------------
   #actstage (the rolled die, its caption, a played card) sits at z-index 150
   INSIDE the board wrapper, so it was painting over the player boards: a die
   and the words ROLLED 1 landed on top of your own mat. Nothing on the table
   may cover a board. */
.kkt-root #lab-host { z-index: 200; }
.kkt-root .opp      { z-index: 160; }

/* --- the caption gets its own strip --------------------------------------
   Directly under the die it sat on the played card in the middle of the
   Krafting and could not be read. It now drops to the foot of the half with a
   backing behind it, the same way a card's effect lines do. */
.kkt-root .as-cap.band {
  top: auto; bottom: 4%;
  transform: translateX(-50%);
  padding: 7px 16px; border-radius: 10px;
  background: rgba(10,8,16,.93);
  border: 1px solid var(--edge);
  box-shadow: 0 10px 26px rgba(0,0,0,.8);
}

/* The played card is part of the Krafting and greys out with it. It sits above
   the scrim (it has to, to read at all normally), so it is dimmed directly. */
.kkt-root #boardwrap.dim-kraft #kkt-played {
  opacity: .16; filter: grayscale(.9); transition: opacity .25s, filter .25s;
}
.kkt-root #kkt-played { transition: opacity .25s, filter .25s; }


/* --- THE GREY WALL IS A WALL --------------------------------------------
   Everything printed or placed on the half being greyed out goes UNDER it —
   cards, dice, the played card. Only the die being rolled and its label are
   above it, and those live in #actstage at 150. #b-dice had been lifted to 9
   so a die on a card stays clickable for RETRIEVE, which also lifted it clear
   of the scrim: a die sat lit on a blacked-out Krafting. */
.kkt-root .bscrim { z-index: 40; }
.kkt-root #hi-slots, .kkt-root #hi-zones { z-index: 41; }
/* dimmed by the wall now, so the direct dimming is no longer needed */
.kkt-root #boardwrap.dim-kraft #kkt-played { opacity: 1; filter: none; }

/* --- the narration banner is not allowed near your board ----------------
   It flew in bottom-right, which under this design is your hand and your
   action rail. It goes to the free column beside the board instead, under the
   deck, where nothing else ever sits. */
/* Nothing floats any more — every notification is announced in the prompt bar,
   which is the one strip of the screen no board ever reaches. */
body.kkt-on #toast-host { display: none; }
/* NO NOTIFICATION BAR. Everything a notice used to say is already on the
   screen: the top bar names the player and the action, the board shows the
   move, the end-of-turn recap lists what it produced, and the log keeps the
   sentence. A strip of prose on top of all of that was noise. */


/* --- WHAT YOU MAY CLICK ---------------------------------------------------
   ALLOCATE, RETRIEVE and PLAY & RESOLVE now mark their own targets the way
   ROLL & INFLUENCE always marked the Gathering slots. */
.kkt-root .dgrid .d8.pickable {
  cursor: pointer; border-radius: 50%;
  animation: hipulsegold 1s ease-in-out infinite;
}
.kkt-root .dgrid .d8.chosen {
  filter: drop-shadow(0 0 12px var(--gold)) drop-shadow(0 6px 7px rgba(0,0,0,.85));
  opacity: .35;
}
.kkt-root .arc .c.playable { cursor: pointer; }
.kkt-root .arc .c.playable::after {
  content: ''; position: absolute; inset: -3px; border-radius: 9px;
  border: 2px solid var(--gold); pointer-events: none;
  animation: playglow 1.3s ease-in-out infinite;
}
@keyframes playglow {
  0%, 100% { opacity: .35; box-shadow: 0 0 0 0 rgba(242,201,76,0); }
  50%      { opacity: 1;   box-shadow: 0 0 16px -2px rgba(242,201,76,.75); }
}


/* --- A PEEK, ON HOVER -----------------------------------------------------
   Rest on a card for two seconds and it opens in the middle of the table, over
   a scrim that puts every other card behind it. It lives INSIDE the board, so
   it is the same size relative to the table on a laptop and on a 27-inch
   monitor — beside the cursor it was a fixed pixel height, which is why it
   looked like a different feature on every screen. */
.kkt-root .kkt-peek {
  position: absolute; inset: 0; z-index: 40; display: none;
  place-items: center; pointer-events: none;
  background: rgba(6, 4, 12, .78);
  backdrop-filter: blur(2px);
  opacity: 0; transition: opacity .28s ease;
}
.kkt-root .kkt-peek.in { opacity: 1; }
.kkt-root .kkt-peek .pk-box {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  transform: scale(.92); transition: transform .28s cubic-bezier(.2,.9,.3,1);
}
.kkt-root .kkt-peek.in .pk-box { transform: none; }
.kkt-root .kkt-peek .pk-cap {
  font-size: clamp(8px, .9vw, 11px); letter-spacing: .18em;
  color: var(--gold, #f2c94c); text-align: center;
}
.kkt-root .kkt-peek .pk-row { display: flex; gap: 2%; align-items: center; }
/* A card is a share of the BOARD's height, so one card is always the same size
   and a run of them shrinks to fit rather than running off the edge. */
.kkt-root .kkt-peek img {
  height: var(--pk-h, 300px); width: auto; display: block;
  border-radius: 10px; border: 1px solid #8a7746;
  box-shadow: 0 16px 40px rgba(0,0,0,.8);
}
/* the PLAYED pile is a control now — it says it can be looked at */
.kkt-root #kkt-played:not(.is-empty) { cursor: zoom-in; }

/* --- THE DAY OF KRYSTALIA -------------------------------------------------
   Six printed positions round the rim of the Krafting, and the stretches of rim
   between them. Each one lights up as the Day Stone leaves it, so the board
   fills as the Day fills and the reshuffle can be seen coming. */
.kkt-root #daystone .dsq {
  position: absolute; width: 2.1%; aspect-ratio: 1;
  transform: translate(-50%, -50%) rotate(45deg);
  border: 1px solid rgba(242,201,76,.22); border-radius: 2px;
  background: rgba(242,201,76,.05);
  transition: background .5s, box-shadow .5s, border-color .5s;
}
.kkt-root #daystone .dsq.lit {
  border-color: rgba(242,201,76,.9);
  background: rgba(242,201,76,.30);
  box-shadow: 0 0 14px 3px rgba(242,201,76,.5), inset 0 0 8px rgba(255,236,170,.6);
}
.kkt-root #daystone .dseg {
  position: absolute; border-radius: 3px;
  background: rgba(242,201,76,0);
  transition: background .55s, box-shadow .55s;
}
.kkt-root #daystone .dseg.lit {
  background: rgba(242,201,76,.45);
  box-shadow: 0 0 12px 2px rgba(242,201,76,.45);
}
/* the circle closed: the whole rim burns for a moment before it drains */
.kkt-root #daystone.full .dsq.lit,
.kkt-root #daystone.full .dseg.lit { animation: dayfull 1.1s ease-in-out infinite; }
@keyframes dayfull {
  0%, 100% { filter: brightness(1); }
  50%      { filter: brightness(1.75); }
}
/* the deck taking the piles back */
.kkt-root #deck-draw.shuffling .dcard { animation: deckshuffle .19s ease-in-out 4; }
@keyframes deckshuffle {
  0%   { transform: translate(0,0) rotate(0deg); }
  25%  { transform: translate(-4px,-2px) rotate(-3deg); }
  50%  { transform: translate(3px,1px) rotate(2.5deg); }
  75%  { transform: translate(-2px,2px) rotate(-1.5deg); }
  100% { transform: translate(0,0) rotate(0deg); }
}


/* --- THE GAME ENDS -------------------------------------------------------
   The canvas drew this and the canvas is hidden here, so a finished game left
   the table live with every action button still inviting a click. */
.kkt-root #kkt-over {
  position: absolute; inset: 0; z-index: 420;
  display: grid; place-items: center;
  background: rgba(5,3,10,.88);
  opacity: 0; transition: opacity .4s;
}
.kkt-root #kkt-over.in { opacity: 1; }
.kkt-root .ko-box {
  min-width: 380px; padding: 26px 34px 24px; text-align: center;
  background: linear-gradient(180deg,#1b1329,#140e22);
  border: 1px solid var(--gold); border-radius: 16px;
  box-shadow: 0 24px 70px rgba(0,0,0,.85), 0 0 60px -20px var(--gold);
}
.kkt-root .ko-av    { font-size: 46px; line-height: 1; }
.kkt-root .ko-title { margin-top: 8px; font-size: 27px; letter-spacing: .12em;
  font-weight: bold; color: var(--gold); }
.kkt-root .ko-sub   { margin-top: 5px; font-size: 12px; color: var(--muted); }
.kkt-root .ko-scores { margin: 18px 0 16px; display: flex; flex-direction: column; gap: 5px; }
.kkt-root .ko-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 12px; border-radius: 9px;
  background: rgba(255,255,255,.03);
  border: 1px solid var(--edge);
}
.kkt-root .ko-row.win { border-color: var(--acc); box-shadow: 0 0 0 1px var(--acc); }
.kkt-root .ko-face { font-size: 17px; }
.kkt-root .ko-name { flex: 1; text-align: left; font-size: 12.5px;
  letter-spacing: .06em; color: var(--acc); }
.kkt-root .ko-k    { font-size: 12px; font-weight: bold; color: #140f1e;
  background: var(--acc); padding: 1px 9px; border-radius: 10px; }
.kkt-root .ko-again {
  cursor: pointer; padding: 9px 26px; border-radius: 9px;
  background: var(--gold); color: #1b1206; border: none;
  font: bold 12px/1 'Courier New', Courier, monospace; letter-spacing: .14em;
}
.kkt-root .ko-again:hover { filter: brightness(1.12); }
/* and the action rail stops asking to be clicked */
.kkt-root #kkt-over ~ * .verbs, .kkt-root #lab-stage:has(#kkt-over) .verbs { pointer-events: none; opacity: .35; }

/* A die ON A GATHERING CARD sits in the card's 3x3 grid (d8.js slotDiePos), so
   it is sized to fit three across a 14.1%-wide slot rather than to be read on
   its own. Dice in the Krafting keep their full size — those zones re-space
   themselves and have the room. */
.kkt-root #b-dice .bdot.gd { width: 3.9%; }

/* The Faction name on a highlighted wedge was 9px text in a 6px box: #boardwrap
   carries line-height:0 so the image has no descender gap, and .tag inherited
   it, so every name was sliced through the middle. */
.kkt-root #hi-zones .tag,
.kkt-root #hi-slots .tag { line-height: 1.25; overflow: visible; }

/* --- an action you cannot take is not offered -----------------------------
   Two reasons, both greyed: 'resource' (nothing to do it with) and 'illegal'
   (resources but no legal target). Retrieve on turn one is the first kind —
   there are no dice on the board to take back. */
.kkt-root .vb.is-off {
  opacity: .34; cursor: not-allowed; filter: grayscale(.85);
  border-color: #3a3150 !important; box-shadow: none !important;
}
.kkt-root .vb.is-off:hover { transform: none; border-color: #3a3150 !important; }

/* WHICH CARDS CAN BE PLAYED — a small mark, nothing more.
   Ernestas: never touch the saturation, the faction colour has to stay legible.
   Stefano: the forbidden circle was too dominant and hid the art, and the red
   halo was barely visible and helped nobody. So: one ⚠️ on the LEFT, sitting
   just above the card's type band where it still shows with the hand fanned,
   and the tooltip does the explaining. */
.kkt-root .arc .c.is-unplayable { cursor: help; }
.kkt-root .arc .c.is-unplayable::after {
  content: '⚠️';
  position: absolute; left: 5%; top: 4%;
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  font-size: 19px; line-height: 1;
  /* A black disc behind it so it reads against any card art, and clear of the
     type band below — the mark was legible only if you already knew it was
     there. */
  background: radial-gradient(circle, rgba(0,0,0,.92) 62%, rgba(0,0,0,.72) 100%);
  border-radius: 50%;
  box-shadow: 0 2px 6px rgba(0,0,0,.85);
  pointer-events: none; z-index: 3;
}
.kkt-root .arc .c.playable img {
  outline: 2px solid var(--gold, #f2c94c);
  outline-offset: -2px;
  box-shadow: 0 0 16px -2px rgba(242,201,76,.75);
  border-radius: 6px;
}

/* (The desktop icons are NOT resized. The request to double them was about the
   phone, where they are 20px; layouts.css sets these at 46px and that is the
   approved design. Changing them here was mine, and wrong.) */


/* ---------------------------------------------------------------------------
   ROOM FOR THE PROMPT BAR.

   layouts.html carried the prompt in its own #topbar, which the arcade page
   replaces with its header — so the design needs a bar of its own, and the
   mockup's geometry knows nothing about it. Reserving its height on the stage
   moves EVERY position inside down together: the seats, an opened opponent
   board, the table. Nudging individual elements moved the furniture and left
   the board behind, which is what put the top seat across the Gathering art.

   The bar itself must also sit above an opened side board (z-index 160).
   --------------------------------------------------------------------------- */
/* THE PROMPT BAR OWNS THE TOP STRIP, and nothing else may sit in it.
   #lab-table and the seat tokens are absolutely positioned, so they resolve
   against the stage's PADDING BOX — a padding-top on the stage reserved nothing
   from them and the bar came down across the top seat's chip. Both are pushed
   by the bar's own height instead, so they move together and the mockup's
   geometry between them is untouched.

   EVERY game element, not just the board column. The left and right SEAT
   tokens carried their own hardcoded top:52px (right only while the bar
   happened to be 52px tall), and the OPEN left/right boards ran top:0 —
   straight up behind the bar, which is how "Lady Krysalind · ALLOCATE" came
   to sit across her own mat's name. The bar's measured height (--kkt-bar-h,
   kkt-view.js reserveHostSpace — re-measured whenever the bar itself resizes)
   is the top edge of ALL of them now: whatever the bar holds, at whatever
   height, the whole row below starts under it. */
.kkt-root { --kkt-bar-h: 52px; }
.kkt-root #lab-stage { padding-top: var(--kkt-bar-h); }
.kkt-root #lab-table { top: calc(10px + var(--kkt-bar-h)); }
.kkt-root .oseat-top { top: calc(6px + var(--kkt-bar-h)); }
.kkt-root .oseat-left, .kkt-root .oseat-right { top: var(--kkt-bar-h); }
.kkt-root .opp-top,
.kkt-root .opp-left,
.kkt-root .opp-right { top: var(--kkt-bar-h); }

/* A CLICK THAT CANNOT BE TAKEN. A rolled 0 may only repel a card with no dice
   on it; the legal ones glow gold and an illegal one shakes rather than
   swallowing the click in silence. */
@keyframes kkt-refuse {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-5px); }
  45%      { transform: translateX(5px); }
  70%      { transform: translateX(-3px); }
}
.kkt-root .bcard.refused {
  animation: kkt-refuse .42s ease;
  box-shadow: 0 0 0 2px rgba(224,104,92,.9), 0 3px 10px rgba(0,0,0,.7);
}

/* WHOSE TURN IT IS, IN WORDS. The acting seat glowed, which is a convention
   nobody has been taught. */
.kkt-root .s-now {
  font-size: 8.5px; letter-spacing: .14em; font-weight: bold;
  color: #140f1e; background: var(--acc, #f2c94c);
  border-radius: 6px; padding: 2px 6px; white-space: nowrap;
}
.kkt-root .LX .s-now { background: var(--gold, #f2c94c); }
/* the rotated side tokens read down their own edge; the badge follows */
.kkt-root .oseat-left .s-now, .kkt-root .oseat-right .s-now { letter-spacing: .1em; }
.kkt-root #lab-stage.push-top #lab-table { padding-top: 214px; }
.kkt-root #kkt-promptbar { z-index: 400; }

/* The action button AS IT APPEARS IN THE RAIL, shown in the top bar — the same
   .vb component, just not clickable. The bar's three parts are the avatar, the
   name, and this. */
.kkt-root #kkt-prompt { display: flex; align-items: center; justify-content: center; gap: 14px; }
.kkt-root .bar-vb { pointer-events: none; min-width: 0; padding: 4px 12px 4px 8px; }
.kkt-root .bar-vb .vi { width: 34px; height: 34px; }
.kkt-root .bar-vb .vl { font-size: 9px; }


/* --- THE FLY SWATTER ------------------------------------------------------
   Big, on the right, above everything. It was parked over the deck column and
   moved off the left edge of the screen when the deck did — and at 34px it was
   a postage stamp for something you are meant to want to hit. */
.kkt-root .flyswat {
  position: fixed; right: 10px; top: 22%; left: auto; bottom: auto;
  z-index: 9000;
  padding: 14px 16px 12px; gap: 6px;
  border-radius: 16px;
  background: linear-gradient(180deg, rgba(42,32,64,.97), rgba(20,15,32,.97));
  border: 2px solid var(--gold-dim, #8a7325);
  box-shadow: 0 14px 40px rgba(0,0,0,.8), 0 0 28px -8px var(--gold, #f2c94c);
}
.kkt-root .flyswat svg { width: 76px; height: 102px; }
.kkt-root .flyswat span { font-size: 12px; letter-spacing: .24em; }
.kkt-root .flyswat:hover { border-color: var(--gold, #f2c94c); transform: scale(1.05); }
.kkt-root .flyswat:active { transform: scale(.97) rotate(-6deg); }

/* While a card's step panel is open it outranks your hand. #lab-host sits above
   #actstage so a die is never painted over a board — which also left the hand
   fan across the panel's own DONE, where four real clicks landed on a card. */
.kkt-root.carding #lab-host { z-index: 120; }

/* --- SOLO ROLL & INFLUENCE ------------------------------------------------
   Solo rolls up to three dice together, so the action has two states the
   multiplayer table never reaches: choosing the dice (ROLL SELECTED lives on
   the stage, where the dice are), and more than one rolled die waiting to be
   placed (each one can be picked up). Both reuse the stage the other actions
   already use; nothing else on the board moves. */
/* #actstage is pointer-events:none so the staged die never eats a click meant
   for the board underneath it. These two ARE the click, so they take it back. */
.kkt-root .as-roll, .kkt-root .as-die.as-pick {pointer-events:auto}
.kkt-root .as-roll {position:absolute;transform:translate(-50%,-50%) scale(.9);opacity:0;
  padding:12px 26px;border-radius:12px;cursor:pointer;font:800 15px/1 ui-sans-serif,system-ui;
  letter-spacing:.14em;background:var(--gold);color:#1b1206;border:0;
  box-shadow:0 10px 28px rgba(0,0,0,.65);transition:opacity .22s ease,transform .22s ease}
.kkt-root .as-roll.in {opacity:1;transform:translate(-50%,-50%) scale(1)}
.kkt-root .as-roll:disabled {background:var(--panel-2);color:var(--muted);cursor:default;box-shadow:none}
.kkt-root .as-roll:not(:disabled):hover {transform:translate(-50%,-50%) scale(1.05)}
/* A rolled die you may pick up. The chosen one is ringed in gold — the board's
   one colour for "this is what you are acting with". */
.kkt-root .as-die.as-pick {width:104px;height:104px;cursor:pointer}
.kkt-root .as-die.as-pick:hover {filter:drop-shadow(0 0 14px rgba(242,201,76,.75))}
.kkt-root .as-die.as-pick.chosen {filter:drop-shadow(0 0 18px rgba(242,201,76,.95))}

/* --- KRYSTALIA'S FAVOUR, SEEN -----------------------------------------------
   The engine raises a rolled 1 to a 2 and a 2 to a 3 in the same instant it
   rolls. The die now lands on the face it fell on and this +1 rises off it a
   beat later, as the face turns over — so a player with Favour on can see both
   what they rolled and what Favour did for them (issue #3).

   FIXED, not absolute, and on <body>: the same badge has to sit over a die on
   the staging layer AND over a die standing in a Faction on the board, which
   live in different positioned ancestors. */
.kkt-fav-pop {
  position: fixed; z-index: 9000; pointer-events: none;
  transform: translate(-50%, -50%);
  font: 900 30px/1 ui-sans-serif, system-ui, sans-serif;
  letter-spacing: .02em;
  color: var(--gold, #f2c94c);
  text-shadow: 0 2px 10px #000, 0 0 22px rgba(242, 201, 76, .85);
  --fav-rise: 30px;
  animation: kkt-favpop 1.2s cubic-bezier(.2, .9, .3, 1) forwards;
}
@keyframes kkt-favpop {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(.4); }
  16%  { opacity: 1; transform: translate(-50%, calc(-50% - var(--fav-rise) * .45)) scale(1.3); }
  50%  { opacity: 1; transform: translate(-50%, calc(-50% - var(--fav-rise))) scale(1); }
  100% { opacity: 0; transform: translate(-50%, calc(-50% - var(--fav-rise) * 1.9)) scale(.9); }
}
/* Too close to the top of the screen to rise — it drops instead. */
.kkt-fav-pop.down { animation-name: kkt-favpop-down; }
@keyframes kkt-favpop-down {
  0%   { opacity: 0; transform: translate(-50%, -50%) scale(.4); }
  16%  { opacity: 1; transform: translate(-50%, calc(-50% + var(--fav-rise) * .45)) scale(1.3); }
  50%  { opacity: 1; transform: translate(-50%, calc(-50% + var(--fav-rise))) scale(1); }
  100% { opacity: 0; transform: translate(-50%, calc(-50% + var(--fav-rise) * 1.9)) scale(.9); }
}
/* the die itself, turning over under it */
.kkt-root .as-die.favoured { animation: kkt-favdie .76s cubic-bezier(.3, 1.3, .4, 1); }
@keyframes kkt-favdie {
  0%   { transform: translate(-50%, -50%) scale(1) rotate(0); }
  40%  { transform: translate(-50%, -50%) scale(1.22) rotate(-8deg);
         filter: drop-shadow(0 0 24px rgba(242, 201, 76, .95)); }
  100% { transform: translate(-50%, -50%) scale(1) rotate(0); }
}
/* a die standing on the board (a Menace L3 re-roll) gets the glow without the
   scale — it is sitting in a Faction row and must not shove its neighbours. */
.kkt-root .bdot.favoured, .kkt-root .mdot.favoured {
  animation: kkt-favdot .76s ease-out;
}
@keyframes kkt-favdot {
  0%, 100% { filter: none; }
  45%      { filter: drop-shadow(0 0 18px rgba(242, 201, 76, .95)) brightness(1.3); }
}
