/* The palette, the type and the photograph are not here: they are the theme, and
   every theme's values live in theme.css, which every page loads first. This file
   is the structure that reads them -- sizes, spacing, what is a card -- and must
   name no colour and no font family of its own, or one theme would be built into
   the parts that are meant to be shared. */

:root{
  /* One spacing scale. Every panel used to pick its own inset -- cards at 12, the map
     at 8, the legend at 6, the feed at 6/12/10 -- so nothing lined up across a row and
     the borders sat at different distances from their content. */
  --pad:12px; --pad-sm:8px;
}

*{box-sizing:border-box}
/* Sections are switched with the `hidden` attribute, and several of them carry an
   author `display` rule, which beats the user-agent `[hidden]{display:none}`.
   Without this, hiding a section does nothing. */
[hidden]{display:none!important}
body{
  margin:0; background:var(--bg); color:var(--ink);
  font-family:var(--font-text);
  font-size:14px; line-height:1.55;
  -webkit-font-smoothing:antialiased;
  padding:22px 18px 30px;
}
.wrap{max-width:1240px;margin:0 auto;display:flex;flex-direction:column;gap:14px}

h1,h2,h3{font-family:var(--font-display);font-weight:700;margin:0;text-wrap:balance}
h1{font-size:38px;line-height:1.08;letter-spacing:-.01em}
h2{font-size:22px}
.lede{color:var(--muted);font-size:13.5px;line-height:1.6;max-width:60ch;text-wrap:pretty}
.lede b{color:var(--ink);font-weight:600}

header{display:flex;flex-wrap:wrap;gap:12px 20px;align-items:flex-end;justify-content:space-between}

/* --- top bar -------------------------------------------------------------
   A wordmark and the controls, nothing else. The page used to open with a title and
   a paragraph explaining the project, which is the right opening for a design note
   and the wrong one for a game: the three numbered steps say what to do. */
.topbar{align-items:center}
.brand{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(--ink)}
.brandname{font-family:var(--font-display);font-weight:700;font-size:24px;line-height:1.05;
  letter-spacing:-.01em;white-space:nowrap}
.brandname i{font-style:italic;color:var(--muted)}
h1.hero{font-size:44px;margin:2px 0 2px;max-width:18ch}

.eyebrow{font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--muted);
  font-weight:600}

.card{background:var(--panel);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow)}
.card-h{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  padding:10px var(--pad);border-bottom:1px solid var(--line-soft)}
.card-h .t{font-family:var(--font-hand);font-weight:400;font-size:19px;
  letter-spacing:0;text-transform:none;color:var(--ink)}
.card-h .v{font-size:11.5px;color:var(--muted)}

/* match tabs */
.tabs{display:flex;gap:8px;flex-wrap:wrap}
.tab{appearance:none;cursor:pointer;text-align:left;background:var(--panel);color:var(--ink);
  border:1px solid var(--line);border-radius:9px;padding:8px 12px;display:flex;flex-direction:column;gap:2px;
  font-family:inherit;font-size:12px;min-width:150px}
.tab:hover{border-color:var(--muted)}
.tab[aria-selected="true"]{border-color:var(--flag);box-shadow:inset 0 0 0 1px var(--flag)}
.tab .tt{font-weight:600;letter-spacing:0}
.tab .ts{color:var(--muted);font-size:11px}

/* The curated-replay page still lays out as a board beside a column of readings;
   it is a watch-only page with no orders to give, so nothing there wants the width. */
.console{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:14px;align-items:start}
@media (max-width:880px){.console{grid-template-columns:minmax(0,1fr)}}
.right{display:flex;flex-direction:column;gap:14px;min-width:0}

/* --- the match: board full width, readings underneath ---------------------
   The board used to share a row with a 340px column of five stacked cards, which
   made the one thing you actually look at the smaller half of the screen. It is now
   full width, with the two panels you read *between* moves side by side below it. */
.underboard{display:grid;grid-template-columns:repeat(auto-fit,minmax(330px,1fr));
  gap:14px;align-items:start}
.rightcol{display:flex;flex-direction:column;gap:14px;min-width:0}

