/* L.U.C.A. playtest HUD — Layout B ("the table").
   Implements design_handoff_luca_hud. Tokens inherited from the component
   system; no new colours.

   Load-bearing semantics — do not violate, these make states collide:
     amber          = live / actionable / over-capacity. Nothing decorative.
     135deg hatch   = spent / no-data / overridden. NEVER over-capacity.
     dashed edge    = area, not object.      solid edge = object.
     selection      = weight (3px), not colour  (greyscale: amber vs amber).
     colour never works alone — motif or ordinal always accompanies it.
*/
:root{
  --film:#141310; --film-deep:#100F0D; --film-panel:#1B1A16; --ink:#17150F;
  --bone:#EFE9D8; --bone2:#E6E0CD; --muted-bone:#8E8977;
  --dis-ink:#5C584C; --dis-edge:#3A372C;
  --amber:#F2C24E; --stock:#E7E1CD;
  --M:#F2C24E; --Sg:#5FBCC1; --S:#6A90C4; --D:#CF5B44; --R:#8A76C4;

  /* Play mode is a FIXED scale. A true-size table does not fit on the device
     (4 mats at life size = 640mm vs ~286mm of glass), so proofing is a
     separate view. Do not reintroduce a global actual-size toggle. */
  --mm:2.4px;

  --hatch:repeating-linear-gradient(135deg,
          rgba(23,21,15,.55) 0 2px, transparent 2px 6px);
}
*{box-sizing:border-box}
html,body{margin:0;padding:0;height:100%}
body{
  background:var(--film); color:var(--bone); overflow:hidden;
  font:400 14px/1.45 "Atkinson Hyperlegible",system-ui,sans-serif;
}
h1,h2,b,.bitter{font-family:Bitter,Georgia,serif;font-weight:700}
.mono{font-family:"IBM Plex Mono",ui-monospace,monospace;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase}
.dim{color:var(--muted-bone)}
.hidden{display:none !important}
.grow{flex:1}
a{color:var(--amber)}
button{font:inherit;font-size:12px;background:#26241D;color:var(--bone);
  border:1px solid var(--dis-edge);border-radius:2px;padding:5px 10px;cursor:pointer}
button:hover:not(:disabled){border-color:var(--muted-bone)}
button.primary{background:var(--amber);color:var(--ink);border-color:var(--amber);
  font-weight:700}
button:disabled{opacity:1;background:transparent;color:var(--dis-ink);
  border-color:var(--dis-edge);cursor:not-allowed}
input,select{font:inherit;font-size:13px;background:#0E0D0A;color:var(--bone);
  border:1px solid var(--dis-edge);border-radius:2px;padding:5px 8px}

/* ---------------------------------------------------------------- setup */
/* #setup is styled by THE FRONT DOOR block at the end of this file. The
   original rule lived here and set its own display/padding/overflow, which
   is exactly the kind of pair that silently half-applies. */