/* Live play: the two panels you read between moves are one row of equal height --
   forced, not hoped for, because the log below only lands flush if they agree -- and
   the log spans the full width underneath in two columns, which is twice the history
   for the same 158px. Watch mode has no orders panel, so none of this applies there
   and the log stays the right-hand column. */
.underboard[data-mode="live"]{align-items:stretch}
.underboard[data-mode="live"] #ordersCard{flex:1}
.underboard[data-mode="live"] .logcard{grid-column:1/-1}
.underboard[data-mode="live"] .logcard .feed{display:grid;
  grid-template-columns:1fr 1fr;gap:0 var(--pad);align-content:start}
@media (max-width:620px){
  .underboard[data-mode="live"] .logcard .feed{display:block}
}

/* Flag state absorbed the tilt table: "if delivered now" was never a separate
   subject, it is what the flag's current position is worth. */
.flagpanel{display:grid;grid-template-columns:minmax(200px,1fr) minmax(190px,1.15fr);
  gap:var(--pad) 16px;padding-top:var(--pad-sm);align-items:start}
@media (max-width:620px){.flagpanel{grid-template-columns:minmax(0,1fr)}}
.flagviz{min-width:0}
.flagtilts{min-width:0}
.subhead{display:flex;align-items:baseline;justify-content:space-between;gap:10px;
  font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
  font-weight:600;padding-bottom:5px;margin-bottom:3px;
  border-bottom:1px solid var(--line-soft)}

/* Gates in hand: one strip above the board, read at a glance between moves. */
.handstrip{display:flex;flex-wrap:wrap;align-items:center;gap:var(--pad-sm) 14px;
  padding:var(--pad-sm) var(--pad)}
.handstrip #hands{display:flex;flex-wrap:wrap;align-items:center;gap:6px 16px}
.peerrow{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px}
.peerrow input[type=text]{font-family:var(--font-mono);font-size:12px;width:110px;
  padding:5px 8px;text-transform:uppercase;background:var(--panel-2);color:var(--ink);
  border:1px solid var(--line);border-radius:7px}
#peersetup{display:flex;flex-direction:column;gap:7px;padding-top:2px;
  border-top:1px dotted var(--line-soft);margin-top:2px}
.readout.warn{color:var(--t1);font-weight:600}
#peerbar code{font-family:var(--font-mono);font-size:11.5px}

/* The board card carries the same inset as every other card, so the map's left edge
   lines up with the panel headings underneath it. At 8px against everyone else's 12px
   it was out by four pixels down the whole page. */
.mapbox{padding:var(--pad);background:var(--board-bg)}

/* --- the end of a match --------------------------------------------------
   A finished match used to be indistinguishable from one in progress: same board,
   same panels, the outcome a small line further down the page. The scrim is what
   says "stop reading the board"; the colour says who won before any word is read. */
.endwrap{position:relative}
.endcard{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:10px;text-align:center;
  padding:var(--pad);border-radius:8px;
  background:color-mix(in srgb, var(--panel) 86%, transparent);
  backdrop-filter:blur(2.5px);animation:endin .28s ease-out}
@keyframes endin{from{opacity:0;transform:scale(.985)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){.endcard{animation:none}}
/* The verdict ("You win") is the big headline now; who-and-how is the
   smaller line underneath it, since the immediate result is what a player
   reads first and the specifics ("Team 0 takes the flag") come second. */
.endcard .verdict{font-family:var(--font-display);font-weight:700;
  font-size:clamp(34px,6vw,60px);line-height:1.03;letter-spacing:-.015em}
.endcard .who{font-size:20px;font-weight:600;letter-spacing:0}
.endcard .how{color:var(--muted);font-size:13px;max-width:46ch;line-height:1.55;
  text-wrap:pretty;margin:0}
.endcard .odds{display:flex;gap:18px;align-items:baseline;font-size:12.5px;
  color:var(--muted);flex-wrap:wrap;justify-content:center}
.endcard .odds b{font-family:var(--font-mono);font-size:15px;color:var(--ink)}
.endcard .again{display:flex;gap:8px;flex-wrap:wrap;justify-content:center;margin-top:2px}
.endcard .endclose{margin-top:4px}
/* Just the flag, large, above the rest of the card -- no badge circle behind
   it. The flag is masked rather than filtered: flag.svg supplies the shape and
   the colour comes from background-color on the masked element, so one file
   serves every colour the card can end up in. A mask image is same-origin only,
   which is why this looks unmasked over file:// and correct everywhere real. */
.endcard .rosette{display:flex;align-items:center;justify-content:center;margin-bottom:4px}
.rosette-flag{display:block;width:110px;height:110px;
  -webkit-mask:url(flag.svg) center/contain no-repeat;
  mask:url(flag.svg) center/contain no-repeat;
  background-color:var(--ink)}
.endcard.t0 .rosette-flag{background-color:var(--t0)}
.endcard.t1 .rosette-flag{background-color:var(--t1)}
.endcard.t0 .who{color:var(--t0)} .endcard.t1 .who{color:var(--t1)}
.endcard.t0 .verdict{color:var(--t0)} .endcard.t1 .verdict{color:var(--t1)}
svg{display:block;max-width:100%;height:auto}
/* blochkit fills its container, so the panel says how big the sphere is. */
#bloch svg{max-width:250px;margin:0 auto 6px}

/* readouts */
.pad{padding:var(--pad)}
.row{display:flex;align-items:center;gap:8px}
.between{justify-content:space-between}
.num{font-family:var(--font-mono);font-variant-numeric:tabular-nums}

.scorebar{height:26px;border-radius:6px;overflow:hidden;display:flex;border:1px solid var(--line)}
.scorebar i{display:block;height:100%;transition:width .18s ease}
.s0{background:var(--t0)} .s1{background:var(--t1)}
.scorelab{display:flex;justify-content:space-between;font-size:11.5px;margin-top:7px;color:var(--muted)}
.scorelab b{font-weight:600;font-size:13px;font-family:var(--font-mono)}
.c0{color:var(--t0)} .c1{color:var(--t1)}

table{width:100%;border-collapse:collapse;font-size:12px;font-family:var(--font-mono)}
th,td{text-align:left;padding:4px 0;border-bottom:1px solid var(--line-soft)}
th{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);
  font-weight:600;font-family:var(--font-text)}
tr:last-child td{border-bottom:none}
/* The applied record. It scrolls rather than growing, because it shares a row with
   the sphere and the sphere's height is what the panel is for. Newest is at the
   bottom, and renderApplied keeps it in view. */
.applied{max-height:184px;overflow-y:auto;font-family:var(--font-mono);font-size:12px}
.arow{display:grid;grid-template-columns:22px 1fr 28px 52px 1fr;gap:7px;
  align-items:center;padding:4px 0;border-bottom:1px solid var(--line-soft)}
.arow:last-child{border-bottom:none}
.arow .r{color:var(--muted);font-size:10.5px;text-align:right}
.arow .g{font-weight:600;white-space:nowrap}
.arow .w{color:var(--muted);font-size:10.5px}
.arow .num{font-variant-numeric:tabular-nums;text-align:right}
/* A gate that landed in the same round as another: they added their generators and
   turned the flag once, so the number beside it is the round's and not its own. */
.arow .together{font-style:normal;color:var(--muted);margin-left:3px}
.applied .empty{color:var(--muted);margin:6px 0 0;font-size:11.5px}

.dz{width:112px}
.dzbar{position:relative;height:9px;background:var(--panel-2);border-radius:3px;overflow:hidden}
.dzbar i{position:absolute;top:0;bottom:0;display:block}
.dzbar .mid{position:absolute;left:50%;top:0;bottom:0;width:1px;background:var(--line);z-index:2}

.feed{height:158px;overflow-y:auto;padding:var(--pad-sm) var(--pad) var(--pad)}
.ev{display:grid;grid-template-columns:30px 1fr;gap:9px;padding:4px 0;
  border-bottom:1px dotted var(--line-soft);font-size:12px;line-height:1.45}
.ev:last-child{border-bottom:none}
.ev .r{color:var(--muted);font-family:var(--font-mono);font-variant-numeric:tabular-nums;
  font-size:11px;text-align:right}