.setup-card{width:min(560px,100%);background:var(--film-panel);
  border:1px solid #2C2A22;border-radius:4px;padding:26px 28px}
.setup-card h1{font-size:30px;letter-spacing:.14em;margin:0 0 6px}
.sub{color:var(--muted-bone);font-size:12.5px;margin:0 0 20px}
.row{display:flex;align-items:center;gap:12px;margin:9px 0;font-size:13px}
.row>span:first-child{width:150px;color:var(--bone2)}
.cfg{margin:16px 0;border-top:1px solid #2C2A22;padding-top:12px}
.cfg summary{cursor:pointer;font-size:12px;color:var(--bone2)}
.cfg em{color:var(--muted-bone);font-style:normal}
.cfgrow{display:flex;gap:10px;align-items:flex-start;margin:11px 0}
.cfgrow label{flex:1;font-size:12.5px}
.cfgrow .help{display:block;color:var(--muted-bone);font-size:11px;margin-top:2px}

/* ------------------------------------------------------------------ lobby */
.orline{display:flex;align-items:center;gap:10px;margin:16px 0 12px;
  color:var(--muted-bone);font-size:11px}
.orline::before,.orline::after{content:"";flex:1;height:1px;background:#2C2A22}
#joinroom{width:100%}
#mkroom{width:100%;margin-top:6px}
.err{color:var(--D);font-size:12px;margin:10px 0 0}

.lobbyhead{display:flex;align-items:flex-start;gap:14px}
.lobbyhead h1{margin-bottom:2px}
.codebox{margin-left:auto;text-align:right;border:1px solid var(--amber);
  border-radius:3px;padding:6px 12px;background:rgba(242,194,78,.08)}
.codebox .mono{display:block;font-size:8.5px;letter-spacing:.24em}
.codebox b{font-family:"IBM Plex Mono",monospace;font-size:24px;
  letter-spacing:.16em;color:var(--amber);line-height:1.1}

#seatlist{margin:18px 0 14px;display:flex;flex-direction:column;gap:6px}
.seatrow{display:flex;align-items:center;gap:10px;padding:8px 10px;
  border:1px solid var(--dis-edge);border-radius:3px;background:#1E1C17}
.seatrow.mine{border-color:var(--amber);background:rgba(242,194,78,.07)}
.seatrow.bot{opacity:.72}
.seatrow .seatn{width:26px;font-size:10px;letter-spacing:.14em;
  color:var(--muted-bone)}
.seatrow .seatwho{flex:1;font-size:13px}
.seatrow .you{color:var(--amber);font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;margin-left:5px}
.seatrow button{font-size:11px;padding:3px 9px}

/* --------------------------------------------------------- game shell */
#game{display:flex;flex-direction:column;height:100%}
#forceband{background:var(--bone);color:var(--ink);font:500 11px/1 "IBM Plex Mono",monospace;
  letter-spacing:.2em;text-transform:uppercase;padding:7px 14px;display:flex;gap:14px}
body.forcing #game{box-shadow:inset 0 0 0 3px transparent;
  border:3px solid transparent;
  border-image:repeating-linear-gradient(135deg,var(--bone) 0 6px,var(--ink) 6px 12px) 3}

#topbar{position:relative;flex:0 0 auto;display:flex;align-items:center;gap:14px;padding:6px 14px;
  background:var(--film-panel);border-bottom:1px solid #26241D;font-size:11px}
.wordmark{font-size:13px;letter-spacing:.18em}
.envnow{color:var(--amber);font-family:"IBM Plex Mono",monospace;font-weight:500;
  letter-spacing:.14em;text-transform:uppercase;font-size:11px}
#topbar .tools{display:flex;gap:6px;align-items:center}
.tgl{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--bone2);
  border:1px solid var(--dis-edge);border-radius:2px;padding:4px 8px;cursor:pointer}
.tgl input{margin:0}
body.forcing .tgl{border-color:var(--bone);color:var(--bone)}

/* whose-turn pill — always visible in the top bar */
.turnpill{display:inline-flex;align-items:center;gap:6px;padding:3px 10px;
  border-radius:999px;border:1px solid var(--dis-edge);background:var(--film);
  font:600 11px/1 "IBM Plex Mono",monospace;letter-spacing:.06em;color:var(--bone2);
  white-space:nowrap}
.turnpill .tp-dot{width:9px;height:9px;border-radius:50%;background:var(--pc,#888)}
.turnpill.mine{background:var(--amber);border-color:var(--amber);color:var(--film)}
.turnpill.mine .tp-dot{background:var(--film)}

/* ------------------------------------------------------------ opponents */
#opponents{flex:0 0 auto;display:flex;gap:1px;background:#26241D;
  border-bottom:1px solid #26241D}
.opp{flex:1;background:var(--film);padding:7px 10px;display:flex;gap:10px;
  align-items:flex-start;min-width:0;position:relative}
/* the opponent on the clock: a colored edge + glow + corner tag */
.opp.onclock{box-shadow:inset 3px 0 0 var(--pc,#888),0 0 11px -5px var(--pc,#888);
  outline:1px solid var(--pc,#888);outline-offset:-1px}
.opp .onturnbadge{position:absolute;top:4px;right:8px;
  font:700 8px/1 "IBM Plex Mono",monospace;letter-spacing:.14em;color:var(--pc,#888)}
.opp .who{display:flex;align-items:center;gap:7px;min-width:0}
.opp .lin{font-family:Bitter,Georgia,serif;font-weight:700;font-size:12px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.opp .sc{font-family:Bitter,Georgia,serif;font-weight:700;font-size:16px;
  margin-left:auto}
.opp .meta{font-size:9.5px}
.oppcols{display:flex;flex-direction:column;gap:4px;min-width:0}

/* seat ring — colour + ordinal + fixed position (three cues) */
.ring{border-radius:50%;background:var(--film);display:grid;place-items:center;
  flex:0 0 auto;font-family:"IBM Plex Mono",monospace;font-weight:500;
  letter-spacing:0;line-height:1}
.ring.s4{outline:1.5px solid var(--bone);outline-offset:-1px}

/* genome thumbnail (opponents) */
.gthumb{display:grid;grid-template-columns:repeat(5,6px);gap:1.5px}
.gthumb i{height:6px;display:block;border-radius:1px}
/* promoter strip (opponents) */
.pstrip{display:flex;gap:2px}
.pstrip i{width:9px;height:9px;display:block;border-radius:1px}
.pstrip i.never{border:1px dashed var(--dis-edge)}
.pstrip i.live{background:var(--amber)}
.pstrip i.spent{background:var(--dis-edge);background-image:var(--hatch)}

/* --------------------------------------------------------------- market */
/* The forks are where every turn is spent -- but a mat is only as tall as a
   card plus its rail. Given the slack it stretched to 432px around a 201px
   card and the extra was dead. It hugs now; the board below takes the rest. */
#market{flex:0 0 auto;min-height:0;display:flex;flex-direction:column;
  background:var(--film-deep);border-top:1px solid #26241D;
  border-bottom:1px solid #26241D;padding:5px 14px 8px}
.bandlabel{font-size:10px;color:var(--muted-bone);margin-bottom:6px;flex:0 0 auto;
  display:flex;align-items:center;gap:8px;min-height:22px}
.bandrule{font-family:"Atkinson Hyperlegible",sans-serif;font-size:12.5px;
  color:var(--bone2);margin-right:6px}
.bandscore{font-family:"Atkinson Hyperlegible",sans-serif;font-size:12.5px;
  color:var(--amber)}
/* Current era as a chip; the full three open in a modal. */
.erabtn{margin-left:auto;display:flex;align-items:center;gap:8px;cursor:pointer;
  background:linear-gradient(90deg,
    color-mix(in srgb,var(--era,#888) 22%,var(--film-panel)),var(--film-panel));
  border:1px solid var(--era,var(--dis-edge));
  border-left:3px solid var(--era,var(--dis-edge));
  border-radius:3px;padding:4px 11px;color:var(--bone)}
.erabtn.e1{--era:var(--Sg)} .erabtn.e2{--era:var(--R)} .erabtn.e3{--era:var(--D)}
.erabtn .mono{font-size:9px;letter-spacing:.18em;color:var(--era)}
.erabtn b{font-family:Bitter,Georgia,serif;font-size:12.5px}
.erabtn:hover{filter:brightness(1.15)}
.erasmodal{margin-top:10px}
.erasmodal .eracard{opacity:1;min-width:0}
/* Mats abut with no gap and no seam — four segments of one chromosome. */
#forks{display:flex;align-items:stretch;position:relative;flex:0 0 auto;
  min-height:0;min-width:0;overflow-x:auto}
.fork{border:1px solid var(--dis-edge);border-right:none;position:relative;
  padding:5px 34px 6px 6px;min-width:0;display:flex;flex-direction:column;
  overflow:hidden}
.fork:last-child{border-right:1px solid var(--dis-edge)}
.fork.can{border-color:var(--amber);background:rgba(242,194,78,.06)}
.fork.can+.fork{border-left-color:var(--amber)}
.fork.sel{border-width:3px;padding:3px 32px 4px 4px}
.fork .flabel{font:500 8.5px/1 "IBM Plex Mono",monospace;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted-bone);margin-bottom:4px}
.fork.can .flabel{color:var(--amber)}
.fork .fcards{display:flex;gap:4px;flex:0 0 auto;align-items:flex-start}
.fork .here{font:500 8.5px/1 "IBM Plex Mono",monospace;letter-spacing:.16em;
  color:var(--dis-ink)}
/* strand: tiled background so the helix never letterboxes into islands */
/* One upright chromosome standing at the right edge of each mat. Vertical, so
   the rungs read at a glance and the mats are visibly separate segments. */
.strand{position:absolute;right:0;top:0;bottom:0;width:26px;z-index:0;
  background-repeat:repeat-y;background-position:right top;opacity:.85;
  pointer-events:none}

/* ---------------------------------------------------------------- cards */
/* Matched to the printed component: spine, specimen plate, name, effect band.
   The plate is where art lands; until it does, the family motif holds the
   space -- which is not the same as a hole holding it. */
.card{background:var(--stock);color:var(--ink);border-radius:2px;display:flex;
  overflow:hidden;flex:0 0 auto;position:relative}
/* Printed card face: the whole card IS the rendered print image. */
.card.printface{background:transparent;padding:0}
.card.printface .cardfull{width:100%;height:100%;object-fit:contain;display:block}
.card.printface.printmiss{align-items:center;justify-content:center;
  text-align:center;font:700 10px/1.2 system-ui;padding:4px}
.spine{flex:0 0 auto;display:flex;flex-direction:column;align-items:center;
  padding-top:2px;position:relative}
.spine .sz{font-family:Bitter,Georgia,serif;font-weight:700;line-height:.86}
.spine .tab{clip-path:polygon(0 0,74% 0,100% 50%,74% 100%,0 100%);
  display:flex;align-items:center;gap:2px;font:700 7px/1 "IBM Plex Mono",monospace}
.spine .sock{clip-path:polygon(0 0,100% 0,100% 100%,0 100%,0 68%,32% 50%,0 32%);
  background:var(--stock);color:var(--ink);display:flex;align-items:center;
  justify-content:flex-end;gap:2px;font:700 7px/1 "IBM Plex Mono",monospace}
/* The notch eats the left third, so the mark sits clear of it. On the printed
   card these two collided until the type came down; same fix, same reason. */
.spine .sock .ptico{margin-left:32%}
.spine .ptico{flex:0 0 auto;width:auto}
.spine .ptcode{flex:0 0 auto}
.spine .motif{position:absolute;bottom:3px;width:70%;height:auto;opacity:.9}
.cbody{flex:1;display:flex;flex-direction:column;min-width:0;padding:2px 5px 0;gap:1px}
/* FIXED ANCHORS. Everything used to key off the band, whose height varies with
   clause count, so the name floated to a different height on every card and a
   spread of cards read as ragged. The plate absorbs the slack instead. */
.cbody.anchored{padding-top:3px}
/* The plate no longer stretches to eat the leftover height: its shape is
   the page's shape now, so it sizes from its width and the name and the
   effect band take what is left. */
.cbody.anchored .plate{flex:0 0 auto;min-height:0}
.cbody.anchored .cname{order:2;flex:0 0 auto;margin:3px 0 2px}
.cbody.anchored .cband{order:3;flex:0 0 auto}

/* specimen plate */
.plate{position:relative;order:1;border:1px solid rgba(23,21,15,.45);
  background:rgba(23,21,15,.035);display:grid;place-items:center;
  overflow:hidden;min-height:0}
.plate .pmotif{width:42%;height:auto;opacity:.30}
/* The specimen plate: the whole lab-notes page, labels and arrows included,
   the same image that prints, and its paper kept.

   The frame is shaped to the PAGE rather than the page cropped to the frame.
   The art is 1024x983, essentially square; the plate used to be 99x131
   portrait, so the cream page could never fill it -- it floated in the middle
   with the card's darker stock showing above and below, which is what read as
   a white rectangle pasted onto a brown card. Given the page's own aspect the
   paper reaches all four edges and the plate simply IS a sheet of notebook
   paper, ruled lines running to the border.

   `cover` is safe now only because the ratios agree to within 4%; the labels
   sit in the left third and must never be cropped. */
.plate{aspect-ratio:1024/983;flex:0 0 auto}
.plate .partwork{width:100%;height:100%;object-fit:cover;object-position:center;
  display:block}
.plate .pslug{position:absolute;right:3px;bottom:2px;
  font:500 5.5px/1 "IBM Plex Mono",monospace;letter-spacing:.1em;
  color:rgba(23,21,15,.42)}
/* the market headline sits under the plate, not in place of it */
.cbody.anchored .mhead{order:3;flex:0 0 auto}
.cbody.anchored .cband{order:4}
.plate .nodata-slug{position:absolute;left:3px;bottom:2px}
.cname{font-family:Bitter,Georgia,serif;font-weight:700;line-height:1.1;
  max-height:2.3em;overflow:hidden}
/* no-data rule: the hatch is the system's no-data texture, and it occupies the
   exact strip real art will later expand into */
.nodata{height:0;margin:3px 0 2px;
  border-top:2px dotted rgba(23,21,15,.55)}
.cband.fixed .nodata{border-top-color:rgba(239,233,216,.5)}
.nodata-slug{font:500 6.5px/1 "IBM Plex Mono",monospace;letter-spacing:.14em;
  color:var(--dis-ink)}
.cband{margin-top:auto;margin-left:-5px;margin-right:-5px;
  border-top:2px solid var(--ink);background:#DCD6C0;
  display:flex;flex-direction:column}
.cband.fixed{background:var(--film)}
.cline{display:flex;align-items:stretch;min-height:0;flex:1}
.cline+.cline{border-top:.5px solid rgba(23,21,15,.35)}
.cband.fixed .cline+.cline{border-top-color:rgba(239,233,216,.3)}
.cstrip{flex:0 0 auto;border-right:1.5px solid var(--ink);display:grid;
  place-items:center;color:var(--ink)}
.cband.fixed .cstrip{border-right-color:rgba(239,233,216,.5)}
.cstrip.ongoing{background:var(--stock)}
.cstrip.taken{background:repeating-linear-gradient(135deg,var(--ink) 0 2px,#C9C2A8 2px 5px)}
.cstrip.fixed{background:var(--amber)}
.cstrip.none{background:#CFC8B0}

/* glyph row */
.grow{display:flex;align-items:center;gap:1px;padding:1px 3px;flex-wrap:wrap;
  color:var(--ink);min-width:0}
.cband.fixed .grow{color:var(--bone2)}
.grow.muted{opacity:.55}
.gi{position:relative;display:inline-block;flex:0 0 auto}
.gi.chip{background:var(--amber);border-radius:2px;padding:1px;box-sizing:content-box}
.cband.fixed .gi.chip{color:var(--ink)}
.gban{position:absolute;inset:0;opacity:.95}
.gspine{position:absolute;left:8%;top:50%;transform:translateY(-50%);
  font-family:Bitter,Georgia,serif;font-weight:700;line-height:1;
  color:var(--stock)}
.cband.fixed .gspine{color:var(--film)}
.gmotif{left:6%}
.gnum{font-family:Bitter,Georgia,serif;font-weight:700;line-height:1;
  letter-spacing:-.02em;flex:0 0 auto}
.gsep{opacity:.6;flex:0 0 auto;padding:0 1px}
.gtext{font-family:"Atkinson Hyperlegible",sans-serif;line-height:1.1;flex:0 0 auto}
.gmay{opacity:.55;font-family:Bitter,serif}

/* market headline glyph */
.mhead{display:flex;align-items:center;gap:2px;margin-top:auto;
  padding:2px 3px;border-top:1.5px solid var(--ink);background:#DCD6C0;
  margin-left:-5px;margin-right:-5px;color:var(--ink)}
.mmode{flex:0 0 auto;opacity:.75}

/* ---------------------------------------------------------- active band */
/* Sizes to content. It used to take flex:1 and stretch, which is where the dead
   space came from -- the tally area was claiming the whole lower half. */
#active{flex:1 1 auto;min-height:0;overflow-y:auto;display:flex;flex-direction:column;
  padding:8px 14px 0;border-top:2px solid var(--bone)}
.ahead{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.ahead .lin{font-family:Bitter,Georgia,serif;font-weight:700;font-size:15px}
.ahead .yt{font:500 9px/1 "IBM Plex Mono",monospace;letter-spacing:.2em;
  color:var(--amber)}
.ahead .yt.waiting{color:var(--dis-ink)}
.ahead .sc{font-family:Bitter,Georgia,serif;font-weight:700;font-size:20px;
  margin-left:auto}
.ahead .stat{font:500 10px/1 "IBM Plex Mono",monospace;letter-spacing:.1em;
  color:var(--muted-bone)}

/* capacity — full width directly above the cell (proximity problem) */
.cap{display:flex;gap:2px;align-items:stretch;margin-bottom:6px}
.cap .lbl{font:500 8.5px/1 "IBM Plex Mono",monospace;letter-spacing:.16em;
  color:var(--muted-bone);display:grid;place-items:center;padding-right:8px}
.cap i{flex:1;height:20px;display:grid;place-items:center;font-style:normal;
  font-family:Bitter,Georgia,serif;font-weight:700;font-size:11px;
  border:1px solid rgba(239,233,216,.25);color:var(--muted-bone)}
.cap i.at{border:1.5px solid var(--amber);color:var(--amber)}
/* over: amber SOLID, never the hatch, never red */
.cap i.over{background:var(--amber);color:var(--ink);border-color:var(--amber)}

/* cell gets the width it needs for a fan; the genome is the thing being read,
   so it gets real area rather than a leftover column */
/* The zones hug their content, but #active does not -- so the slack pooled
   below them as dead space. It goes to the cell, which is the one zone that
   genuinely grows during play: the genome stays sized to its rows (a tally
   should not eat the column) and the lineage panel hugs its stages. */
.azones{display:flex;gap:14px;flex:1 1 auto;min-height:0;padding-bottom:8px;
  align-items:flex-start}
.zone{display:flex;flex-direction:column;min-width:0;min-height:0}
/* Cell over keys in one column; the genome takes the width that frees up. */
.sidecol{display:flex;flex-direction:column;gap:10px;flex:0 1 300px;
  min-width:240px;min-height:0;align-self:stretch}
#cellzone{flex:1 1 auto;min-width:0}
.sidecol .zone:last-child{flex:0 0 auto}
.gzone{flex:1 1 auto;min-width:0;justify-content:flex-start}
.zhead{font:500 10px/1 "IBM Plex Mono",monospace;letter-spacing:.13em;
  color:var(--muted-bone);margin-bottom:4px;display:flex;gap:6px;
  align-items:center;flex-wrap:wrap;row-gap:3px;min-height:12px}
.zhead>span{white-space:nowrap}
.overchip{background:var(--amber);color:var(--ink);padding:2px 6px;
  border-radius:2px;font-weight:700;flex:0 0 auto}

/* cell — dashed = area. cards fan overlapping, spines exposed. */
#cellzone{flex:1;min-width:0}
.cell{border:1px dashed rgba(239,233,216,.3);border-radius:2px;padding:5px;
  display:flex;flex:0 0 auto;min-height:0;overflow-x:auto;align-items:flex-start}
.cell.over{border-top:3px solid var(--amber)}
.cell .card{margin-right:-1px}
.cell .card.spineonly{box-shadow:1px 0 0 rgba(23,21,15,.35)}
.cell .card.pastlimit{outline:1.5px solid var(--amber);outline-offset:-1.5px;z-index:2}
.cell .card:hover{z-index:5;cursor:pointer}

/* promoter track */
.proms{display:flex;gap:3px}
.prom{width:34px;border-radius:2px;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:2px;padding:4px 0;
  font:500 6px/1 "IBM Plex Mono",monospace;letter-spacing:.08em}
.prom svg{width:15px;height:15px}
.prom.never{border:1px dashed rgba(239,233,216,.34);color:var(--dis-ink)}
.prom.never svg{color:rgba(239,233,216,.22)}
.prom.live{background:var(--amber);color:var(--ink);
  box-shadow:inset 0 2px 0 rgba(255,255,255,.4),inset 0 -2px 0 rgba(23,21,15,.25)}
.prom.live svg{color:var(--ink)}
.prom.spent{background:var(--dis-edge);background-image:var(--hatch);color:var(--dis-ink)}
.prom.spent svg{color:var(--ink)}

/* genome */
.gwrap{display:flex;gap:4px;flex:1;min-height:0}
.gcols{display:flex;flex-direction:column;flex:1;min-width:0}
/* Sized to its rows, not stretched. The genome is a reference tally; letting it
   eat the column was giving the most vertical space to the least-read thing. */
.genome{display:grid;gap:4px;flex:0 0 auto;grid-auto-rows:64px;
  padding-top:5px;border-top:1px solid rgba(239,233,216,.22)}
/* The titles are caps sitting ON their column, squared off where they meet the
   grid and separated from it by a rule -- so the header reads as a header and
   not as a fourth row of cells. */
.ghead{display:grid;gap:4px;margin-bottom:0;height:23px;flex:0 0 auto}
.ghead span{font:500 9.5px/1 "IBM Plex Mono",monospace;letter-spacing:.08em;
  padding:0 8px;color:var(--ink);border-radius:3px 3px 0 0;
  display:flex;align-items:center;justify-content:space-between;gap:6px}
.ghead svg{width:12px;height:12px;flex:0 0 auto}
.ghead b{font-family:Bitter,Georgia,serif;font-size:11px}
.ghead .gfam{font:600 10px/1 "IBM Plex Mono",monospace;letter-spacing:.1em;
  margin-right:auto;text-transform:uppercase}
.gcell{border-width:1px;border-style:solid;border-radius:3px;position:relative;
  display:grid;place-items:center;overflow:hidden;min-height:0;min-width:62px}
/* An empty slot should look like a slot, not a dimmer gene. */
.gcell.empty{border-style:dashed;border-color:rgba(239,233,216,.16)}
.gcell .nm{font-size:10.5px;line-height:1.2;text-align:center;padding:2px 5px;
  color:var(--ink);font-weight:700}
.gcell[data-clickable]{cursor:pointer}
.gcell[data-clickable]:hover{filter:brightness(1.1);
  box-shadow:inset 0 0 0 1.5px rgba(23,21,15,.45)}
.gcell .gh{font-family:Bitter,Georgia,serif;font-weight:700;font-size:15px;
  opacity:.30;position:static}
.rowtabs{display:flex;flex-direction:column;gap:3px;padding-top:21px;flex:0 0 auto}
.rowtabs .rowtab{flex:0 0 64px}
.rowtab{border:1px solid var(--dis-edge);border-radius:2px;width:46px;
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  font:500 8.5px/1.3 "IBM Plex Mono",monospace;letter-spacing:.05em;
  color:var(--muted-bone);padding:2px}
.rowtab.near{border:1.5px solid var(--amber);color:var(--amber)}
.rowtab b{font-family:Bitter,Georgia,serif;font-size:10px;color:var(--bone)}
.rowtab.near b{color:var(--amber)}

/* -------------------------------------------------------------- turnbar */
#turnbar{flex:0 0 auto;display:flex;align-items:center;gap:8px;padding:6px 14px;
  background:var(--film-panel);border-top:1px solid #26241D}
#acts{display:flex;gap:7px;align-items:stretch;flex-wrap:wrap}
/* Symbol-only, square, with the words on hover. */
.act{display:flex;align-items:center;justify-content:center;width:42px;height:36px;
  padding:0;border:1px solid var(--dis-edge);border-radius:3px;
  background:transparent;color:var(--dis-ink);cursor:not-allowed}
.act .actglyph{width:22px;height:22px;opacity:.8}
.act.on .actglyph,.act.exit .actglyph{opacity:1}
.act.on:hover,.act.forced:hover{filter:brightness(1.12)}
.act b{font:500 11px/1 "IBM Plex Mono",monospace;letter-spacing:.12em}
.act .why{font-size:9.5px;letter-spacing:0;text-transform:none;
  font-family:"Atkinson Hyperlegible",sans-serif;opacity:.9}
.act.on{background:var(--amber);color:var(--ink);border-color:var(--amber);
  cursor:pointer}
.act.exit{background:var(--amber);color:var(--ink);border-color:var(--amber)}
/* An overridden action must never look like a legal one: it wears the hazard
   stripe as an edge, with the label on solid ink so it stays readable. */
.act.forced{background:var(--ink);color:var(--bone);border-color:var(--bone);
  cursor:pointer;position:relative;padding-left:16px;overflow:hidden}
.act.forced::before{content:"";position:absolute;left:0;top:0;bottom:0;width:10px;
  background:repeating-linear-gradient(135deg,var(--bone) 0 4px,var(--ink) 4px 8px)}
.act.forced b{color:var(--bone)}
.act.forced .why{color:var(--muted-bone)}

/* --------------------------------------------------------- interstitial */
#handover{position:fixed;inset:0;background:var(--film);z-index:80;
  display:flex;flex-direction:column}
.hobar{flex:0 0 8px}
.hocore{flex:1;display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:14px}
.horing{width:54px;height:54px}
.holin{font-family:Bitter,Georgia,serif;font-weight:700;font-size:26px}
.hopass{font-size:10px;color:var(--muted-bone)}
.hodigest{font-size:12px;color:var(--bone2);max-width:520px;text-align:center;
  line-height:1.5}
#hobegin{padding:11px 26px;font:500 12px/1 "IBM Plex Mono",monospace;
  letter-spacing:.2em}

/* --------------------------------------------------------------- modal */
#modal{position:fixed;inset:0;background:#000000cc;display:grid;place-items:center;
  z-index:90;padding:20px}
.sheet{background:var(--film-panel);border:1px solid var(--dis-edge);border-radius:4px;
  width:min(1000px,100%);max-height:88vh;overflow:auto;padding:22px 24px;position:relative}
.x{position:absolute;top:8px;right:10px;background:none;border:none;font-size:22px;
  color:var(--muted-bone);padding:0 6px}
.sheet h3{margin:0 0 6px;font-size:17px;font-family:Bitter,Georgia,serif}
.sheet h4{margin:14px 0 4px;font-size:12px}
.joinrow{display:flex;align-items:center;gap:8px;margin:7px 0}
.joinrow b{font:500 10px/1 "IBM Plex Mono",monospace;letter-spacing:.14em;
  min-width:56px}
.joinrow input{flex:1;font-size:11px;font-family:"IBM Plex Mono",monospace}
.undesigned{border:1px dashed var(--dis-edge);border-radius:2px;padding:7px 10px;
  font-size:11px;color:var(--muted-bone);margin-bottom:12px}
table{border-collapse:collapse;width:100%;font-size:12px}
th,td{text-align:left;padding:4px 8px;border-bottom:1px solid #26241D}
th{color:var(--muted-bone);font:500 10px/1 "IBM Plex Mono",monospace;
  letter-spacing:.1em;text-transform:uppercase}
.bar{height:5px;background:#26241D;border-radius:99px;overflow:hidden;margin:4px 0 10px}
.bar i{display:block;height:100%;background:var(--amber)}
.covgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:3px}
.covgrid div{font:500 10px/1.5 "IBM Plex Mono",monospace;letter-spacing:.04em;
  padding:2px 5px;border-radius:2px;background:#1A1813;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;text-transform:none}
.covgrid div.y{background:#241F12;color:var(--amber)}
.logline{font:500 11px/1.6 "IBM Plex Mono",monospace;letter-spacing:.02em;
  padding:2px 0;border-bottom:1px solid #1E1C17;display:flex;gap:9px;
  text-transform:none}
.logline .who{color:var(--amber);min-width:34px}
.logline.override{color:var(--bone);background:var(--film-panel)}
.logline.system{color:var(--muted-bone);font-style:italic}
.choice{display:flex;flex-direction:column;gap:5px;margin-top:10px}
.choice button{text-align:left;padding:8px 11px}

/* ---------------------------------------------------------- proof mode */
#proofbody .ruler{height:26px;position:relative;border-top:1px solid var(--muted-bone);
  margin-top:10px}
#proofbody .ruler i{position:absolute;top:0;width:1px;background:var(--muted-bone)}
#proofbody .ruler span{position:absolute;top:8px;font:500 8px/1 "IBM Plex Mono",monospace;
  color:var(--muted-bone)}
.proofnote{font-size:11.5px;color:var(--muted-bone);line-height:1.5}

/* ------------------------------------------------- phase 4: board fixes */

/* 4.1 worker rail — off the helix, where they were unreadable */
.wrail{position:absolute;right:30px;top:20px;bottom:6px;display:flex;
  flex-direction:column;justify-content:flex-start;gap:4px;align-items:center}
.wempty{width:26px}
/* the printed mat draws its empty worker slots; so does this one */
.wrail .wslot{width:26px;height:26px;border-radius:50%;display:block;
  flex:0 0 auto;border:1.5px dashed var(--dis-edge)}
.fork.can .wrail .wslot{border-color:rgba(242,194,78,.4)}

/* 4.2 capacity you see rather than read */
.cap{display:flex;align-items:center;gap:9px;margin-bottom:7px}
.cap .lbl{font:500 8.5px/1 "IBM Plex Mono",monospace;letter-spacing:.16em;
  color:var(--muted-bone);padding:0}
.captrack{flex:1;display:flex;gap:2px;height:16px}
.captrack i{flex:1;background:#0E0D0A;border:1px solid rgba(239,233,216,.16);
  border-radius:1px;display:block}
.captrack i.filled{background:var(--muted-bone);border-color:var(--muted-bone)}
.captrack i.limit{border-right:3px solid var(--bone)}
.captrack i.beyond{opacity:.3}
.captrack i.spill{background:var(--amber);border-color:var(--amber)}
.capread{font-family:Bitter,Georgia,serif;font-weight:700;font-size:15px;
  min-width:52px;text-align:right}
.capread span{font-size:11px;color:var(--muted-bone);font-weight:400}
.capread.over{color:var(--amber)}

/* 4.3 cell breathes until it genuinely cannot */
/* Sized to the space it has, and scrolls past it. Since #active stopped
   stretching, an unbounded cell would push the whole board down. */
/* The 236px cap dates from when the cell was squeezed for space. It has the
   height now, so it fills its zone and only scrolls when genuinely overfull --
   capping it just moved the empty space inside the zone instead. */
.cell{gap:5px;align-content:flex-start;flex-wrap:wrap;overflow-y:auto;
  flex:1 1 auto;min-height:120px;scrollbar-width:thin}
.cell .card{margin-right:0}
.cell.tight{flex-wrap:nowrap;overflow-x:auto}
.cell.tight .card{margin-right:-1px}

/* ------------------------------------------------------- final scoreboard */
.finalwrap{display:flex;flex-direction:column;gap:14px}
.finalhead{display:flex;align-items:baseline;gap:12px}
.finalhead h3{margin:0}

.fcard{position:relative;border:1px solid var(--dis-edge);border-radius:4px;
  padding:14px 16px 12px;background:var(--film-panel);overflow:hidden}
.fcard::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  background:var(--pc)}
.fcard.won{border-color:rgba(242,194,78,.5);
  background:radial-gradient(120% 140% at 0% 0%,
    rgba(242,194,78,.10),var(--film-panel) 55%)}

.fhead{display:flex;align-items:center;gap:12px}
.fmedal{width:26px;height:26px;flex:0 0 auto;border-radius:50%;display:grid;
  place-items:center;font:700 12px/1 "IBM Plex Mono",monospace;
  border:1px solid var(--dis-edge);color:var(--muted-bone)}
.fcard.won .fmedal{border-color:var(--amber);color:var(--amber);
  background:rgba(242,194,78,.12);font-size:15px}
.fwho{display:flex;flex-direction:column;gap:1px;min-width:0}
.fwho b{font-family:Bitter,Georgia,serif;font-size:16px;line-height:1.1}
.fwho span{font-size:11px}
.ftotwrap{margin-left:auto;display:flex;align-items:baseline;gap:8px}
.ftot{font-family:Bitter,Georgia,serif;font-weight:700;font-size:30px;
  line-height:1;color:var(--bone)}
.fcard.won .ftot{color:var(--amber)}
.fgap{font:500 11px/1 "IBM Plex Mono",monospace}

.fgrid{display:flex;flex-wrap:wrap;gap:18px;align-items:flex-start;margin:12px 0 4px}
/* min-width:0 on BOTH: a flex child defaults to min-content, so the genome map
   and the legend each refused to shrink and the card overflowed by ~130px on a
   narrow window. The map keeps its size and drops to its own line; the legend
   is the part that reflows. */
.fright{flex:1 1 260px;min-width:0}
.gmap{flex:0 0 auto}

/* the genome, as it finished. the shape is the story. */
.gmap{flex:0 0 auto;display:flex;flex-direction:column;gap:3px}
.gmrow{display:flex;gap:3px;align-items:center}
.gmcell{width:26px;height:26px;border-radius:2px;display:grid;place-items:center;
  border:1px dashed rgba(239,233,216,.16);background:transparent}
.gmcell.on{border:1px solid var(--fam);
  background:color-mix(in srgb,var(--fam) 26%,transparent)}
.gmcell.on.col{background:color-mix(in srgb,var(--fam) 55%,transparent)}
.gmcell .gmico{width:13px;height:13px;color:var(--fam);opacity:.9}
.gmcell.on.col .gmico{color:var(--ink);opacity:1}
.gmrow.full .gmcell{box-shadow:0 0 0 1px rgba(242,194,78,.55)}
.gmtag{width:18px;font:700 9px/1 "IBM Plex Mono",monospace;color:var(--amber);
  text-align:right}
.gmfeet{display:flex;gap:3px;margin-top:1px}
.gmfoot{width:26px;height:3px;border-radius:1px;background:rgba(239,233,216,.10)}
.gmfoot.full{background:var(--fam)}

/* one stacked bar: the question is what SHARE each thing was */
.fstack{display:flex;height:14px;border-radius:2px;overflow:hidden;
  background:rgba(239,233,216,.06)}
.fstack .fseg{display:block;height:100%}
.fstack .fseg+.fseg{box-shadow:inset 1px 0 0 rgba(20,19,16,.55)}

.flegend{margin-top:9px;display:grid;
  grid-template-columns:auto auto 1fr auto auto;gap:2px 8px;align-items:center;
  min-width:0}
.fleg{display:contents}
.fleg .fsw{width:9px;height:9px;border-radius:2px}
.fleg .flico{width:12px;height:12px;color:var(--muted-bone)}
.fleg .flab{font-size:12px}
.fleg .fvp{font-family:Bitter,Georgia,serif;font-weight:700;font-size:13px;
  text-align:right}
.fleg .flab{font-size:12px;min-width:0;overflow:hidden;text-overflow:ellipsis}
.fleg .fnote{font-size:10.5px;text-align:right;min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.fleg.neg .flab,.fleg.neg .fvp{color:var(--dis-ink)}
.fleg.neg .fsw{background:repeating-linear-gradient(135deg,
  var(--dis-ink) 0 2px,transparent 2px 4px) !important;
  box-shadow:inset 0 0 0 1px var(--dis-ink)}

.fstats{display:flex;flex-wrap:wrap;gap:7px 16px;margin-top:11px;padding-top:9px;
  border-top:1px solid var(--dis-edge);min-width:0}

/* Below this the note column has nowhere to go, so it goes. The numbers and
   the genome map are the point; the parenthetical was always the first thing
   to drop. */
@media (max-width:620px){
  .fleg .fnote{display:none}
  .flegend{grid-template-columns:auto auto 1fr auto}
  .fhead .ftot{font-size:24px}
  .sheet{padding:16px 14px}
}
.fstat{display:flex;align-items:center;gap:5px;cursor:help}
.fstat .fsico{width:13px;height:13px;color:var(--muted-bone)}
.fstat b{font-family:Bitter,Georgia,serif;font-size:14px;line-height:1}
.fstat span{font-size:11px}

/* key picker: the demand number is the whole decision, so it is the loudest
   thing on the button */
.keypick{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:8px;margin:10px 0}
.keyopt{display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  padding:10px 12px;text-align:left}
.keyopt .kico{width:20px;height:20px;color:var(--amber)}
.keyopt b{font-family:Bitter,Georgia,serif;font-size:15px}
.keyopt .kname{font-size:11px}
.keyopt .kdem{font:500 10px/1 "IBM Plex Mono",monospace;letter-spacing:.1em;
  text-transform:uppercase;color:var(--dis-ink);margin-top:3px}
.keyopt .kdem.want{color:var(--amber)}
.keyopt:hover{border-color:var(--amber)}

/* family-first slots, styled as the printed tiles are */
.ffrow{margin-top:14px;flex:0 0 auto}
.ffslots{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;
  padding-top:5px;border-top:1px solid rgba(239,233,216,.22)}
.ffslot{position:relative;height:46px;border-radius:2px;display:grid;
  place-items:center;border:1.5px dashed color-mix(in srgb,var(--fam) 45%,transparent);
  background:color-mix(in srgb,var(--fam) 7%,transparent)}
.ffslot .ffico{width:22px;height:22px;color:color-mix(in srgb,var(--fam) 60%,transparent)}
.ffslot.held{border:1.5px solid var(--fam);background:var(--fam)}
.ffslot.held .ffico{color:var(--ink);opacity:.85}
.ffslot .ffvp{position:absolute;right:6px;bottom:3px;color:var(--ink);
  font-family:Bitter,Georgia,serif;font-weight:700;font-size:13px}
/* locked = you hold all three and nobody can take it */
.ffslot.lock{background:color-mix(in srgb,var(--fam) 32%,var(--ink))}
.ffslot.lock .ffico{color:var(--fam);opacity:1}
.ffslot.lock .ffvp{color:var(--fam)}
.ffslot.lock::after{content:"";position:absolute;inset:3px;border-radius:1px;
  border:1px solid color-mix(in srgb,var(--fam) 70%,transparent)}

/* 4.4 / 4.5 panels */
.izone{flex:0 0 250px;gap:8px;display:flex;flex-direction:column;overflow-y:auto}
.panel{border:1px solid #2C2A22;border-radius:3px;background:var(--film-panel);
  padding:7px 9px}
.linpanel{border-left:3px solid var(--lin,var(--amber));
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--lin,#888) 11%,var(--film-panel)) 0%,
    var(--film-panel) 58%)}
.linpanel .phead b{color:var(--lin,var(--bone))}
.linpanel .stagerow.done .stagen{background:var(--lin);color:var(--ink);
  border-color:var(--lin)}
.phead{display:flex;align-items:baseline;gap:8px;margin-bottom:5px}
.phead b{font-family:Bitter,Georgia,serif;font-size:13px}
.phead span{font-size:8.5px;margin-left:auto}
.prule{display:flex;gap:6px;align-items:flex-start;font-size:11px;
  line-height:1.35;margin-top:4px;color:var(--bone2)}
.ptag{flex:0 0 auto;font-size:7.5px;letter-spacing:.16em;color:var(--muted-bone);
  border:1px solid var(--dis-edge);border-radius:2px;padding:1px 4px;margin-top:1px}
.pscore{display:flex;flex-direction:column;gap:3px}
.pscore .grow{padding:0;color:var(--bone2)}

.stagerow{border-top:1px solid #26241D;padding:7px 0 6px;display:flex;
  flex-direction:column;gap:5px}
.stagetop{display:flex;gap:7px;align-items:baseline}
.stagen{font-size:10px;color:var(--muted-bone);flex:0 0 auto}
.stageeff{font-size:11.5px;line-height:1.35}
.stagerow.done .stagen{color:var(--amber)}
.stagerow.done .stageeff{color:var(--muted-bone)}
.stagerow.ready{background:rgba(242,194,78,.06);margin:0 -9px;padding:7px 9px 6px}
.stagerow.ready .stagen{color:var(--amber)}
.stageend{font-size:10.5px;color:var(--muted-bone);display:flex;gap:6px;
  align-items:flex-start;line-height:1.3}
.stageneed{display:flex;flex-direction:column;align-items:stretch;gap:3px}
.stageneed .mono{font-size:8.5px;color:var(--muted-bone);line-height:1.3}
.needbar{flex:1;height:4px;background:#26241D;border-radius:99px;overflow:hidden}
.needbar i{display:block;height:100%;background:var(--muted-bone)}
.stagerow.ready .needbar i{background:var(--amber)}
.stagerow button{width:100%;font-size:10px;font-family:"IBM Plex Mono",monospace;
  letter-spacing:.14em;padding:5px}
.stagewhy{font-size:10px;color:var(--dis-ink);line-height:1.3}

/* key supply: gives / needs still in this era's deck */
.keysupply{display:flex;gap:3px;font:500 7px/1 "IBM Plex Mono",monospace;
  margin-top:1px}
.keysupply .kg{color:var(--muted-bone)}
.keysupply .kn{color:var(--muted-bone);opacity:.55}
.prom.live .keysupply .kg,.prom.live .keysupply .kn{color:var(--ink);opacity:.7}
.prom.scarce .keysupply .kg{color:var(--amber);font-weight:700}
.prom.live.scarce .keysupply .kg{color:var(--ink)}

/* choice modal — options rendered as the objects being chosen */
.choicegrid{display:flex;gap:14px;flex-wrap:wrap;margin-top:10px}
.choicecol{flex:1;min-width:210px;border:1px solid #2C2A22;border-radius:3px;
  padding:9px;background:#16150F}
.choicehead{display:flex;align-items:center;gap:9px;margin-bottom:7px}
.choicehead .mono{font-size:7.5px;letter-spacing:.16em}
.choicelist{display:flex;flex-direction:column;gap:4px}
.choicelist button{text-align:left;font-size:11px;padding:5px 8px}
.choicelist .mono{font-size:8px;letter-spacing:.14em;color:var(--amber)}
.choicecards{display:flex;gap:12px;flex-wrap:wrap;margin-top:10px}
.choicepick{border:1px solid #2C2A22;border-radius:3px;padding:8px;cursor:pointer;
  display:flex;flex-direction:column;align-items:center;gap:5px;background:#16150F}
.choicepick:hover{border-color:var(--amber);background:rgba(242,194,78,.06)}
.choicepick .mono{font-size:8px;letter-spacing:.18em;color:var(--amber)}
.skipbtn{margin-top:12px;width:100%;font-size:11px}

/* log */
.logbar{display:flex;gap:6px;flex-wrap:wrap;margin:8px 0}
.logbar button{font-size:10px;font-family:"IBM Plex Mono",monospace;
  letter-spacing:.1em;padding:4px 9px}
.loglines{max-height:52vh;overflow:auto;border-top:1px solid #26241D}
.logera{display:flex;gap:10px;align-items:baseline;font-size:9px;
  letter-spacing:.2em;color:var(--amber);padding:10px 0 4px;
  border-bottom:1px solid #26241D;margin-bottom:3px;position:sticky;top:0;
  background:var(--film-panel)}
.logera .dim{letter-spacing:.14em}
.logline .ltext{flex:1}
.logline .lscore{font-family:Bitter,Georgia,serif;font-weight:700;
  color:var(--muted-bone);min-width:28px;text-align:right}
.logline.override{border-left:3px solid var(--bone);padding-left:6px}
.logline .who.inkseat{text-shadow:0 0 0 var(--ink);
  border-bottom:1.5px solid var(--muted-bone)}
.botcell{display:flex;align-items:center;gap:5px;font-size:11px;color:var(--bone2);
  white-space:nowrap;min-width:52px}
.botcell input{margin:0}
.logline.bot{color:var(--muted-bone)}
.logline.bot .ltext{font-style:italic}

/* --------------------------------------------------- era cards in the market
   The market row no longer stretches its mats, so the space at the end holds
   the three era cards: the one you are in, the one coming, and the one you
   are not allowed to see. */
/* The era cards hold their ground: they used to be flex:1 with min-width:0, so
   any growth in the mats squeezed them off the edge entirely. */
.eras{display:flex;gap:10px;flex:1 1 auto;min-width:0;align-items:stretch}
/* One colour per era, cool to hot as the game escalates. The panels were three
   identical grey slabs; nothing told you which era you were reading. */
.eracard{flex:1 1 0;min-width:150px;max-width:250px;
  border:1px solid var(--dis-edge);border-left:3px solid var(--era,var(--dis-edge));
  border-radius:3px;padding:7px 9px 8px 10px;
  background:linear-gradient(180deg,
    color-mix(in srgb,var(--era,#888) 9%,var(--film-panel)) 0%,
    var(--film-panel) 62%);
  display:flex;flex-direction:column;gap:4px;opacity:.78;align-self:stretch}
.eracard.e1{--era:var(--Sg)}
.eracard.e2{--era:var(--R)}
.eracard.e3{--era:var(--D)}
.eracard .eraname{color:var(--era,var(--bone))}
.eracard .erahead .mono:first-child{color:var(--era,var(--muted-bone));opacity:.9}
.eracard.now{opacity:1;border-color:var(--era);
  box-shadow:0 0 0 1px color-mix(in srgb,var(--era) 45%,transparent)}
.eracard.past{opacity:.34}
.eracard.hidden-era{background:repeating-linear-gradient(135deg,
  #1B1A16 0 5px,#141310 5px 10px);border-style:dashed}
.erahead{display:flex;gap:7px;align-items:baseline;font-size:8px;
  letter-spacing:.18em;color:var(--muted-bone)}
.nowtag{color:var(--ink);background:var(--amber);border-radius:2px;padding:1px 4px}
.eraname{font-family:Bitter,Georgia,serif;font-weight:700;font-size:12.5px;
  line-height:1.1}
.erabody{font-size:10px;line-height:1.35;color:var(--muted-bone)}
.erarule{display:flex;gap:5px;align-items:flex-start;font-size:10px;
  line-height:1.3;color:var(--bone2)}
.erarule .ptag{font-size:6.5px;padding:1px 3px;margin-top:1px}
.erascore{display:flex;flex-direction:column;gap:2px;min-width:0}
.erascore .grow{padding:0;color:var(--bone2)}

/* --------------------------------------------------------- card inspector
   Clicking a card shows the card, at print size, beside a plain reading of it. */
.inspect{display:flex;gap:22px;align-items:flex-start}
.inspectcard{flex:0 0 auto;display:flex;flex-direction:column;gap:6px;
  align-items:center}
.inspectcard .mono{font-size:9.5px;letter-spacing:.14em}
.inspectinfo{flex:1;min-width:0;display:flex;flex-direction:column;gap:10px}
.inspectinfo h3{margin:0}
.facts{display:flex;flex-direction:column;gap:6px}
.fact{display:flex;gap:9px;align-items:flex-start;font-size:14.5px;line-height:1.5;
  color:var(--bone2)}
.fact .mono{flex:0 0 92px;font-size:9.5px;letter-spacing:.12em;color:var(--muted-bone);
  border:1px solid var(--dis-edge);border-radius:2px;padding:2px 4px;
  text-align:center;margin-top:1px}
.effects{display:flex;flex-direction:column;gap:8px;border-top:1px solid #26241D;
  padding-top:10px}
.effrow{display:flex;flex-direction:column;gap:2px}
.efftext{font-size:15.5px;line-height:1.5}
.effmode{font-size:12.5px;line-height:1.45}
.inspect .choice{margin-top:auto}
.inspect .choice p{font-size:13px;line-height:1.5;margin:2px 0 0}

/* ------------------------------------------------------------------ menu
   Undo and Force stay in the bar: one is used every turn, the other is a mode
   you must be able to see is armed. Everything else is occasional. */
#menubtn{min-width:74px}
#menu{position:absolute;top:100%;right:14px;margin-top:4px;z-index:40;
  background:var(--film-panel);border:1px solid var(--dis-edge);border-radius:3px;
  box-shadow:0 8px 24px #000a;width:268px;padding:5px;display:flex;
  flex-direction:column;gap:1px}
.menuitem{background:none;border:none;border-radius:2px;text-align:left;
  padding:7px 9px;cursor:pointer;display:flex;flex-direction:column;gap:2px}
.menuitem:hover:not(:disabled){background:#26241D}
.menuitem:disabled{opacity:.4;cursor:not-allowed}
.menutop{display:flex;align-items:baseline;gap:8px;font-size:12.5px;
  color:var(--bone)}
.menukey{margin-left:auto;font-size:9px;color:var(--muted-bone);
  border:1px solid var(--dis-edge);border-radius:2px;padding:1px 5px}
.menuhint{font-size:10.5px;line-height:1.3;color:var(--muted-bone)}
.menusep{height:1px;background:#26241D;margin:4px 2px}

/* ------------------------------------------------------------ card browser */
.browse{display:flex;flex-direction:column;gap:10px;min-height:0}
.browsehead{position:sticky;top:0;background:var(--film-panel);z-index:2;
  padding-bottom:6px}
.browsehead h3{margin:0 0 6px}
.browsebody{display:flex;flex-direction:column;gap:14px;overflow:auto;
  max-height:66vh;padding-right:4px}
.browsegroup{display:flex;flex-direction:column;gap:6px}
.browsegrouphead{display:flex;align-items:baseline;gap:10px;
  border-bottom:1px solid #26241D;padding-bottom:3px}
.browsegrouphead b{font-family:Bitter,Georgia,serif;font-size:13px}
.browsegrouphead .mono{font-size:8.5px;letter-spacing:.14em}
.browserow{display:flex;flex-wrap:wrap;gap:7px}
.browsecard{position:relative;cursor:pointer;border-radius:3px;padding:2px;
  border:1px solid transparent}
.browsecard:hover{border-color:var(--amber);background:rgba(242,194,78,.07)}
.browsecard .card{opacity:.62}
.browsecard.seen .card{opacity:1}
.wherechip{position:absolute;left:2px;right:2px;bottom:2px;font-size:6px;
  letter-spacing:.1em;text-align:center;padding:1px 0;border-radius:1px;
  background:var(--film);color:var(--muted-bone)}
.wherechip.market{background:var(--amber);color:var(--ink)}
.wherechip.yours,.wherechip.yourgenome{background:var(--bone);color:var(--ink)}

/* ------------------------------------------------------------ symbol legend */
.leggrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));
  gap:9px 18px;margin:6px 0 4px}
.legrow{display:flex;gap:10px;align-items:flex-start}
.legmark{flex:0 0 26px;height:26px;display:grid;place-items:center;
  border:1px solid var(--dis-edge);border-radius:2px;background:#16150F}
.legname{font-size:12px;font-weight:700;font-family:Bitter,Georgia,serif}
.legmean{font-size:10.5px;line-height:1.35;color:var(--muted-bone)}
.legswatch{width:20px;height:20px;border-radius:2px}
.sw-hatch{background:var(--dis-edge);background-image:var(--hatch)}
.sw-taken{background:repeating-linear-gradient(135deg,var(--ink) 0 2px,#C9C2A8 2px 5px)}
.sw-dotted{background:var(--stock);border-top:3px dotted var(--ink)}
.sw-dashed{border:1.5px dashed rgba(239,233,216,.4)}
.sw-amber{background:var(--amber)}
.gonebanner{position:fixed;left:0;right:0;top:0;z-index:200;background:var(--bone);
  color:var(--ink);font:500 12px/1.4 "IBM Plex Mono",monospace;letter-spacing:.08em;
  padding:12px 16px;text-align:center}

/* ------------------------------------------------------------- rulebook */
.rulebook{max-width:760px}
.rbbody{max-height:66vh;overflow-y:auto;padding-right:8px;margin-top:8px}
.rbbody .rbh{font-family:Bitter,Georgia,serif;margin:16px 0 6px;color:var(--bone)}
.rbbody h2.rbh{font-size:17px} .rbbody h3.rbh{font-size:14.5px}
.rbbody h4.rbh{font-size:13px;color:var(--amber)}
.rbp{font-size:14px;line-height:1.55;margin:6px 0;color:var(--bone2)}
.rbli{font-size:14px;line-height:1.55;margin:4px 0 4px 20px;color:var(--bone2);
  position:relative}
.rbli::before{content:"\2022";position:absolute;left:-14px;top:0;
  color:var(--amber);font-size:12px}
.rbbody hr{border:none;border-top:1px solid var(--dis-edge);margin:14px 0}
.rbtable{border-collapse:collapse;margin:10px 0;width:100%;font-size:13px}
.rbtable th,.rbtable td{border:1px solid var(--dis-edge);padding:5px 8px;
  text-align:left;line-height:1.4}
.rbtable th{background:var(--film-panel);color:var(--amber);
  font:500 10px/1.3 "IBM Plex Mono",monospace;letter-spacing:.1em;
  text-transform:uppercase}
.rbbody code{font-family:"IBM Plex Mono",monospace;font-size:12.5px;
  background:var(--film-panel);padding:1px 4px;border-radius:2px}


/* ---- coach: what the board cannot say for itself -------------------------
   Sits above the actions, in the one place a player is already looking when
   deciding what to do. Ranked, and capped at three lines: the failure mode of
   a hint system is volume, after which nobody reads the one that mattered. */
.coach{display:flex;flex-direction:column;gap:4px;margin-bottom:6px}
.coach .hint{display:flex;gap:.5rem;align-items:flex-start;
  font:400 11.5px/1.45 Bitter,Georgia,serif;color:var(--bone);
  background:var(--film-panel);border-left:2px solid var(--dis-ink);
  border-radius:0 3px 3px 0;padding:5px 8px}
.coach .hint .tag{font:600 8.5px/1.6 "IBM Plex Mono",monospace;letter-spacing:.12em;
  text-transform:uppercase;color:var(--dis-ink);flex:none;padding-top:1px}
.coach .hint.now{border-left-color:var(--amber)}
.coach .hint.now .tag{color:var(--amber)}
.coach .hint.watch{border-left-color:#6E93B8}
.coach .hint.watch .tag{color:#6E93B8}
.coach.hidden{display:none}


/* ---- first-run walkthrough -------------------------------------------------
   Same material as the front door, because it is the same moment: you tapped
   How to play and a page turned. A dark system dialog over cream paper read as
   an interruption from a different application. */
#modal.introsheet{background:rgba(38,49,59,.55)}
#modal.introsheet .sheet{
  width:min(40rem,100%);           /* NOT the 1000px card-browser sheet */
  background:#F1E7D0;color:#26313B;
  border:1px solid rgba(38,49,59,.35);border-radius:3px;
  padding:26px 30px 22px;
  background-image:repeating-linear-gradient(
    to bottom, transparent 0 33px, #BFCBD6 33px 34px);
  background-position:0 12px;
}
#modal.introsheet .x{color:rgba(38,49,59,.55)}
#modal.introsheet .x:hover{color:#26313B}

.intro{display:flex;flex-direction:column;gap:18px}
.introhead{display:flex;align-items:center;justify-content:space-between;gap:1rem}
.introhead h3{
  margin:0;font-family:Kalam,"Bradley Hand",cursive;font-weight:700;
  font-size:clamp(1.45rem,1.2rem + 1vw,1.95rem);line-height:1.15;color:#26313B;
}
.introdots{display:flex;gap:6px;flex:none}
.introdots .dot{width:7px;height:7px;border-radius:50%;background:rgba(38,49,59,.25)}
.introdots .dot.on{background:#F2C24E}
/* Fixed height so the pager never jumps between panels of different length,
   sized to the longest panel rather than padded with dead space. */
.introbody{display:flex;flex-direction:column;gap:.75rem;min-height:7.5rem}
.introbody p{margin:0;font:400 14.5px/1.65 Bitter,Georgia,serif;color:#26313B;
  max-width:44ch}
.introbody b{font-weight:700;border-bottom:2px solid #F2C24E}
.introfoot{display:flex;align-items:center;justify-content:space-between;gap:1rem;
  padding-top:4px;border-top:1px solid rgba(38,49,59,.20)}
.introfoot .pager{display:flex;gap:8px}
.introfoot button{
  font-family:Bitter,Georgia,serif;font-size:.9rem;font-weight:700;
  padding:.5rem .95rem;border-radius:2px;cursor:pointer;
  border:1px solid #26313B;background:transparent;color:#26313B;
}
.introfoot button.primary{background:#F2C24E;border-color:#C89A2C}
.introfoot button.primary:hover{background:#EFB93A}
.introfoot button.ghost:hover{background:rgba(38,49,59,.08)}
.introfoot button:disabled{opacity:.35;cursor:default}
.introfoot button.linkish{
  border:none;background:none;padding:.5rem 0;font-weight:400;
  color:rgba(38,49,59,.62);text-decoration:underline;text-underline-offset:3px;
}
.introfoot button.linkish:hover{color:#26313B}

/* =========================================================================
   THE FRONT DOOR
   The box lid, as a screen. Every colour here is sampled from
   print/box/luca-box-lid.png, so the first thing a player sees and the thing
   they will hold are the same object rather than two designs of the same name.

   The page is not a card floating on a background -- it IS ruled notebook
   paper, margin rule and all, and the menu entries are written ON the rules.
   ====================================================================== */
#setup{
  --paper:#F1E7D0; --rule:#BFCBD6; --marginrule:#E0C0AF;
  --pink:#26313B; --nink:#26313B; --nink-soft:rgba(38,49,59,.60);
  background:var(--paper);
  display:grid;justify-items:center;align-items:start;
  /* A BOUNDED height, or overflow-y never engages. body sets overflow:hidden --
     right for a game board, which must not scroll -- and .screen has no rule of
     its own, so this element grew past the viewport and the body simply clipped
     it. Opening the online panel put the room code and Join button below the cut
     with no way to reach them. */
  height:100dvh;overflow-y:auto;padding:0;
}
#setup .page{
  position:relative;width:min(46rem,100%);min-height:100%;
  padding:clamp(1.6rem,1rem + 3vw,3.2rem) clamp(1.4rem,1rem + 4vw,4rem)
          clamp(4rem,2rem + 6vw,6rem) clamp(3.2rem,2rem + 7vw,7rem);
  color:var(--nink);
  /* the ruled lines, drawn rather than imaged so they stay crisp at any zoom */
  background-image:repeating-linear-gradient(
    to bottom, transparent 0 33px, var(--rule) 33px 34px);
  background-position:0 6px;
}
#setup .pagerule{
  position:absolute;top:0;bottom:0;left:clamp(2.2rem,1.4rem + 5vw,5rem);
  width:2px;background:var(--marginrule);
}
#setup .eyebrow{
  font-size:11px;letter-spacing:.22em;text-transform:none;  /* the lid reads
     "lab notebook · vol. I · entry 001" -- lowercase words, uppercase numeral.
     No transform can do both, so the markup says it and CSS keeps its hands
     off. The culprit was .mono, which upper-cases globally -- correct for
     every label in the app, wrong for this one line. */
  color:var(--nink-soft);margin-bottom:clamp(1.5rem,4vh,3rem)
}

/* --- title block, composed as the lid composes it --- */
#setup .titleblock{text-align:center;margin-bottom:1.2rem}
#setup .wordmark{
  font-family:Kalam,"Bradley Hand",cursive;font-weight:700;
  font-size:clamp(4.2rem,3rem + 9vw,8.5rem);line-height:.86;
  letter-spacing:.04em;margin:0;color:var(--nink);
}
#setup .subtitle{
  font-family:Kalam,"Bradley Hand",cursive;
  font-size:clamp(1rem,.85rem + .7vw,1.45rem);
  margin:.35rem 0 .55rem;color:var(--nink)
}
#setup .titleline{height:2px;background:var(--nink);width:min(24rem,80%);margin:0 auto}

#setup .motif{display:block;width:clamp(9rem,26vw,14rem);height:auto;
  margin:.9rem auto .3rem;color:var(--nink)}
#setup .dots{display:flex;gap:.85rem;justify-content:center;margin:.9rem 0 2rem}
#setup .dots span{width:18px;height:18px;border-radius:50%}

/* --- the signature: entries written on the ruled lines --- */
#setup .entries{display:flex;flex-direction:column}
#setup .entry{
  all:unset;box-sizing:border-box;cursor:pointer;
  display:flex;align-items:baseline;gap:.9rem;flex-wrap:wrap;
  height:68px;padding:0 .5rem 0 0;
  border-bottom:1px solid transparent;   /* the page rule shows through */
}
#setup .entry .what{
  font-family:Kalam,"Bradley Hand",cursive;
  font-size:clamp(1.5rem,1.2rem + 1.3vw,2.15rem);line-height:1;color:var(--nink)
}
#setup .entry .note{
  font-family:Bitter,Georgia,serif;font-size:.83rem;color:var(--nink-soft)
}
#setup .entry.quiet .what{font-size:clamp(1.15rem,1rem + .7vw,1.5rem)}
/* hover/focus underlines the entry the way you would underline a line you
   meant to come back to -- not a button state, a reading state */
#setup .entry:hover .what,
#setup .entry:focus-visible .what,
#setup .entry.on .what{
  text-decoration:underline;text-decoration-thickness:3px;
  text-underline-offset:5px;text-decoration-color:#F2C24E;
}
#setup .entry:focus-visible{outline:2px solid var(--nink);outline-offset:3px;border-radius:2px}

/* --- mode panels --- */
#setup .panel{
  display:flex;flex-direction:column;gap:.7rem;
  margin:.4rem 0 1.4rem;padding:1rem 1.1rem;
  background:#FBF7EC;   /* opaque: ruled lines running through form labels
     read as a printing fault rather than as paper */
  border:1px solid rgba(38,49,59,.22);border-radius:3px;
  box-shadow:0 1px 0 rgba(38,49,59,.06);
}
#setup .panel.hidden{display:none}
#setup .panel .row{display:flex;align-items:center;justify-content:space-between;gap:1rem}
#setup .panel .row span{font-family:Bitter,Georgia,serif;font-size:.92rem}
#setup .panel input,#setup .panel select{
  font:inherit;font-size:.95rem;padding:.4rem .55rem;min-width:11rem;
  background:#FBF7EC;color:var(--nink);
  border:1px solid rgba(38,49,59,.35);border-radius:2px;
}
#setup .panel button{
  font-family:Bitter,Georgia,serif;font-size:.95rem;font-weight:700;
  padding:.55rem .9rem;cursor:pointer;border-radius:2px;
  border:1px solid var(--nink);background:transparent;color:var(--nink);
}
#setup .panel button.primary{background:#F2C24E;border-color:#C89A2C}
#setup .panel button:hover{background:rgba(38,49,59,.08)}
#setup .panel button.primary:hover{background:#EFB93A}
#setup .panel .hint{font-family:Bitter,Georgia,serif;font-size:.82rem;
  color:var(--nink-soft);margin:0}
#setup .panel .orline{display:flex;align-items:center;gap:.7rem;
  color:var(--nink-soft);font-size:.8rem;font-family:Bitter,Georgia,serif}
#setup .panel .orline::before,#setup .panel .orline::after{
  content:"";flex:1;height:1px;background:rgba(38,49,59,.25)}

/* --- badges, as circled on the lid --- */
#setup .badges{display:flex;gap:1.1rem;justify-content:center;margin-top:2rem}
#setup .badge{
  width:74px;height:74px;border-radius:50%;border:1.6px solid var(--nink);
  display:grid;place-items:center;align-content:center;gap:1px;
}
#setup .badge b{font-family:Kalam,cursive;font-size:1.25rem;font-weight:700;line-height:1}
#setup .badge i{font:400 8.5px/1 "IBM Plex Mono",monospace;font-style:normal;
  letter-spacing:.1em;color:var(--nink-soft)}

#setup .err{color:#B0301C;font-family:Bitter,Georgia,serif;font-size:.9rem;margin:.4rem 0 0}
#setup .err.hidden{display:none}

/* credits read as a notebook entry, not a dialog */
#setup .credits{font-family:Bitter,Georgia,serif;font-size:.9rem;line-height:1.65;
  color:var(--nink)}
#setup .credits p{margin:0 0 .6rem;max-width:34rem}
#setup .credits b{font-weight:700}

@media (max-width:560px){
  #setup .entry{height:60px}
  #setup .badges{gap:.7rem}
}


/* ---- guided first game ------------------------------------------------------
   A spotlight, not a modal. The board stays visible and stays real -- the bot
   plays, the rules apply -- so the scrim dims rather than covers, and the one
   thing a step is about is cut out of it and left clickable. */
#tut{position:fixed;inset:0;z-index:120;pointer-events:none}
/* Hide the moment a modal opens, in CSS rather than in JS.
   tutorialTick() runs after render(), and opening a card modal does not
   re-render -- so between the click and the next repaint the spotlight was
   still painted over the sheet. That is the flash. :has() has no such gap:
   the rule applies as #modal loses .hidden. The JS check stays as well, for
   tut-lock and for browsers without :has(). */
body:has(#modal:not(.hidden)) #tut{display:none !important}
.tut-hole{
  position:fixed;border-radius:4px;display:none;
  border:2px solid var(--amber);
  /* the cut-out: an enormous shadow dims everything except this rectangle */
  box-shadow:0 0 0 9999px rgba(10,9,7,.72), 0 0 18px rgba(242,194,78,.35);
  transition:top .18s ease,left .18s ease,width .18s ease,height .18s ease;
}
.tut-bubble{
  position:fixed;width:min(26rem,calc(100vw - 24px));pointer-events:auto;
  background:#F1E7D0;color:#26313B;border:1px solid rgba(38,49,59,.4);
  border-radius:3px;padding:16px 18px 13px;
  box-shadow:0 10px 34px rgba(0,0,0,.5);
}
.tut-text{margin:0 0 12px;font:400 13.5px/1.6 Bitter,Georgia,serif;color:#26313B}
.tut-foot{display:flex;align-items:center;gap:10px}
.tut-foot .tut-skip{
  border:none;background:none;padding:4px 0;cursor:pointer;
  font:400 12px/1 Bitter,Georgia,serif;color:rgba(38,49,59,.6);
  text-decoration:underline;text-underline-offset:3px;
}
.tut-foot .tut-skip:hover{color:#26313B}
.tut-count{margin-left:auto;font-size:9.5px;color:rgba(38,49,59,.5)}
.tut-foot .tut-next{
  font:700 13px/1 Bitter,Georgia,serif;padding:.5rem .9rem;cursor:pointer;
  border:1px solid #C89A2C;background:#F2C24E;color:#26313B;border-radius:2px;
}
.tut-foot .tut-next:hover{background:#EFB93A}

/* While a do-it step waits, the board is inert except for the spotlit thing.
   Without this a player can wander three moves past the lesson and the step
   sits there waiting for something that already happened. */
body.tut-lock #game{pointer-events:none}
body.tut-lock .tut-live{pointer-events:auto}
body.tut-lock .tut-live,
body.tut-lock .tut-live *{cursor:pointer}

@media (prefers-reduced-motion:reduce){ .tut-hole{transition:none} }