.ev .k{font-weight:600}

/* transport */
.transport{padding:var(--pad);display:flex;flex-direction:column;gap:var(--pad-sm)}
.controls{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
button.btn{appearance:none;font-family:inherit;font-size:12.5px;cursor:pointer;
  background:var(--panel-2);color:var(--ink);border:1px solid var(--line);border-radius:7px;padding:6px 12px;font-weight:500}
button.btn:hover{border-color:var(--muted)}
button.btn[aria-pressed="true"]{background:var(--flag);border-color:var(--flag);color:var(--on-flag)}
.spacer{flex:1 1 auto}
.readout{font-size:12.5px;color:var(--muted)}
.readout b{color:var(--ink);font-weight:600;font-family:var(--font-mono);
  font-variant-numeric:tabular-nums;font-size:12px}

.track{position:relative;width:100%}
#scrub{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:pointer}
:focus-visible{outline:2px solid var(--flag);outline-offset:2px;border-radius:4px}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* --- tournament results ------------------------------------------------- */
#results{display:flex;flex-direction:column;gap:14px}
.standrow{display:grid;grid-template-columns:72px 1fr 52px;align-items:center;gap:8px;
  padding:5px 0;border-bottom:1px solid var(--line-soft)}
.standrow:last-child{border-bottom:none}
.sname{font-size:12px;font-weight:600;font-family:var(--font-mono)}
.sbar{height:12px;background:var(--panel-2);border-radius:3px;overflow:hidden}
.sbar i{display:block;height:100%;background:var(--flag);border-radius:3px}
.sval{font-size:12px;text-align:right;color:var(--muted)}

table.matrix{width:100%;border-collapse:separate;border-spacing:2px;font-size:11.5px;
  font-family:var(--font-mono);font-variant-numeric:tabular-nums}
table.matrix th{font-size:10px;letter-spacing:.06em;text-transform:uppercase;
  color:var(--muted);font-weight:600;padding:2px;border:none;text-align:center}
table.matrix th.rowname{text-align:right;padding-right:6px;text-transform:none;
  letter-spacing:0;font-size:11px;color:var(--ink);white-space:nowrap}
table.matrix td{text-align:center;padding:6px 2px;border-radius:4px;border:none;
  color:var(--ink);cursor:default}
table.matrix td.self{color:var(--muted)}

/* --- setup page ---------------------------------------------------------- */
/* Both views stack cards, and both need the same gap between them. #board had no rule
   at all -- it was a plain block, so its cards sat flush against each other and only the
   grids inside it had any spacing. */
#setup,#board{display:flex;flex-direction:column;gap:14px}
button.btn.primary{background:var(--flag);border-color:var(--flag);color:var(--on-flag);font-weight:600}
button.btn:disabled,.chip:disabled,select:disabled,input:disabled{opacity:.45;cursor:not-allowed}
a.btn{display:inline-block;color:var(--ink)}

.chips{display:flex;flex-wrap:wrap;gap:6px}
.chip{appearance:none;font-family:var(--font-mono);font-size:11.5px;cursor:pointer;
  background:var(--panel-2);color:var(--ink);border:1px solid var(--line);
  border-radius:999px;padding:4px 11px;font-weight:500;min-width:34px}
.chip:hover:not(:disabled){border-color:var(--muted)}
.chip[aria-pressed="true"]{background:var(--line-strong);border-color:var(--line-strong);color:var(--panel)}

.launch{display:flex;flex-wrap:wrap;align-items:center;gap:10px}
.launch .seed{display:flex;align-items:center;gap:6px;font-size:12px;color:var(--muted)}
input[type=number]{font-family:var(--font-mono);font-size:12px;width:96px;padding:5px 8px;
  background:var(--panel-2);color:var(--ink);border:1px solid var(--line);border-radius:7px}
/* Errors are `rough`, the same gold that nags about a player without orders: it
   belongs to neither side, and team-1 -- which used to carry this -- is white in the
   default palette, where an error then reads as ordinary emphasis. */
.problems{border-color:var(--rough);color:var(--rough);font-size:12px;display:flex;
  flex-direction:column;gap:4px}
.problems p{margin:0}

/* rule groups: one <details> per section of the variant matrix */
#ruleform{display:flex;flex-direction:column;gap:10px}
.group summary{cursor:pointer;display:flex;align-items:baseline;justify-content:space-between;
  gap:10px;padding:9px 12px;list-style:none}
.group summary::-webkit-details-marker{display:none}
.group summary::before{content:"\25B8";color:var(--muted);margin-right:7px;font-size:10px}
.group[open] summary::before{content:"\25BE"}
.group summary .t{font-size:10.5px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--muted);font-weight:600;flex:1 1 auto}
.group summary .v{font-size:11.5px;color:var(--muted)}
.group[open] summary{border-bottom:1px solid var(--line-soft)}

.knobs{display:flex;flex-direction:column;gap:9px}
.knob{padding-bottom:8px;border-bottom:1px dotted var(--line-soft)}
.knob:last-child{border-bottom:none;padding-bottom:0}
.knob-h{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:8px}
.knob-n{font-size:13px;font-weight:600}
.knob-help{color:var(--muted);font-size:11.5px;line-height:1.5;margin:3px 0 0;max-width:68ch}
.knob.off .knob-n{color:var(--muted)}
.knob.off .knob-help{color:var(--t1);opacity:.85}

select{font-family:var(--font-mono);font-size:12px;padding:5px 8px;max-width:100%;
  background:var(--panel-2);color:var(--ink);border:1px solid var(--line);border-radius:7px}
.slider{display:flex;align-items:center;gap:9px}
.slider input[type=range]{width:180px;accent-color:var(--flag)}
.slider b{font-size:12.5px;min-width:42px;text-align:right;font-family:var(--font-mono);
  font-variant-numeric:tabular-nums}

@media (max-width:880px){
  .slider input[type=range]{width:130px}
  .knob-h{flex-direction:column;align-items:flex-start}
}

/* --- boot ----------------------------------------------------------------
   The deployed build fetches a Python runtime before it can do anything, so this
   is on screen for seconds. It says which slow thing is happening; a spinner says
   only that something is. */
.boot{display:flex;flex-direction:column;align-items:center;gap:11px;text-align:center;
  padding:30px var(--pad) 26px}
/* The flag fills as the boot advances -- the same number the bar reports, in the
   page's own picture rather than a second widget. The mask clips the fill to the
   drawing, so the raising happens inside the shape. */
.bootflag{position:relative;display:block;width:78px;height:78px;
  background:color-mix(in srgb, var(--muted) 38%, transparent);
  -webkit-mask:url(flag.svg) center/contain no-repeat;
  mask:url(flag.svg) center/contain no-repeat}
.bootflag i{position:absolute;left:0;right:0;bottom:0;height:0;background:var(--flag);
  transition:height .35s ease}
.bootmsg{margin:0;font-size:13.5px;font-weight:600;color:var(--ink)}
.bootbar{display:block;width:min(340px,100%);height:6px;background:var(--panel-2);
  border:1px solid var(--line);border-radius:999px;overflow:hidden}
.bootbar i{display:block;height:100%;width:0;background:var(--flag);border-radius:999px;
  transition:width .35s ease}
.boothint{margin:0;max-width:46ch;font-size:11.5px;line-height:1.5;color:var(--muted)}
/* A failure is the same panel with the moving parts gone: a bar frozen at 40% under
   an error is a page that looks like it is still trying. */
.boot.failed .bootbar,.boot.failed .bootflag{display:none}
.boot.failed .bootmsg{color:var(--rough)}

/* --- homepage ------------------------------------------------------------ */
.homegrid{display:grid;grid-template-columns:minmax(0,1fr);
  gap:18px;align-items:start}
@media (max-width:900px){.homegrid{grid-template-columns:minmax(0,1fr)}}
.homemain{display:flex;flex-direction:column;gap:10px}
.homemain .lede{max-width:60ch;margin:0}
.tiles{margin-top:4px}
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:12px}
.tile{display:flex;flex-direction:column;gap:5px;text-decoration:none;color:var(--ink);
  background:var(--panel);border:1px solid var(--line);border-radius:10px;
  box-shadow:var(--shadow);padding:15px 16px 14px;transition:border-color .15s ease}
.tile:hover{border-color:var(--flag)}
.tile-k{font-size:10.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted);
  font-weight:600}
.tile-t{font-family:var(--font-display);font-size:23px;font-weight:400;letter-spacing:0;
  line-height:1.15}
.tile-d{color:var(--muted);font-size:12.5px;line-height:1.55;flex:1 1 auto}
.tile-go{font-size:12px;font-weight:600;color:var(--flag);margin-top:2px}
.tile.primary{border-color:var(--flag);box-shadow:inset 0 0 0 1px var(--flag),var(--shadow)}
.tile.primary .tile-k{color:var(--flag)}

/* The match status bar. It had no layout rule at all, so its `.spacer` did nothing
   and the buttons sat in the middle of a wrapped run of text. */
.statusbar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px}
.statusbar .readout{display:inline-flex;align-items:baseline;gap:5px;white-space:nowrap}
.statusbar .readout + .readout::before{content:"";width:1px;height:11px;
  background:var(--line);margin-right:9px}
#statusWho{font-weight:600;color:var(--ink)}
#outcome{font-weight:600;color:var(--ink)}
#matchmeta .readout{margin:0}

/* --- playing a round yourself -------------------------------------------- */

.orderrow{display:flex;flex-wrap:wrap;align-items:center;gap:6px;padding:6px var(--pad-sm);
  border:1px solid var(--line-soft);border-radius:8px;background:var(--panel-2)}
.orderrow.sel{border-color:var(--flag);box-shadow:inset 0 0 0 1px var(--flag)}
/* Still waiting on you. Not the same as "no order this round" -- a walk or a hold is a
   decision already taken, and marking those too made the panel nag about nothing. */
.orderrow.awaiting{border-color:var(--rough);
  background:color-mix(in srgb, var(--rough) 9%, var(--panel-2))}
.orderrow.awaiting.sel{border-color:var(--flag)}
.awaitmark{font-size:10px;letter-spacing:.09em;text-transform:uppercase;font-weight:600;
  color:var(--rough);margin-left:2px}
.card-h .v.warn{color:var(--rough);font-weight:600}
.orderwho{appearance:none;font-family:var(--font-mono);font-size:12px;cursor:pointer;
  background:none;border:none;color:var(--ink);padding:0 4px 0 2px;text-align:left;flex:1 1 auto}
.orderwho .tok{font-weight:600;color:var(--flag)}
.orderwho .dim{color:var(--muted)}
.orderacts{display:flex;gap:4px;flex-wrap:wrap}
.orderlist{display:flex;flex-direction:column;gap:6px}
.orderbtns{padding-top:0;display:flex;gap:var(--pad-sm);flex-wrap:wrap}
.orderhelp{padding:0 var(--pad) var(--pad);margin:0}
.pad.tight{padding-top:var(--pad-sm)}
#map path[fill="transparent"]{cursor:pointer}
/* A wall is hoverable for its explanation and not clickable: nobody walks there. */
#map path[data-wall]{cursor:help}
.chip.hit{border-color:var(--t1);color:var(--t1);font-weight:600}
.chip.hit[aria-pressed="true"]{background:var(--t1);border-color:var(--t1);color:var(--panel)}
.chip.pickup{border-color:var(--good);color:var(--good);font-weight:600}
.chip.pickup[aria-pressed="true"]{background:var(--good);border-color:var(--good);color:var(--panel)}
.orderwho .onGate{color:var(--good)}

/* The Bloch axes (--ax-x/y/z) are muted on purpose: the state vector is --flag and
   must stay the most prominent thing in the picture. Their values are in theme.css
   with the rest of the palette. */
/* Applied by scripts/build_browser.py, not by any source page: the deployed build
   drops the two replay tiles, and the remaining one should stay card-sized rather
   than stretching across the column. */
.tiles.solo{grid-template-columns:minmax(0,340px)}

/* player pickers */
/* The setup reads as three numbered steps: who plays, which rules, start.
   The accent rail down the left edge is what makes them a sequence rather than three
   unrelated cards -- it is the only thing distinguishing this from the old layout at a
   glance, and the numbering alone was too quiet to do it. */
.step{display:flex;flex-direction:column;gap:11px;position:relative;
  padding-left:15px;overflow:hidden}
.step::before{content:"";position:absolute;left:0;top:0;bottom:0;width:3px;
  background:var(--line);transition:background .18s ease}
.step:focus-within::before{background:var(--flag)}
/* Handwritten, like the landing page's captions -- the numbering that used to
   sit in a circle before each title is gone; card order alone carries the
   sequence now. */
.step .eyebrow{display:flex;align-items:center;gap:9px;color:var(--ink);
  font-family:var(--font-hand);font-weight:400;font-size:24px;
  text-transform:none;letter-spacing:0;padding-left:14px}
.step.launch{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px}
.step.launch .btn.primary{padding:8px 18px;font-size:13px}

/* "Custom" is not another preset -- it opens the rule form. Dashed, so it reads as a
   door rather than as a seventh thing you could have picked. */
.chip[data-name="custom"]{border-style:dashed}
.chip[data-name="custom"]::before{content:"+ ";opacity:.7}
.chip[data-name="custom"][aria-pressed="true"]{border-style:solid}

/* Colour-coded pickers: the same two colours the board, the score bar and the Bloch
   sphere use, so the convention is taught once and never explained. */
.teampick{padding-left:11px;border-left:3px solid var(--line)}
.players .teampick:first-child{border-left-color:var(--t0)}
.players .teampick:last-child{border-left-color:var(--t1)}

.group summary:hover .t{color:var(--ink)}
.players{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px}
.teampick{display:flex;flex-direction:column;gap:5px;min-width:0}
.teamlab{font-size:12px;font-weight:600;display:flex;gap:7px;align-items:baseline}
.teamlab span{font-weight:400;color:var(--muted);font-size:11px}
.teampick select{width:100%;font-size:13px;padding:7px 9px}
.teamdoc{margin:0;color:var(--muted);font-size:11.5px;line-height:1.5;min-height:2.6em}
#presetHelp{margin:0;min-height:1.4em}
.hand{display:flex;align-items:center;gap:7px}
.handlab{font-size:11.5px;font-weight:600}
.handgates{display:flex;flex-wrap:wrap;gap:5px;align-items:center}
.handgate{font-family:var(--font-mono);font-size:12px;padding:1px 6px;border-radius:6px;
  background:var(--panel-2);border:1px solid var(--line);cursor:help}
.handgates .unknown{font-style:normal;font-size:11.5px;color:var(--muted)}
.chip.goto{border-color:var(--good);color:var(--good)}
.chip.goto[aria-pressed="true"]{background:var(--good);border-color:var(--good);color:var(--panel)}

/* --- what a gate does: the hover tip -------------------------------------
   Never takes the pointer: it is placed beside whatever is hovered, and a tip that
   could land under the cursor would flicker itself in and out. */
.gtip{position:fixed;z-index:60;width:214px;pointer-events:none;
  background:var(--panel);border:1px solid var(--line);border-radius:10px;
  box-shadow:var(--shadow);padding:9px 10px 10px}
.gtip-h{display:flex;align-items:baseline;justify-content:space-between;gap:8px}
.gtip-n{font-family:var(--font-mono);font-size:15px;font-weight:600}
.gtip-s{font-family:var(--font-mono);font-size:10.5px;color:var(--muted);text-align:right}
.gtip-c{margin:1px 0 3px}
.gtip-f{display:flex;flex-direction:column;gap:2px}
.gtip-row{display:flex;align-items:baseline;gap:7px;font-size:11.5px;
  font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.gtip-row .k{color:var(--muted);width:10px;flex:none}
.gtip-row .num{flex:1 1 auto}
.gtip-v{margin:5px 0 0;padding-top:5px;border-top:1px solid var(--line-soft);
  font-size:11px;line-height:1.45;color:var(--muted)}
.gtip-v b{color:var(--ink);font-weight:600}
tr[data-gate],.tok[data-gate],.arow[data-gate]{cursor:help}
.arow:hover{background:var(--panel-2)}
