/*
 * Contested Realm — the client's whole stylesheet.
 *
 * The palette comes off the cards themselves: Sorcery's frames are dark with
 * old-gold ornament, and the art is heavy on teal, so the ground is a deep
 * blue-green and the accent is that gold. The four elements keep their own
 * colours throughout — thresholds, costs and card edges all read from the
 * same four hues, because element is the thing a player is always counting.
 *
 * One display face (Marcellus, roman capitals) for headings only; everything
 * that is operated rather than read is set in Alegreya Sans, which keeps its
 * numerals legible at the sizes the board needs.
 */

:root {
    --ground: #0d1315;
    --ground-deep: #070b0c;
    --panel: #151f21;
    --panel-high: #1d292c;
    --edge: #2b3a3d;
    --edge-bright: #3d5257;
    --ink: #e9e3d5;
    --ink-dim: #9aa8aa;
    --ink-faint: #66767a;
    --gold: #c9a227;
    --gold-dim: #8a7020;
    --air: #7fb8d4;
    --earth: #94a55e;
    --fire: #cd5f3c;
    --water: #4f86bd;
    --danger: #c0503f;
    --good: #6f9f6a;
    /* A card shown before its set is out, wherever a deck is made. */
    --unreleased: #e5322d;
    /* Two ways of being stopped that the picture cannot show: silence takes
       a card's text away, disabling takes its actions away. Neither is one
       of the four elements, so they get hues the board uses nowhere else. */
    --silenced: #d98ac0;
    --disabled: #9d7bd6;

    --card-ratio: 380 / 531;
    --radius: 3px;
    --shadow: 0 2px 10px rgba(0, 0, 0, .5);

    --display: "Marcellus", "Palatino Linotype", Palatino, Georgia, serif;
    --body: "Alegreya Sans", "Avenir Next", "Segoe UI", system-ui, sans-serif;
}

/*
 * The same board for eyes that do not tell red from green.
 *
 * Every hue that carries a meaning of its own is swapped for one from the
 * Okabe-Ito set, which was chosen to stay apart under every common kind of
 * colour blindness: the pairs that matter here are mine/theirs (gold and
 * vermilion), can/cannot (sky blue and vermilion) and silenced/disabled
 * (yellow and reddish purple). And the two stopped states get a border
 * style each as well, so they are told apart with no colour at all.
 */
html.colorblind {
    --good: #56b4e9;
    --danger: #d55e00;
    --silenced: #f0e442;
    --disabled: #cc79a7;
}
html.colorblind .unit.silenced, html.colorblind .site-art.silenced { border-style: dashed; }
html.colorblind .unit.disabled, html.colorblind .site-art.disabled { border-style: double; border-width: 3px; }

/* A checkbox with its words, in the bar. */
.toggle {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    margin: 0;
    font-size: .72rem;
    /* Not the form label it would otherwise be styled as: no capitals, no
       spacing, no margin under it. */
    text-transform: none;
    letter-spacing: 0;
    color: var(--ink-dim);
    white-space: nowrap;
    cursor: pointer;
    user-select: none;
}
/* A checkbox, not the text field the generic input rule dresses every input
   as: Safari laid it out full width with the field's padding and pushed the
   label's words out over whatever stood beside it. */
.toggle input {
    width: auto;
    flex: 0 0 auto;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
}

* { box-sizing: border-box; }

html, body {
    height: 100%;
}

body {
    margin: 0;
    background:
        radial-gradient(120% 90% at 50% 0%, #14202300 0%, var(--ground-deep) 100%),
        var(--ground);
    color: var(--ink);
    font-family: var(--body);
    font-size: 15px;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
    font-family: var(--display);
    font-weight: 400;
    letter-spacing: .02em;
    margin: 0;
    text-wrap: balance;
}

h1 { font-size: 1.4rem; }

/* The state of the place, beside its name in the main hall. Set apart rather
   than run on, so the name still reads as the name. */
.beta {
    font-family: var(--body);
    font-size: .62rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .18em;
    color: var(--gold-dim);
    border: 1px solid var(--gold-dim);
    border-radius: 2px;
    padding: .12rem .4rem;
    margin-left: 1.1rem;
    vertical-align: middle;
    white-space: nowrap;
}
/* Where to send bug reports, beside the beta badge that invites them. Set in
   the body face at reading size rather than as another badge: it is a
   sentence to be read once, not a label to be glanced at. Wraps under the
   name on a narrow window rather than pushing it off the edge. */
.bug-report {
    font-family: var(--body);
    font-size: .72rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink-faint);
    margin-left: 1.1rem;
    vertical-align: middle;
}

.bug-report a {
    color: var(--gold-dim);
}

/* The small print's two pages, after the bug line and as quiet as it. */
.legal-links {
    font-family: var(--body);
    font-size: .72rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
    color: var(--ink-faint);
    margin-left: 1.1rem;
    vertical-align: middle;
}
.legal-links a { color: var(--gold-dim); }

h2 { font-size: 1.05rem; color: var(--gold); margin-bottom: .5rem; }
h3 {
    font-size: .8rem;
    text-transform: uppercase;
    letter-spacing: .14em;
    color: var(--ink-faint);
}

/* Only the screen the body names is on. The showing rules are compounded so
   they outrank each screen's own id selector; a bare `main { display: none }`
   loses to `#gate { display: grid }` and every screen stacks up at once. */
main { display: none; }
body[data-screen="gate"] #gate { display: grid; }
body[data-screen="table"] #table { display: flex; }
body[data-screen="builder"] #builder { display: block; }
body[data-screen="replay"] #replay { display: flex; }

/* The hall is the height of the screen and no taller: the tables and the
   controls take what they need, and the chat takes the rest and scrolls
   inside it. Left to grow, a busy evening's chat pushed the whole page off
   the bottom and the only way to the newest line was to scroll the window. */
body[data-screen="lobby"] #lobby {
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
}

/* ---------- controls ---------- */

button {
    font: inherit;
    font-size: .9rem;
    color: var(--ink);
    background: var(--panel-high);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: .4rem .85rem;
    cursor: pointer;
    transition: border-color .12s, background .12s, color .12s;
}

button:hover { border-color: var(--edge-bright); background: #243236; }
button:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
button:disabled { opacity: .4; cursor: not-allowed; }

button.primary {
    background: linear-gradient(#3a3013, #241e0c);
    border-color: var(--gold-dim);
    color: #f0e2b4;
}
button.primary:hover { border-color: var(--gold); background: linear-gradient(#4a3d18, #2e260f); }
button.wide { width: 100%; margin-top: .6rem; }

input, select {
    font: inherit;
    width: 100%;
    color: var(--ink);
    background: var(--ground-deep);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: .4rem .55rem;
}

input:focus, select:focus { outline: none; border-color: var(--gold-dim); }

label {
    display: block;
    margin-bottom: .6rem;
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--ink-faint);
}

label input, label select { margin-top: .25rem; text-transform: none; letter-spacing: 0; }

.row { display: flex; gap: .5rem; }
.row button { flex: 1; }
.muted { color: var(--ink-faint); font-size: .8rem; }
.error { color: var(--danger); font-size: .85rem; margin: .6rem 0 0; }
.tally { color: var(--ink-dim); font-size: .85rem; font-variant-numeric: tabular-nums; }

/* ---------- signing in ---------- */

#gate {
    /* min-height, not height, and it scrolls: the card is centred in a tall
       window and the small print below it has to stay reachable in a short
       one, rather than being cut off at the bottom of the viewport. */
    min-height: 100%;
    place-items: center;
    align-content: center;
    padding: 2rem;
    overflow-y: auto;
}

.gate-card {
    width: min(340px, 100%);
    background: var(--panel);
    border: 1px solid var(--edge);
    border-top: 2px solid var(--gold-dim);
    border-radius: var(--radius);
    padding: 1.8rem;
    box-shadow: var(--shadow);
}

/* ---------- Discord ---------- */

/* Discord's own blurple, so the way in through Discord is recognisably
   Discord's; everything else on the gate stays the site's. */
button.discord {
    background: #5865f2;
    border-color: #5865f2;
    color: #ffffff;
}
button.discord:hover { background: #4752c4; border-color: #4752c4; }

#discord-connect { margin-top: .8rem; }

.discord-dialog {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: grid;
    place-items: center;
    padding: 1rem;
    background: rgba(0, 0, 0, .72);
}
.discord-dialog[hidden] { display: none; }

.discord-box {
    width: min(440px, 100%);
    max-height: 92vh;
    overflow: auto;
    padding: 1.2rem 1.3rem;
    background: var(--panel);
    border: 1px solid var(--edge-bright);
    border-top: 2px solid var(--gold-dim);
    border-radius: 6px;
    box-shadow: var(--shadow);
}
.discord-head { display: flex; align-items: center; justify-content: space-between; }
.discord-head h2 { margin: 0; }
.discord-close { padding: 0 .55rem; font-size: 1.2rem; line-height: 1.5; }

.discord-choice { padding: .9rem 0; border-bottom: 1px solid var(--edge); }
.discord-choice:last-of-type { border-bottom: none; padding-bottom: .2rem; }
.discord-choice h3 { margin: 0 0 .3rem; color: var(--ink-dim); }
.discord-choice p,
.discord-note {
    margin: 0 0 .6rem;
    font-size: .82rem;
    line-height: 1.45;
    color: var(--ink-dim);
}
.discord-choice form { margin-top: .2rem; }

/* A word after signing in, for a moment: linked, or signed in already. */
#notice {
    position: fixed;
    top: 1rem;
    left: 50%;
    z-index: 70;
    transform: translateX(-50%);
    max-width: min(520px, calc(100vw - 2rem));
    padding: .6rem .9rem;
    background: var(--panel-high);
    border: 1px solid var(--gold-dim);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    color: var(--ink);
    font-size: .88rem;
}
#notice[hidden] { display: none; }

/* The small print under the card: what the game is, and whose it is. Set
   narrow and quiet -- it is there to be read once and then not again, so it
   must not compete with the two fields above it. */
.gate-print {
    width: min(540px, 100%);
    margin-top: 1.6rem;
    color: var(--ink-faint);
    font-size: .74rem;
    line-height: 1.65;
    text-align: center;
}

.gate-print p + p {
    margin-top: .7rem;
}

/* Underlined rather than coloured: the print is quiet on purpose, and a link
   in it should read as a link without becoming the brightest thing there. */
.gate-print a {
    color: var(--ink-dim);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.gate-print a:hover,
.gate-print a:focus-visible {
    color: var(--gold);
}

/* How busy the server is, between the card and the small print. The two
   lines of history are quiet; the room as it is now is set larger, being
   the part worth a glance before signing in. */
.gate-stats {
    width: min(540px, 100%);
    margin-top: 1.4rem;
    color: var(--ink-dim);
    font-size: .85rem;
    line-height: 1.6;
    text-align: center;
    font-variant-numeric: lining-nums tabular-nums;
}

.gate-stats p { margin: 0; }

.gate-stats b {
    color: var(--gold);
    font-weight: 700;
}

.gate-now {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .2rem 2rem;
    margin-top: .7rem;
    color: var(--ink);
    font-family: var(--display);
    font-size: 1.2rem;
}

.gate-now b { font-weight: 400; }

/* The counts in the body face: the display face's 0 is a round O and its 1
   an I, which is fine in a word and wrong in a number. */
.gate-count {
    font-family: var(--body);
    font-weight: 700;
}

.gate-card h1 { font-size: 1.6rem; text-align: center; }

/* The wordmark stands in for the title and the tagline both -- it says
   "Sorcery / Contested Realm" itself, so repeating either in text beneath it
   would be saying the same thing twice. Still an h1, with the words in the
   alt text, so the page keeps its heading and a screen reader keeps the name.
   Width and height are on the img as well so nothing jumps while it loads. */
.gate-logo {
    margin: 0 0 1.5rem;
    line-height: 0;
}

.gate-logo img {
    display: block;
    width: 100%;
    height: auto;
}

/* ---------- shared chrome ---------- */

.bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .7rem 1.1rem;
    background: var(--panel);
    border-bottom: 1px solid var(--edge);
}

.bar-right { display: flex; align-items: center; gap: .7rem; }

/* The table's own header is shorter than the hall's. Nothing in it is read --
   it is a name and four buttons -- and the realm underneath is sized from the
   height left over, so every pixel taken off this is four onto every square
   of the board. */
#table > .bar { padding: .3rem 1.1rem; }
#table > .bar h1 { font-size: 1.1rem; }
.bar-left { display: flex; align-items: center; gap: .2rem; min-width: 0; }
/* On the table the bug line is a reminder rather than a notice: small, and
   cut short before it can push the buttons off the bar. */
#table .bug-report {
    font-size: .64rem;
    margin-left: .6rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
}
#table .beta { margin-left: .6rem; }
#who { color: var(--gold); font-family: var(--display); }

.panel {
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: 1rem;
}

.list { list-style: none; margin: 0; padding: 0; }

.list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .6rem;
    padding: .45rem .1rem;
    border-bottom: 1px solid var(--edge);
    font-size: .9rem;
}

.list li:last-child { border-bottom: none; }
.list.dense li { padding: .2rem .1rem; font-size: .85rem; }
.list .sub { color: var(--ink-faint); font-size: .78rem; }
.list button { padding: .18rem .5rem; font-size: .78rem; }
.list .empty { color: var(--ink-faint); font-style: italic; justify-content: center; }

/* ---------- lobby ---------- */

.lobby-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
    padding: 1rem;
    align-items: start;
}

/* ---------- deck builder ---------- */

.builder-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 1rem;
    padding: 1rem;
    height: calc(100vh - 56px);
}

.pool { display: flex; flex-direction: column; min-height: 0; }

/* A column of the builder: its panel, and under it the chart that goes with
   it when that is switched on. With the chart off the panel fills the column,
   as it did before there were charts. */
.builder-column {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
    min-height: 0;
}
.builder-column > .pool,
.builder-column > .deck { flex: 1 1 auto; }
.builder-chart { flex: none; }
.builder-chart[hidden] { display: none; }
.builder-chart h3 { margin: 0 0 .6rem; }
.builder-chart h3 .muted { margin-left: .4rem; text-transform: none; letter-spacing: 0; }

/* The two switches for the charts, beside the title rather than among the
   buttons that act on the deck. */
.builder-views { display: inline-flex; gap: .9rem; margin-left: 1.1rem; }
#builder > .bar { flex-wrap: wrap; }

/* The mana curve: a bar for each cost, 0 to 7 and then everything dearer. */
.curve {
    display: grid;
    grid-template-columns: repeat(8, minmax(0, 1fr));
    gap: .5rem;
    height: 110px;
}
.curve-column {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    min-height: 0;
}
.curve-track {
    flex: 1 1 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: stretch;
}
.curve-count {
    text-align: center;
    font-size: .74rem;
    color: var(--ink);
    font-variant-numeric: tabular-nums;
    line-height: 1.4;
}
.curve-bar {
    background: var(--gold-dim);
    border-top: 2px solid var(--gold);
    border-radius: 2px 2px 0 0;
}
.curve-cost {
    margin-top: .25rem;
    padding-top: .2rem;
    border-top: 1px solid var(--edge);
    text-align: center;
    font-size: .74rem;
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
}

/* The threshold matrix: for each element, how many of the deck's spells need
   one, two, three or four of it, and how many sites give it. */
.matrix {
    width: 100%;
    border-collapse: collapse;
    font-size: .8rem;
    font-variant-numeric: lining-nums tabular-nums;
}
.matrix th,
.matrix td {
    padding: .22rem .3rem;
    text-align: center;
    border-bottom: 1px solid var(--edge);
}
.matrix thead th {
    color: var(--ink-faint);
    font-weight: 500;
    font-size: .72rem;
}
.matrix tbody th { text-align: left; font-weight: 700; }
.matrix tr:last-child > * { border-bottom: none; }
.matrix .sites { border-left: 1px solid var(--edge); }
.matrix .none { color: var(--ink-faint); }
.matrix .EARTH { color: var(--earth); }
.matrix .AIR { color: var(--air); }
.matrix .FIRE { color: var(--fire); }
.matrix .WATER { color: var(--water); }

.pool-controls {
    display: flex;
    gap: .5rem;
    align-items: center;
    margin-bottom: .8rem;
}

.pool-controls input { flex: 2; }
.pool-controls select { flex: 1; }

.pool-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
    gap: .5rem;
    overflow-y: auto;
    min-height: 0;
    padding-right: .3rem;
}

.pool-card {
    position: relative;
    aspect-ratio: var(--card-ratio);
    border-radius: var(--radius);
    border: 1px solid var(--edge);
    background-color: var(--ground-deep);
    background-size: cover;
    background-position: center;
    cursor: pointer;
}

.pool-card:hover { border-color: var(--gold); }

/* Said across the whole grid when there is nothing to show, as a pool with
   nothing in it yet. */
.pool-empty {
    grid-column: 1 / -1;
    margin: 2rem 0;
    text-align: center;
    color: var(--ink-faint);
    font-style: italic;
}

/* A booster pack: its own picture, whole, and its name beneath. */
.pool-card.pack {
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center 30%;
    border-style: dashed;
    cursor: context-menu;
}
.pool-card.pack.spent { opacity: .45; }
.pool-card .pack-name {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 3px;
    text-align: center;
    font-size: .66rem;
    color: var(--ink-dim);
}
/* How many of a card the chosen pool holds, opposite the in-deck count. */
.pool-card[data-owned]::before {
    content: attr(data-owned);
    position: absolute;
    left: 3px;
    bottom: 3px;
    z-index: 1;
    background: var(--panel-high);
    color: var(--ink);
    border: 1px solid var(--edge-bright);
    font-size: .68rem;
    border-radius: 999px;
    min-width: 17px;
    text-align: center;
    padding: 0 4px;
}

.context-menu {
    position: fixed;
    z-index: 60;
    display: flex;
    flex-direction: column;
    min-width: 8rem;
    padding: 3px;
    background: var(--panel-high);
    border: 1px solid var(--edge-bright);
    border-radius: var(--radius);
    box-shadow: 0 6px 18px rgba(0, 0, 0, .5);
}
.context-menu button {
    text-align: left;
    background: none;
    border: 0;
    color: var(--ink);
    padding: .35rem .6rem;
    border-radius: 3px;
    cursor: pointer;
}
.context-menu button:hover:not(:disabled),
.context-menu button:focus-visible { background: var(--edge); }
.context-menu button:disabled { color: var(--ink-faint); cursor: default; }

/* A pack's contents, shown once over everything but the card under the pointer. */
.pack-reveal {
    position: fixed;
    inset: 0;
    z-index: 45;
    display: grid;
    place-items: center;
    background: rgba(0, 0, 0, .72);
}
.pack-reveal-box {
    /* Narrow enough that three rows of five fit a laptop's height unscrolled. */
    width: min(92vw, 680px);
    max-height: 92vh;
    overflow: auto;
    padding: 1rem 1.2rem;
    background: var(--panel);
    border: 1px solid var(--edge-bright);
    border-radius: 6px;
}
.pack-reveal-box h2 { margin: 0 0 .6rem; }
.pack-reveal-grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: .5rem;
}
.pack-reveal-grid .pool-card { cursor: default; }
/* The set-aside picker's cards are chosen by clicking one. */
.pack-reveal-grid .pool-card.choosable { cursor: pointer; }
.pack-reveal-grid .pool-card.choosable:hover, .pack-reveal-grid .pool-card.choosable:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.pack-reveal-grid .pool-card.rarity-unique { border-color: var(--gold); }
/* The foil: a cold sheen round the card and a word to say so. */
.pack-reveal-grid .pool-card.foil {
    border-color: #cfe6ff;
    box-shadow: 0 0 0 1px #cfe6ff, 0 0 14px rgba(170, 210, 255, .65);
}
.pack-reveal-grid .foil-tag {
    position: absolute;
    top: 3px;
    left: 3px;
    padding: 0 5px;
    border-radius: 3px;
    background: linear-gradient(90deg, #e8f4ff, #c9b6ff, #b8f0e6);
    color: #1d2230;
    font-size: .66rem;
    font-weight: 600;
}
.pack-reveal-foot {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: .8rem;
}

/* Legal only at a table that plays with unreleased cards, so marked where
   decks are made: the pool's tile, the deck's row and the Avatar's slot. */
.pool-card.unreleased,
.list li.unreleased,
#deck-avatar.unreleased {
    outline: 2px solid var(--unreleased);
    outline-offset: -2px;
}
.list li.unreleased { border-radius: 3px; }
/* A format's own piece, The Orb or The Outlands: there to be read, and put
   in no deck, so it neither looks nor acts like a card to click in. */
.pool-card.view-only { border-style: dashed; cursor: default; }
.pool-card.view-only:hover { border-color: var(--edge-bright); }
.pool-card .token-tag {
    position: absolute;
    top: 3px;
    left: 3px;
    padding: 0 5px;
    border-radius: 3px;
    background: var(--panel-high);
    border: 1px solid var(--edge-bright);
    color: var(--ink-dim);
    font-size: .66rem;
}
#deck-avatar.unreleased { outline-offset: 1px; border-radius: 2px; }
.pool-card[data-in]::after {
    content: attr(data-in);
    position: absolute;
    top: 3px;
    right: 3px;
    background: var(--gold);
    color: #1a1405;
    font-size: .7rem;
    font-weight: 700;
    border-radius: 999px;
    min-width: 17px;
    text-align: center;
    padding: 0 4px;
}

.pool-card .fallback,
.hand .card .fallback {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    padding: .3rem;
    text-align: center;
    font-size: .7rem;
    color: var(--ink-dim);
}

.deck { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; }
.deck h3 { margin-top: .9rem; }
.deck .kinds { margin: -.15rem 0 .35rem; font-size: .8rem; }
.deck-name { margin-bottom: .5rem; }
.deck-folder { margin-bottom: .6rem; }
.deck-folder select { width: 100%; }
.folder-dialog { color: var(--ink); min-width: 20rem; box-shadow: var(--shadow); }
.folder-dialog::backdrop { background: rgba(7, 11, 12, .7); }
.folder-dialog form { display: flex; flex-direction: column; gap: .7rem; }
.folder-dialog h3 { margin: 0; }
.folder-dialog label { display: flex; flex-direction: column; gap: .25rem; }
.folder-dialog label[hidden] { display: none; }
.folder-dialog-buttons { display: flex; justify-content: flex-end; gap: .5rem; }
.deck-avatar { font-size: .78rem; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-faint); }
.deck-avatar strong { display: block; color: var(--ink); text-transform: none; letter-spacing: 0; font-weight: 500; }

/* ---------- the table ---------- */

/* The table fills the window and does not scroll: a player should never have
   to hunt for their own rail or the question they are being asked. The realm
   is sized from the height left over, and everything else is fixed. */
body[data-screen="table"] { overflow: hidden; }

#table { height: 100vh; flex-direction: column; }

.table-grid {
    flex: 1;
    min-height: 0;
    display: grid;
    /* Each player's own information stands beside the board rather than
       above and below it. The board used to get whatever height was left
       after two horizontal rails and the hand -- which is to say it was
       height-constrained, and a wider window did nothing for it. Flanking
       rails cost width, which there is more of, and hand the realm the
       whole height of the row. */
    /* The board is square-celled and the window is wider than it is tall, so
       the realm is bound by its height and takes only the width its squares
       come out at. The flanks are set to what is left over rather than to
       what they need: anything narrower would be dead space between the
       columns, since the board cannot grow sideways to use it. */
    /* What each flank needs for its own contents, and -- since these are the
       widths the exact fit came out at -- the proportion any spare width is
       divided in. fitTheColumns() reads both and writes the two above. */
    --flank-left-least: 246px;
    --flank-right-least: 300px;
    grid-template-columns:
        var(--flank-left, var(--flank-left-least))
        minmax(0, 1fr)
        var(--flank-right, var(--flank-right-least));
    gap: .9rem;
    padding: 1rem;
    align-items: stretch;
}

/* A player's own column: their rail, and whatever belongs to their side of
   the table under it. */
.flank {
    display: flex;
    flex-direction: column;
    gap: .7rem;
    min-height: 0;
    min-width: 0;
}


.rail {
    display: flex;
    flex-direction: column;
    gap: .6rem;
    padding: .7rem .6rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    font-size: .82rem;
    flex: 0 0 auto;
}

.rail .name { font-family: var(--display); color: var(--gold); font-size: 1.05rem; line-height: 1.2; }
.rail.turn { border-color: var(--gold-dim); box-shadow: inset 0 0 0 1px rgba(201, 162, 39, .18); }

/* Life and mana are the two numbers a player checks constantly, so they are
   set large and side by side, with the thresholds beside them. */
.vitals { display: flex; gap: .6rem; align-items: flex-end; }
.vital { font-size: .76rem; color: var(--ink-dim); line-height: 1.25; }
.vital b {
    display: block;
    color: var(--ink);
    font-weight: 700;
    font-size: 1.5rem;
    font-variant-numeric: tabular-nums;
}

/* The rest are counts, two to a line, quiet under a rule. */
.tallies {
    border-top: 1px solid var(--edge);
    padding-top: .55rem;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: .4rem .7rem;
}
.rail .stat {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .3rem;
    color: var(--ink-dim);
    font-variant-numeric: tabular-nums;
    font-size: .78rem;
}
.rail .stat b { color: var(--ink); font-weight: 700; font-size: .92rem; }
/* A set-aside card -- a Dragonlord's Dragon -- takes a line of its own, and shows the card when pointed at. */
.tallies .stat.set-aside { grid-column: 1 / -1; cursor: help; }
.seat-tallies .stat.set-aside { cursor: help; }
/* The hand is one line of its own, because its split needs the room. */
.rail .stat.hand {
    /* A fan, overlapping downward, because the hand stands in a column
       beside the board rather than in a strip beneath it. Each card shows
       its own top — which is where a Sorcery card puts its name, its cost
       and its thresholds — and the whole of whichever one is under the
       pointer. */
    display: flex;
    flex-direction: column;
    align-items: center;
    overflow-y: auto;
    overflow-x: hidden;
    min-height: 0;
    flex: 1;
    padding: 2px 0 .3rem;
}
.rail .stat .stat-note { color: var(--ink-faint); font-size: .72rem; }

.thresholds { display: flex; gap: 4px; margin-left: auto; padding-bottom: 3px; }

/* The element's own symbol with its count on top, rather than a coloured
   disc with a number in it: the symbols are what the cards use, so a player
   reads the same mark on the board as on the card in their hand. */
.pip {
    position: relative;
    display: grid;
    place-items: center;
    width: 25px;
    height: 25px;
    font-size: .74rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--ink);
    /* The symbols are dark in the middle, so a light numeral carries on all
       four; the shadow is what keeps it legible over the lightest of them. */
    text-shadow: 0 1px 2px rgba(0, 0, 0, .95), 0 0 3px rgba(0, 0, 0, .8);
    background-size: 25px 25px;
    background-position: center;
    background-repeat: no-repeat;
}
.pip.AIR { background-image: url("element-air.png"); }
.pip.EARTH { background-image: url("element-earth.png"); }
.pip.FIRE { background-image: url("element-fire.png"); }
.pip.WATER { background-image: url("element-water.png"); }

.pip.spent { opacity: .42; font-weight: 400; }

/* The middle column: the board, and the hand lying along the bottom of it.
   The hand is a fixed bar and the board takes the rest, which is what makes
   the board's height -- and so its whole size -- the bar's to give away. */
.middle {
    display: flex;
    flex-direction: column;
    gap: .75rem;
    min-height: 0;
    min-width: 0;
}

/* The realm: five across, four down, drawn as the viewer's own side up.
   Twenty card-shaped squares, so the whole board is 5:4 of a card - it takes
   whichever of the width and the height runs out first and centres itself. */
.realm-holder {
    /* Whatever height the hand bar under it has not taken. Without this the
       box is sized by its contents, and its contents are sized by the box --
       a container query against nothing is nothing, and the board vanished. */
    flex: 1;
    min-height: 0;
    min-width: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    /* Measured, so the board below can size itself against both of this
       box's dimensions rather than only one. */
    container-type: size;
}

.realm {
    display: grid;
    /* minmax(0, 1fr) rather than 1fr: a 1fr track will not shrink below its
       content, and each square asks for aspect-ratio 1, so a wide board gave
       every row a tall minimum and the whole grid grew past the height it was
       given -- pushing the hand off the bottom of the screen. The board's own
       5:4 ratio is what keeps the cells square; the tracks must be free to
       shrink to it. */
    /* Five by four unless the board being drawn says otherwise: the page
       sets --cols and --rows from the board the game is played on. */
    grid-template-columns: repeat(var(--cols, 5), minmax(0, 1fr));
    grid-template-rows: repeat(var(--rows, 4), minmax(0, 1fr));
    gap: 4px;
    /* Square cells, five by four, so the board takes whichever of the height
       and the width runs out first: the holder gives it the height, the ratio
       gives it the width back. */
    /* Fit the board inside whichever of the two runs out first. Driving it
       from the height alone was right when the rails sat above and below and
       height was always the scarce one; with the rails beside the board it is
       usually the width, and a height-driven box then kept its full height
       while the width clamped -- leaving the squares correct but the board's
       box, and the picture under it, taller than the squares it held. */
    /* And never a cell larger than five by four's: a board three wide
       (Adventure mode's skirmish) would otherwise fill the height with three
       giant squares. */
    width: min(100cqw, calc(100cqh * var(--cols, 5) / var(--rows, 4)), calc(100cqh / 4 * var(--cols, 5)));
    height: auto;
    aspect-ratio: var(--cols, 5) / var(--rows, 4);
    /* A picture of somewhere, laid under the board and dimmed almost to
       nothing: the squares and what stands on them have to stay the brightest
       things on the screen, so the art is atmosphere rather than scenery. The
       flat colour is painted over it rather than behind it, which keeps the
       board legible whatever the picture happens to be -- and keeps it
       looking right when there is no picture at all. */
    background-color: var(--ground-deep);
    background-image:
        linear-gradient(rgba(9, 14, 16, .84), rgba(9, 14, 16, .84)),
        var(--ground-art, none);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: 4px;
}

.square {
    position: relative;
    min-height: 0;
    aspect-ratio: 1;
    border-radius: 2px;
    border: 1px solid var(--edge);
    /* Translucent, so the picture under the board shows through the empty
       squares. Opaque cells hid all of it but the four pixels of gap. */
    background-color: rgba(10, 16, 18, .58);
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    overflow: hidden;
}

/*
 * A site lies sideways in its square, the way it is laid on a table.
 *
 * The card is portrait, so it is turned a quarter turn and sized from the
 * square's height: at 380/531 of the square's width it comes out exactly as
 * wide as the square once turned, and the whole card stays visible with a
 * band above and below for the site's name and whatever is standing on it.
 * Centred by `inset: 0; margin: auto` rather than a translate, because a
 * translate after a rotate moves along the rotated axes.
 */
.site-art {
    position: absolute;
    inset: 0;
    margin: auto;
    height: 100%;
    width: 71.56%;
    transform: rotate(90deg);
    background-size: cover;
    background-position: center;
    border-radius: 2px;
}

/*
 * The other player's ground, laid facing them.
 *
 * A site is sideways on the board, so facing the other way is the same turn
 * plus half a revolution. Only the board is turned: the picture that pops up
 * on hover is built separately and stays the right way up, because the point
 * of it is to be read.
 */
.site-art.theirs {
    transform: rotate(270deg);
}

/* And the ground of a player at either hand, on a board with players round
   it: a quarter turn on from each neighbour, so every site faces whoever
   holds it. */
.site-art.to-the-left {
    transform: rotate(180deg);
}

.site-art.to-the-right {
    transform: rotate(0deg);
}

/* A site whose own picture stands upright -- The Tower of Babel -- is not
   turned at all: it fills the square, the tower's middle showing, whoever
   holds it. The pop-up shows the whole card. */
.site-art.upright,
.site-art.upright.theirs,
.site-art.upright.to-the-left,
.site-art.upright.to-the-right {
    width: 100%;
    transform: none;
    background-position: center 40%;
}

/* Nobody's: The Nexus, The Fortress or The Outlands with no controller,
   turned a further 18 degrees on top of however it lies, as a tapped unit is. */
.site-art.unheld { rotate: 18deg; }

.square.void {
    /* The hatching that says "nothing here", drawn in translucent ink so the
       picture under the board still reads through it. */
    background-image:
        repeating-linear-gradient(45deg,
            rgba(12, 18, 20, .75) 0 6px, rgba(10, 15, 17, .55) 6px 12px);
    border-style: dashed;
    border-color: #222e30;
}

.square.flooded::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(79, 134, 189, 0) 30%, rgba(79, 134, 189, .38));
    pointer-events: none;
}

.square .number {
    position: absolute;
    top: 2px;
    left: 4px;
    font-size: .62rem;
    color: rgba(233, 227, 213, .45);
    font-variant-numeric: tabular-nums;
    text-shadow: 0 1px 2px #000;
}

/* A marked square, in the colours the board already uses for whose is whose:
   green for yours, red for theirs, as on a unit's own edge. Sat beside the
   number rather than over the art, so a marked square still reads as ground. */
.square .number .mark {
    display: inline-block;
    width: 5px;
    height: 5px;
    margin-left: 3px;
    border-radius: 50%;
    vertical-align: middle;
    box-shadow: 0 0 2px rgba(0, 0, 0, .9);
}

.square .number .mark.mine { background: var(--good); }
.square .number .mark.theirs { background: var(--danger); }
/* A tiny flame: a site a Flame of the First Ones has stopped at. A teardrop
   turned point-up, white-hot at the base and red at the tip. */
.square .number .mark.flame {
    width: 5px;
    height: 5px;
    margin-left: 4px;
    border-radius: 50% 0 50% 50%;
    transform: rotate(-45deg) translate(1px, -1px);
    background: radial-gradient(circle at 30% 70%, #fff4c2 0 22%, #ffb53a 48%, #e2531f 82%, #9c2a12);
    box-shadow: 0 0 3px rgba(255, 150, 50, .85);
}

/* Ashes: ground a Wildfire has burnt over, ember-orange fading to grey. */
.square .number .mark.burnt {
    width: 7px; height: 7px; border-radius: 2px;
    background: linear-gradient(135deg, #e0782a, #6b6b6b);
    box-shadow: 0 0 3px rgba(224, 120, 42, .8);
}

/* An element the ground provides that its picture does not show: a Valley
   of Delight's choice, made on arrival and kept. */
.square .provides {
    position: absolute;
    top: 2px;
    left: 2px;
    z-index: 2;
    display: flex;
    gap: 1px;
}
/* A Trap laid under its Draft Site: everybody sees one is there, its owner which. */
.square .trap-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    z-index: 2;
    max-width: calc(100% - 4px);
    padding: 1px 4px;
    border-radius: 3px;
    background: rgba(20, 12, 8, .82);
    border: 1px solid var(--gold-dim);
    color: var(--gold);
    font-size: .62rem;
    line-height: 1.2;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.square .provides .pip {
    width: 16px;
    height: 16px;
    background-size: 16px 16px;
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .9));
}

.square .site-name {
    position: relative;
    font-size: .62rem;
    line-height: 1.15;
    padding: 1px 3px 2px;
    background: rgba(7, 11, 12, .82);
    text-align: center;
}

.layers {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 2px;
}

/* A region's units in one row, drawn closer together once there are more
   than fit: each pulled in by exactly as much as the square is short, and
   tucked under the one before it, so every chip keeps its right edge -- where
   its power and its damage are -- in sight. Wrapping stacked rows up past the
   top of a crowded square, which cut them off. Pointed at, a chip comes to
   the front. */
.layer { display: flex; flex-wrap: nowrap; gap: 2px; }
.layer > .unit, .layer > .unit-stack { z-index: var(--stack, auto); }
.layer > :is(.unit, .unit-stack) + :is(.unit, .unit-stack) {
    margin-left: min(0px, calc((100% - var(--count, 1) * var(--chip-wide, 38px))
            / (var(--count, 2) - 1) - 2px));
}
.layer > .unit:hover,
.layer > .unit.pointed,
.layer > .unit-stack:hover { z-index: 100; }

/* A bearer with what it carries: the artifacts just behind it, each a little
   higher and to the right, so a strip of every one shows above the bearer
   and can still be pointed at and clicked. */
.unit-stack {
    position: relative;
    flex: none;
    width: var(--chip-wide, 38px);
    height: var(--chip-tall, 54px);
}
.unit-stack > .unit { position: absolute; left: 0; top: 0; }
.unit-stack > .unit.carried {
    transform: translate(calc(var(--under, 1) * 5px), calc(var(--under, 1) * -9px)) scale(.9);
    transform-origin: bottom left;
    filter: brightness(.85);
}
.unit-stack > .unit.carried:hover { filter: none; z-index: 5; }

/* One unit standing somewhere: the card's own art, cropped to its picture. */
.unit {
    position: relative;
    /* A unit is a card standing on the ground, so it is shaped like one:
       taller than it is wide, in the printed proportion. Square chips read
       as counters and made a site full of units look like a spreadsheet.

       Twice the area it was, which is each edge times the root of two: at
       27 by 38 a minion was a thumbnail of a thumbnail and its picture told
       you nothing. Four to a site still fit side by side.

       Set from a pair of properties rather than written twice, so the key in
       Game Aids can draw the board's own chip at the size a key needs
       without restating anything else about it. */
    width: var(--chip-wide, 38px);
    height: var(--chip-tall, 54px);
    border-radius: 2px;
    border: 1px solid var(--edge-bright);
    background-color: var(--panel-high);
    background-size: 190%;
    background-position: center 22%;
    cursor: pointer;
    flex: 0 0 auto;
}

.unit.mine { border-color: var(--gold); }
.unit.theirs { border-color: var(--danger); }
.unit.tapped { transform: rotate(18deg); }
/* A Ward is the one mark that stops the next thing outright, so it is drawn
   as a hard white edge rather than a tint — there either is one or there is
   not, and it goes the moment it is spent. */
.unit.ward {
    border-color: #fff;
    box-shadow: 0 0 0 1px #fff;
}

.site-art.ward {
    border: 2px solid #fff;
}

.unit.stealth { opacity: .6; }

/*
 * Stopped rather than gone.
 *
 * A silenced Sparkmage is a Sparkmage: nothing about the picture changes when
 * its text stops working, and nothing about it changes when it is disabled
 * and cannot act. The hover panel has named both in words for a while, which
 * is no use to somebody scanning the whole board for what is still dangerous.
 *
 * These come after whose-it-is deliberately, and so overrule it: the edge
 * answers "can this do anything" before it answers "whose is it", because
 * that is the order the two questions get asked in. A card that is both is
 * drawn disabled, the harder of the two to work around.
 */
.unit.silenced { border-color: var(--silenced); }
.unit.disabled { border-color: var(--disabled); }

.site-art.silenced { border: 2px solid var(--silenced); }
.site-art.disabled { border: 2px solid var(--disabled); }

.unit .power {
    position: absolute;
    bottom: -1px;
    right: -1px;
    font-size: .58rem;
    font-weight: 700;
    line-height: 1;
    padding: 1px 2px;
    background: rgba(7, 11, 12, .9);
    border-radius: 2px;
    font-variant-numeric: tabular-nums;
}

/* Damage is its own mark rather than a second number: a player counts the
   power first and only then asks how much of it has been chipped away. */
.unit .hurt {
    position: absolute;
    top: -3px;
    right: -3px;
    min-width: 12px;
    padding: 0 2px;
    font-size: .56rem;
    font-weight: 700;
    line-height: 12px;
    text-align: center;
    color: #fff;
    background: var(--danger);
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
}

/* A count the card keeps and its text refers to -- a fuse, a level -- worn
   at the other corner from the damage, so the two numbers are never taken
   for each other. */
.unit .counters {
    position: absolute;
    bottom: -3px;
    left: -3px;
    min-width: 12px;
    padding: 0 2px;
    font-size: .56rem;
    font-weight: 700;
    line-height: 12px;
    text-align: center;
    color: #111;
    background: var(--gold);
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
}

/* A card that covers more than one square is drawn once, over the border
   the squares share -- or, for a two-by-two, over the corner all four meet
   at -- the way it is laid on a table. */
.unit.oversized {
    place-self: center;
    z-index: 3;
    box-shadow: 0 2px 8px rgba(0, 0, 0, .7);
}

/* A card stretched over more places than a border or a corner can hold
   (a Megamoeba over three, or five; an Avatar stretched likewise): the card
   where it stands, and in each other place it covers a card half its size,
   which taps and glows with it. */
.unit.part {
    width: calc(var(--chip-wide, 38px) / 2);
    height: calc(var(--chip-tall, 54px) / 2);
    align-self: flex-end;
}

.unit.part .power,
.unit.part .hurt,
.unit.part .counters {
    display: none;
}

.unit .subsurface {
    position: absolute;
    top: -1px;
    left: -1px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
}

/*
 * A unit too newly arrived to act.
 *
 * The one thing about a minion that is invisible and decides what a whole
 * turn can be: there is nothing on the card, nothing in its position and
 * nothing in its colour to say it. A player counts squares, works out an
 * attack, and finds the unit is not being offered it.
 *
 * Ruled out, in the plainest sense of the phrase -- a line struck across the
 * face from corner to corner. The corners are the four things the board
 * already keeps there, and this passes between them: it crosses the card
 * itself, which is the part nothing else has a claim on.
 *
 * The line is drawn by a gradient rather than by a rotated box, so that it
 * stays on the two corners at whatever size the chip is. "to bottom right"
 * sets the gradient's axis through the other diagonal, and the band at its
 * halfway mark is the one that runs through the top-right and bottom-left
 * corners -- the CSS corner-to-corner rule puts both of them exactly there.
 * A dark line a pixel wider sits under it, because a red hairline over red
 * card art is a red hairline nobody can see.
 */
.unit .resting {
    position: absolute;
    inset: -1px;
    pointer-events: none;
    background:
        linear-gradient(to bottom right, transparent calc(50% - 1px),
            var(--danger) calc(50% - 1px), var(--danger) calc(50% + 1px),
            transparent calc(50% + 1px)),
        linear-gradient(to bottom right, transparent calc(50% - 2px),
            rgba(0, 0, 0, .75) calc(50% - 2px), rgba(0, 0, 0, .75) calc(50% + 2px),
            transparent calc(50% + 2px));
}

/* Where the top-right corner is already taken, the line stops short of it
   rather than running into it: a red hairline arriving at a red badge reads
   as part of the badge, and the count is the thing that must stay legible.
   Cut out of the line rather than drawn shorter, so what is left of it lies
   on exactly the same diagonal -- the chip is taller than it is wide, and a
   line drawn between two inset corners would sit at its own angle. */
.unit:has(.hurt) .resting {
    -webkit-mask-image: radial-gradient(circle 15px at 100% 0, transparent 0 15px, #000 15px);
    mask-image: radial-gradient(circle 15px at 100% 0, transparent 0 15px, #000 15px);
}

.unit .subsurface.UNDERGROUND { background: var(--earth); }
.unit .subsurface.UNDERWATER { background: var(--water); }
.unit .subsurface.VOID { background: var(--ink-faint); }

/*
 * A unit that is not standing on the ground has to look like it.
 *
 * Most rules keep the regions apart — a nearby ally cannot cross a regional
 * boundary — so mistaking a buried minion for one on the surface makes the
 * game look broken when it is behaving correctly. The old signal was 8% of
 * opacity and a 6px dot, which is no signal at all: the chip is now visibly
 * sunk, its edge is broken rather than solid, and the dot is big enough to
 * find with a ring dark enough to hold against card art.
 */
.unit[data-region="UNDERGROUND"],
.unit[data-region="UNDERWATER"],
.unit[data-region="VOID"] {
    border-style: dashed;
    filter: brightness(.62) saturate(.75);
    box-shadow: inset 0 2px 5px rgba(0, 0, 0, .75);
}

.unit .subsurface {
    width: 9px;
    height: 9px;
    border: 1px solid rgba(0, 0, 0, .8);
    box-shadow: 0 0 2px rgba(0, 0, 0, .9);
}

/* What is true of this one card -- where it is, whose it is -- under its
   name in the picture that pops up. */
.hover-fact {
    font-size: .78rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

/* The card's own note, the one fact its picture cannot show: a quest's end,
   a Trap's name. Lit, so it is found without reading the rest. */
.hover-fact.noted {
    color: var(--gold);
    font-weight: 600;
}

/* One line per effect reaching this card, under "Being changed by". Sentence
   case and indented, because these are whole sentences rather than labels and
   the uppercase treatment above makes them unreadable at this length. */
.hover-change {
    font-size: .78rem;
    color: var(--ink-faint);
    padding-left: .5rem;
    text-indent: -.5rem;
}

/* A pile laid out to be looked through: the cemetery and the banished, which
   are face up and get read constantly. Over the table rather than beside it,
   since it is opened to answer one question and then shut. */
.pile {
    position: fixed;
    inset: 6vh 8vw;
    z-index: 40;
    display: flex;
    flex-direction: column;
    gap: .6rem;
    padding: 1rem;
    background: var(--panel);
    border: 1px solid var(--gold-dim);
    border-radius: var(--radius);
    box-shadow: 0 18px 60px rgba(0, 0, 0, .7);
}

.pile[hidden] { display: none; }

/* A notice put up with a button on it -- a player's time running out --
   near the top of the board rather than over it, so the board can be looked
   at while it is read. */
.announce {
    position: fixed;
    top: 3.2rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 35;
    display: flex;
    align-items: center;
    gap: .8rem;
    padding: .5rem .9rem;
    background: var(--panel-high);
    border: 1px solid var(--gold-dim);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    max-width: min(90vw, 40rem);
}
.announce[hidden] { display: none; }
.announce-who { color: var(--gold); font-family: var(--display); white-space: nowrap; }
.overtime { top: 6.5rem; border-color: var(--danger); }
.overtime .announce-who { color: var(--danger); }
/* Each player's match clock, beside their life and mana. */
.vital.clock b { font-variant-numeric: tabular-nums; }
.vital.clock.low b { color: var(--danger); }
.announce-what { min-width: 0; }
.chat-mute { margin-top: .4rem; }
.log-detail { margin: .2rem 0 .4rem; font-size: .85rem; }
/* Under the mute, and small: a thing done once a game, not every turn. */
.observer-link {
    align-self: flex-start;
    margin-top: .4rem;
    font-size: .76rem;
    padding: .25rem .6rem;
}
/* Somebody watching by link has no account: nothing to make links with,
   and nothing to say in the chat. */
body.guest .observer-link,
body.guest #table-chat-form { display: none; }
.chat-said a { color: var(--gold); word-break: break-all; }

.pile-bar {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    flex: 0 0 auto;
}

.pile-bar h3 {
    font-family: var(--display);
    color: var(--gold);
    font-size: 1.05rem;
}

.pile-cards {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: .5rem;
    overflow-y: auto;
    min-height: 0;
    flex: 1;
}

/*
 * A card laid out to be looked at, wherever it is laid.
 *
 * Shared with the hand rather than restated, because restating it is how the
 * two drifted apart: a pile's cards had a height and "width: auto" and nothing
 * to give them a width -- no aspect ratio, no art, no border -- so a cemetery
 * opened onto ten cards a hundred and thirty pixels tall and none wide, and
 * looked empty. Nothing loaded their art either: it is fetched when a tile is
 * scrolled into view, and a tile with no width is never in view.
 */
.hand .card,
.pile-cards .card {
    flex: 0 0 auto;
    width: auto;
    aspect-ratio: var(--card-ratio);
    border-radius: var(--radius);
    border: 1px solid var(--edge);
    background-color: var(--panel-high);
    background-size: cover;
    background-position: center;
}

.pile-cards .card { height: 132px; }

/*
 * A card in your hand you could put down right now.
 *
 * The board already works out which cards have an option to their name --
 * it is the same mark that decides what is clickable -- and in the hand that
 * answers exactly one question, which is the question a player asks of their
 * hand every single turn: what can I play? Green rather than gold, because
 * gold already means "the thing being talked about" everywhere else here.
 */
.hand .card.answerable {
    border-color: var(--good);
    box-shadow: 0 0 0 1px var(--good), 0 0 8px rgba(111, 159, 106, .45);
}

/* A count you can open, and one that is empty and so opens nothing. */
.stat-note { opacity: .6; font-size: .85em; }
.stat.lookable { cursor: pointer; }
.stat.lookable:hover b { color: var(--gold); }
.stat.lookable.empty { cursor: default; }
.stat.lookable.empty:hover b { color: var(--ink); }

/*
 * The hand lies along the bottom of the board, fanned sideways.
 *
 * It used to stand in a column in the right-hand flank, which cost the flank
 * the width of a card and cost the board nothing -- and then the flank had to
 * be wide enough for a card whatever else was in it. Below the board it costs
 * height instead, which is the same height the board was going to lose to
 * something; and the flanks come back to the width their own contents need,
 * which is the width the board could not have used anyway.
 *
 * The bar is a fixed height and the board takes what is left, so the bar is
 * the one lever on how big the realm is: every pixel off it is four onto
 * every square. At 110 a card's head shows -- the part with its name, its
 * cost and its thresholds printed on it -- and the whole card is in the panel
 * under the pointer, which is where a card is actually read.
 */
.hand-strip {
    flex: 0 0 auto;
    height: 110px;
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: 0 .75rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
}

/* The table with its rails or its hand put away (the user, 13 October 2026):
   the board takes the room, as it is sized from whatever room there is. The
   question being asked is never put away -- it is how a game is played -- so
   with the rails gone it sits over the bottom right of the board. */
#table.rails-hidden > header.bar,
#table.rails-hidden .flank.theirs,
#table.rails-hidden .flank.yours > :not(#decision) { display: none; }
#table.rails-hidden .table-grid { grid-template-columns: minmax(0, 1fr); }
#table.rails-hidden .flank.yours {
    position: fixed;
    right: 1rem;
    bottom: calc(var(--under-the-board, 1rem));
    /* In the room the board leaves beside it, set by fitTheColumns. */
    width: var(--beside-the-board, min(300px, 40vw));
    max-height: 45vh;
    overflow-y: auto;
    z-index: 20;
}
#table.rails-hidden #decision:empty { display: none; }
#table.rails-hidden.hand-hidden .flank.yours { --under-the-board: 1rem; }
#table.rails-hidden:not(.hand-hidden) .flank.yours { --under-the-board: calc(110px + 2rem); }
#table.hand-hidden .hand-strip { display: none; }
.show-rails, .show-hand {
    position: fixed;
    z-index: 21;
    opacity: .78;
}
.show-rails:hover, .show-hand:hover, .show-rails:focus-visible, .show-hand:focus-visible { opacity: 1; }
.show-rails { top: .6rem; left: .6rem; }
.show-hand { bottom: .6rem; left: .6rem; }
.hand-strip .hand-hide { flex: 0 0 auto; align-self: center; font-size: .78rem; }

/* Turned on its side, because the bar has height to spare in a 24px column
   and no width to spare anywhere: a word lying down costs the fan nothing. */
#hand-label {
    flex: 0 0 auto;
    width: 24px;
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: center;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-family: var(--body);
    font-size: .7rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--ink-faint);
    white-space: nowrap;
}

/*
 * The fan itself: a window the cards are placed inside rather than a row they
 * are packed into, so that a hand of twenty ends where a hand of three ends
 * and neither scrolls. Where the placing happens is placeTheFan(), which
 * hands each card the two numbers below -- where it starts, and how much of
 * it the next one leaves showing.
 *
 * Shorter than the cards are tall on purpose. A card cut off at the foot
 * still shows everything printed at its head; a card scaled down to fit shows
 * all of a picture too small to tell from the next one.
 */
.hand {
    position: relative;
    flex: 1;
    min-width: 0;
    height: 94px;
    overflow: hidden;
    --card-wide: 84px;
    --card-tall: 118px;
    --laid-wide: 118px;
    --laid-tall: 84px;
}

.hand .card {
    position: absolute;
    top: 0;
    left: var(--at, 0px);
    width: var(--card-wide);
    height: var(--card-tall);
    aspect-ratio: auto;
    z-index: var(--fan, 1);
}

/* A site is held the way it is played, on its side: a landscape box with the
   upright picture turned inside it, which is the same trick the board uses
   for the ground itself, so the proportions stay the printed ones. Short
   enough to stand whole in the window, so it is dropped to sit in the middle
   of it rather than hanging off the top. */
.hand .card.laid {
    width: var(--laid-wide);
    height: var(--laid-tall);
    top: 10px;
    overflow: hidden;
}

.hand .laid-art {
    position: absolute;
    inset: 0;
    margin: auto;
    width: var(--laid-tall);
    height: var(--laid-wide);
    transform: rotate(90deg);
    background-size: cover;
    background-position: center;
    border-radius: 2px;
}

/*
 * Pointing at a card in the fan means pointing at the part of it you can see.
 *
 * A card in a fan is mostly behind another one, and the strip of it left
 * showing is the only part a player is looking at -- so that strip is the
 * only part that answers. The card itself takes no pointer at all and its
 * reach does, a band down its leading edge exactly as wide as the next card
 * leaves showing; the last card in the fan is covered by nothing and answers
 * all over. Which also means the card under the pointer is never lifted out
 * of the fan to be read, because lifting it would put it over the neighbours
 * whose own strips the pointer is on its way to.
 */
.hand .card { pointer-events: none; }
/* Over the card's edge as well as its face -- inset from the padding box by
   the border it is drawn inside, so one card's band meets the next one's
   exactly and there is no hairline between them that answers to nobody. */
.hand .reach {
    position: absolute;
    top: -1px;
    bottom: -1px;
    left: -1px;
    width: var(--shows, 100%);
    pointer-events: auto;
}
/* A site clips its own picture, and would clip the band with it, so that one
   keeps inside the card. */
.hand .card.laid .reach { top: 0; bottom: 0; left: 0; }

.hand .card:hover { border-color: var(--gold); }

/* Nothing in hand, said in the middle of the bar rather than in its corner. */
.hand > .muted {
    position: absolute;
    top: 50%;
    left: 0;
    transform: translateY(-50%);
}

/* A hand some card keeps for itself sits apart from yours, behind its name:
   a rule down the bar with the name lying against it, placed by the fan like
   anything else it has to find room for. */
.hand .held-by {
    position: absolute;
    top: 0;
    bottom: 0;
    left: var(--at, 0px);
    z-index: var(--fan, 1);
    width: 16px;
    padding-left: 4px;
    border-left: 1px solid var(--edge-bright);
    display: flex;
    align-items: center;
}
.hand .held-by span {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-size: .7rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ink-dim);
    white-space: nowrap;
}
/* The top of your own spellbook, in the hand while it may be cast from there.
   Not one of the hand's cards, so it stands behind a rule of its own and
   under a dashed edge -- gold while it is something that may be cast now. */
.hand .held-by.next-spell-rule span { color: var(--gold); }
.hand .card.next-spell { border-style: dashed; }
.hand .card.next-spell.answerable { border-color: var(--gold); }

/* ---------- the side: what you are being asked ---------- */

.side {
    display: flex;
    flex-direction: column;
    gap: .8rem;
    height: 100%;
    min-height: 0;
    overflow-y: auto;
}

.decision {
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: .9rem;
}

.decision.live { border-color: var(--gold); box-shadow: 0 0 18px rgba(201, 162, 39, .12); }

/* What was cast or played this turn and the turn before, fanned under the
   decision: in each turn the newest upright and on top, the ones before it
   tilting away beneath it. The first thing to give up height on a short
   window, since the decision above it is the thing that has to be answered. */
.played {
    flex: 0 1 auto;
    min-height: 0;
    overflow: hidden;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: .7rem .9rem .6rem;
}
.played[hidden] { display: none; }
.played h3 { margin: 0 0 .3rem; }
.played-turns { display: flex; flex-direction: column; gap: .45rem; }
.played-label { font-size: .76rem; color: var(--ink-dim); }
.played-none { font-size: .76rem; color: var(--ink-faint); font-style: italic; padding: .15rem 0 .2rem; }
.played-fan {
    position: relative;
    height: 116px;
}
.played-card {
    position: absolute;
    bottom: 4px;
    left: calc(12px + var(--at) * var(--step));
    width: 70px;
    height: 98px;
    z-index: calc(var(--at) + 1);
    background-size: cover;
    background-position: center;
    background-color: var(--panel-high);
    border: 1px solid var(--edge);
    border-radius: 4px;
    box-shadow: var(--shadow);
    transform: rotate(calc(var(--back) * -4deg));
    transform-origin: 50% 100%;
}
.played-card.mine { border-color: var(--gold); }
.played-card.theirs { border-color: var(--danger); }
.played-card:hover { border-color: var(--ink); }
/* A site lies on its side, as it does in the hand and on the board. */
.played-card.laid {
    width: 98px;
    height: 70px;
    overflow: hidden;
}
.played-card .laid-art {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 70px;
    height: 98px;
    transform: rotate(90deg);
    background-size: cover;
    background-position: center;
}
.decision .prompt { font-family: var(--display); font-size: 1rem; margin-bottom: .35rem; }

/* An action the rules make compulsory: said under the prompt, since there is
   no Pass to notice missing. */
.decision .must {
    margin-bottom: .35rem;
    font-size: .8rem;
    color: var(--gold);
}

/* How long is left before the server answers for you. Quiet while there is
   plenty, and only loud when there is not. */
.countdown {
    margin-bottom: .7rem;
    font-size: .76rem;
    letter-spacing: .06em;
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
}

.countdown.soon { color: var(--gold); }

.countdown.urgent {
    color: var(--danger);
    font-weight: 700;
}
.decision .waiting { color: var(--ink-faint); font-style: italic; }

/* What the bot opposite has just done, with the OK that lets it go on: first
   in the decision panel, where a player looks for what is asked of them, and
   ruled off from a question under it. */
.decision .announced {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .8rem;
}
.decision .announced + * {
    margin-top: .8rem;
    padding-top: .8rem;
    border-top: 1px solid var(--edge);
}
.announced-words { min-width: 0; }
.announced-who { color: var(--gold); font-family: var(--display); }
/* The OK, and to the right of it the way into Auto-Pass or out of it. */
.announced-buttons { display: flex; gap: .5rem; flex: 0 0 auto; }
.announced-buttons .auto-pass { white-space: nowrap; }
/* On Auto-Pass, between OKs: the last thing passed, already gone by. */
.decision .announced.passed .announced-words { color: var(--ink-faint); }
.decision .announced.passed .announced-who { color: var(--gold-dim); }

/* Not a wait at all: the game fell over and will not ask anything again. */
.decision .waiting.broken { color: var(--danger); font-style: normal; }
.decision .waiting.broken .sub {
    margin-top: .4rem;
    font-size: .74rem;
    color: var(--ink-faint);
    word-break: break-word;
}

.options { display: flex; flex-direction: column; gap: .35rem; max-height: 46vh; overflow-y: auto; }

.option-find { margin-bottom: .35rem; }
/* A unit clicked on the board: the panel narrowed to what it can do, and a way back. */
.unit-focus { display: flex; align-items: center; justify-content: space-between; gap: .5rem;
    margin-bottom: .35rem; font-size: .9rem; }
.option[hidden] { display: none; }

.option {
    display: flex;
    align-items: center;
    gap: .5rem;
    text-align: left;
    width: 100%;
}

.option .thumb {
    flex: 0 0 auto;
    width: 26px;
    height: 26px;
    border-radius: 2px;
    background-color: var(--ground-deep);
    background-size: 200%;
    background-position: center 26%;
}

.option .label { flex: 1; }

/* A step with more to settle after it says so, rather than looking like a
   button that commits. */
.option .more { color: var(--gold); font-size: 1rem; line-height: 1; }
.option.deeper { border-left: 2px solid var(--gold-dim); }

.option.pass { margin-top: .3rem; border-style: dashed; width: 100%; }

/* A deck search's pile: every card gone through, those not to be picked here
   shown as cards rather than buttons, and those the search cannot find plainly
   unavailable. */
.option.pile-card {
    font-size: .9rem;
    color: var(--ink);
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: .4rem .85rem;
    cursor: default;
}
.option.pile-card.unfound { color: var(--ink-faint); opacity: .55; filter: grayscale(1); border-style: dashed; cursor: not-allowed; }
.option.pile-card.unfound .thumb { opacity: .5; }
.decision .partner-asked-options li.unfound { opacity: .45; text-decoration: line-through; }

/* What has been picked so far on the way to one action. */
.trail {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem;
    margin-bottom: .6rem;
}

.trail .crumb {
    padding: .1rem .45rem;
    font-size: .76rem;
    background: transparent;
    border-color: var(--edge);
    color: var(--ink-dim);
}

.trail .crumb:hover { color: var(--ink); border-color: var(--gold-dim); }
/* The way back out of a half-made choice. Always live, including while an
   answer is in flight — a player part-way in must be able to start over. */
.trail .crumb.start-over {
    color: var(--gold);
    border-color: var(--gold-dim);
    border-style: solid;
}

.trail .crumb.start-over:hover { background: var(--panel-high); }

.refused {
    margin-bottom: .6rem;
    font-size: .78rem;
    color: var(--danger);
}

/* Whatever a step is about, while it is under the pointer: the square it
   names, and the one card it names — three Humble Villages read alike in an
   option and are three different cards on the board. */
.square.pointed {
    outline: 2px solid var(--gold);
    outline-offset: -2px;
    z-index: 1;
}

/*
 * The panel points at the board, and the board points back.
 *
 * A card with an option to its name is worth clicking, and says so; one under
 * the pointer lights the option it belongs to. The two highlights are
 * deliberately different: gold rings the thing being talked about, and this
 * softer wash marks the option being talked about -- so pointing at a card
 * and pointing at an option never look like the same thing happening.
 */
[data-card].answerable,
.square.answerable {
    cursor: default;
}

[data-card].actionable,
.square.actionable {
    cursor: pointer;
}

/* An empty square with something to answer -- somewhere to summon to, or to
   move to -- has no picture to ring, so the square itself says so. */
.square.answerable {
    border-color: var(--gold-dim);
}

.option.wanted {
    border-color: var(--gold-dim);
    background: rgba(201, 162, 39, .12);
}

.unit.pointed,
.hand .card.pointed,
.site-art.pointed {
    outline: 2px solid var(--gold);
    outline-offset: 1px;
    box-shadow: 0 0 12px rgba(201, 162, 39, .75);
    z-index: 2;
}

/* A tapped unit is drawn rotated, so its outline turns with it — which is
   right, and worth saying so nobody straightens it later. */
.unit.tapped.pointed { outline-offset: 1px; }

.preview {
    display: none;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    overflow: hidden;
}

.preview.shown { display: block; }
.preview img { display: block; width: 100%; }

/* The log takes whatever height the side has left, and scrolls inside it —
   a board is pushed several times a turn and a log that resized with it
   would move everything else on the panel each time. */
.log-box {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 8rem;
    flex: 1;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: .9rem;
}

.option.back { margin-top: .3rem; width: 100%; color: var(--ink-dim); border-style: dashed; }
.option.back:hover { color: var(--ink); }

.side-tabs { display: flex; flex-wrap: wrap; gap: .2rem; border-bottom: 1px solid var(--edge); }
.side-tab {
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--ink-dim);
    padding: .35rem .45rem;
    cursor: pointer;
    font: inherit;
    letter-spacing: .04em;
    text-transform: uppercase;
    font-size: .75rem;
}
.side-tab.active { color: var(--gold); border-bottom-color: var(--gold); }
.side-tab.flash { animation: tab-flash .9s ease-in-out infinite alternate; }
@keyframes tab-flash {
    from { color: var(--ink-dim); }
    to { color: var(--gold); text-shadow: 0 0 6px var(--gold-dim); }
}
@media (prefers-reduced-motion: reduce) {
    .side-tab.flash { animation: none; color: var(--gold); }
}
.side-tab:hover { color: var(--ink); }
.unread {
    display: inline-block;
    min-width: 1.2em;
    padding: 0 .3em;
    margin-left: .3em;
    border-radius: 1em;
    background: var(--gold);
    color: #1b1b1b;
    font-size: .7rem;
    text-align: center;
}
/* The display above outranks the hidden attribute's own, so a count once
   read stayed on the tab; hidden has to say so here. */
.unread[hidden] { display: none; }
.side-pane { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.side-pane[hidden] { display: none; }

/*
 * The four reference panes, one level down under Rules.
 *
 * Seven tabs wrapped onto three lines of a rail this narrow, which is
 * forty-five pixels of log traded for a row of things a player opens twice a
 * game. The three that are the game keep the top line; the four that are the
 * rules share a tab, and their own line is there only while it is open.
 *
 * Set smaller and quieter than the line above, so that the two rows read as
 * one inside the other rather than as two rows of equals.
 */
.rule-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: .15rem;
    padding-top: .35rem;
    flex: 0 0 auto;
}

.rule-tab {
    background: none;
    border: 1px solid transparent;
    border-radius: 999px;
    color: var(--ink-faint);
    padding: .1rem .4rem;
    cursor: pointer;
    font: inherit;
    letter-spacing: .03em;
    font-size: .68rem;
}
.rule-tab:hover { color: var(--ink); }
.rule-tab.active {
    color: var(--gold);
    border-color: var(--gold-dim);
    background: rgba(201, 162, 39, .08);
}

.rule-pane { display: flex; flex-direction: column; flex: 1; min-height: 0; }
.rule-pane[hidden] { display: none; }
.side-pane .chat-lines { margin-top: .5rem; }
#table-chat-form { display: flex; gap: .5rem; }
#table-chat-form input { flex: 1; }
.people { padding-top: .5rem; overflow-y: auto; }
.people-group + .people-group { margin-top: .8rem; }
.people h4 { margin: 0 0 .3rem; color: var(--ink-dim); font-weight: normal; letter-spacing: .05em; text-transform: uppercase; font-size: .7rem; }
.person { padding: .15rem 0; }
.person-name { color: var(--ink); }

/*
 * Game Aids: a key to the board's own shorthand.
 *
 * The board says a great deal without words -- a white edge, a tilt, a chip
 * dashed and sunk with a coloured dot in its corner -- and a player who has
 * not been told reads none of it. This is where it is told.
 *
 * Every entry draws itself with the board's own classes rather than with a
 * picture of them, so the key cannot drift from the thing it explains: change
 * how a warded unit looks and the key changes with it. The chips are drawn
 * small by setting the two properties the board's own rule reads.
 *
 * The drawing and the name share a line and the sentence runs the full width
 * under them, because the rail is two hundred pixels wide and a sentence in
 * the column left over beside a chip comes out four characters to the line.
 */
.aids { padding-top: .5rem; overflow-y: auto; }

.aid-group + .aid-group { margin-top: .9rem; }

.aids h4 {
    margin: 0 0 .3rem;
    color: var(--ink-dim);
    font-weight: normal;
    letter-spacing: .05em;
    text-transform: uppercase;
    font-size: .7rem;
}

.aid {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: center;
    gap: .1rem .5rem;
    padding: .4rem 0;
}

.aid + .aid { border-top: 1px solid rgba(43, 58, 61, .6); }

/* One lane for the drawing, the same width whatever is in it, so the names
   beside them line up down the column. Tall enough for a chip laid over at
   its tapped angle, which is the tallest thing the key draws. */
.aid-shown {
    --chip-wide: 26px;
    --chip-tall: 37px;
    width: 62px;
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
}

.aid-name { font-size: .78rem; color: var(--ink); letter-spacing: .03em; }

.aid-why {
    grid-column: 1 / -1;
    font-size: .72rem;
    line-height: 1.35;
    color: var(--ink-dim);
}

/* The swatches are the real elements, so they need only what the board would
   have given them: a square its own size, and something to be a picture of.
   A flat wash rather than card art, because the key is about the edge and the
   tilt and the dot, and a picture underneath competes with all three. */
/* Small enough that the two entries showing a pair of them -- which way the
   ground faces, and the two colours of being stopped -- still fit the lane. */
.aid-shown .square { width: 28px; height: 28px; flex: 0 0 28px; }
.aid-shown .unit { background-image: linear-gradient(150deg, #3b4b4f, #212e31 60%, #2d3c40); }
/* A band across the head of the card, so that ground laid facing the other
   way is visibly laid the other way round rather than merely shaded a
   little differently. */
.aid-shown .site-art { background-image: linear-gradient(180deg, #6d5d3d 0 32%, #2a231a 32%); }

/* A card out of the hand, which takes its shape from the hand it is normally
   in -- so the key gives it one of its own rather than borrowing that. */
.aid-shown .card {
    width: 30px;
    height: 42px;
    border-radius: var(--radius);
    border: 1px solid var(--edge);
    background: linear-gradient(150deg, #3b4b4f, #212e31);
}

.aid-shown .card.answerable {
    border-color: var(--good);
    box-shadow: 0 0 0 1px var(--good), 0 0 8px rgba(111, 159, 106, .45);
}

.aid-empty { font-size: .75rem; color: var(--ink-faint); line-height: 1.35; }

/*
 * ---------- watching a game that is over ----------
 *
 * The same board the table draws, out of boards that were written down as
 * the game was played rather than out of the engine playing it again. Which
 * is the whole point: the engine that would play it again is not the engine
 * that played it, and every card fixed since would quietly change what you
 * were shown. See Store.Step.
 */
#replay { height: 100vh; flex-direction: column; }
body[data-screen="replay"] { overflow: hidden; }

/* Laid out as the table is: the far player's rail on the left with what was
   asked under it, the board in the middle, and the near player's rail on the
   right with what was recently played under it, as a player saw it. */
.replay-grid {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: 280px minmax(0, 1fr) 300px;
    gap: .9rem;
    padding: 1rem;
    align-items: stretch;
}

.replay-title {
    font-family: var(--body);
    font-size: .7rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ink-dim);
    font-weight: normal;
}

.replay-asked { padding-top: .5rem; overflow-y: auto; flex: 1; min-height: 0; }

.replay-prompt {
    font-family: var(--display);
    font-size: .95rem;
    color: var(--ink);
    padding-bottom: .4rem;
}

/* What was on offer, and which of it was taken. The taken one is the answer
   and the rest are the roads not travelled, so only one of them is lit. */
.replay-option {
    font-size: .74rem;
    line-height: 1.35;
    color: var(--ink-faint);
    padding: .1rem 0 .1rem .8rem;
    text-indent: -.8rem;
}

.replay-option.taken { color: var(--gold); }
.replay-option.taken::before { content: "\2192\00a0"; }
.replay-option:not(.taken)::before { content: "\00a0\00a0\00a0"; }

.replay-none { font-size: .75rem; color: var(--ink-faint); line-height: 1.4; }

/* The transport: the buttons, then a scrubber that takes the rest. */
.transport {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: .4rem;
    padding: .5rem .75rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
}

.transport button {
    font-size: .8rem;
    padding: .2rem .5rem;
    min-width: 2.2rem;
}

.scrub {
    flex: 1;
    min-width: 0;
    accent-color: var(--gold);
    background: transparent;
}

/* A rail in the replay names its player, since neither of them is you. */
#replay .rail { flex: 0 0 auto; }

/*
 * The FAQ tab: what is asked about the cards in front of you.
 *
 * Shut by default and opened one card at a time, because the rail is narrow
 * and twenty cards' questions at once is a thing nobody scrolls twice. The
 * list of names is useful shut: it says which of the cards you can see have
 * something known to be asked about them.
 */
.faqs { padding-top: .5rem; overflow-y: auto; }

.faq-count {
    font-size: .7rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
    padding-bottom: .4rem;
}

.faq + .faq { border-top: 1px solid rgba(43, 58, 61, .6); }

.faq > summary {
    display: flex;
    align-items: baseline;
    gap: .4rem;
    padding: .35rem 0;
    cursor: pointer;
    list-style: none;
}

/* The disclosure triangle, drawn rather than inherited: Safari's own marker
   sits outside the box and pushed the name out of a rail this narrow. */
.faq > summary::-webkit-details-marker { display: none; }
.faq > summary::before {
    content: "";
    flex: 0 0 auto;
    width: 0;
    height: 0;
    border-left: 4px solid var(--ink-faint);
    border-top: 3px solid transparent;
    border-bottom: 3px solid transparent;
    transform: translateY(-1px);
}
.faq[open] > summary::before { transform: rotate(90deg) translateX(-1px); }

.faq-card { font-size: .8rem; color: var(--ink); }
.faq[open] .faq-card { color: var(--gold); }
.faq > summary:hover .faq-card { color: var(--gold); }

.faq-many {
    margin-left: auto;
    font-size: .68rem;
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
}

.faq-one { padding: 0 0 .5rem .6rem; }

.faq-q {
    font-size: .74rem;
    line-height: 1.35;
    color: var(--ink-dim);
    font-style: italic;
}

.faq-a {
    font-size: .74rem;
    line-height: 1.35;
    color: var(--ink);
    padding-top: .15rem;
}

.faq-empty { font-size: .75rem; color: var(--ink-faint); line-height: 1.35; }

/* The codex, which is the FAQ's shape with a box to search it by. */
.codex { padding-top: .5rem; overflow-y: auto; flex: 1; min-height: 0; }

.codex-search {
    flex: 0 0 auto;
    margin-top: .5rem;
    width: 100%;
    font: inherit;
    font-size: .78rem;
    padding: .25rem .4rem;
    color: var(--ink);
    background: var(--ground-deep);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
}
.codex-search:focus { outline: none; border-color: var(--gold-dim); }

/* One paragraph of an entry, set as the codex sets it: several of them are
   lists and worked examples, and run together they are unreadable. */
.codex-p {
    font-size: .74rem;
    line-height: 1.4;
    color: var(--ink-dim);
    padding: 0 0 .4rem .6rem;
}
.codex-p:first-of-type { color: var(--ink); }

/*
 * The quick reference: page 37 of the rulebook, as a page.
 *
 * Drawn to the width of the rail, which makes the small print small -- so the
 * link under it opens the picture at its own size, which is where anybody who
 * actually needs to read a paragraph of it will go.
 */
.quickref { padding-top: .5rem; overflow-y: auto; }

.quickref-page {
    display: block;
    width: 100%;
    height: auto;
    border-radius: var(--radius);
    border: 1px solid var(--edge);
    background: #fff;
}

.quickref-open {
    display: block;
    padding-top: .4rem;
    font-size: .72rem;
    color: var(--ink-dim);
}
.quickref-open:hover { color: var(--gold); }

.log {
    list-style: none;
    margin: .5rem 0 0;
    padding: 0 .4rem 0 0;
    /* All the height the column has left, down to its foot, so there is as
       much of the game to read as there is room for. Capped only on a narrow
       screen, below, where the table becomes a page that scrolls. */
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    font-size: .8rem;
    color: var(--ink-dim);
}

.log li { padding: .12rem 0; border-bottom: 1px solid rgba(43, 58, 61, .5); }
.log li:last-child { color: var(--ink); }

/* Shown only while the reader has scrolled away from the newest line. */
.log-latest {
    position: absolute;
    right: 1.2rem;
    bottom: .9rem;
    padding: .2rem .6rem;
    font-size: .75rem;
    background: var(--panel-high);
    border-color: var(--gold-dim);
    color: var(--gold);
    box-shadow: var(--shadow);
}

/* A card held under the pointer, shown full size wherever there is room. */
.hover {
    position: fixed;
    z-index: 50;
    width: 220px;
    pointer-events: none;
    border-radius: 4px;
    box-shadow: 0 6px 26px rgba(0, 0, 0, .7);
}

.hover img { display: block; width: 100%; border-radius: 4px 4px 0 0; }

/*
 * A site, shown the way it lies in the Realm.
 *
 * The card is printed portrait and played sideways, so a picture of it stood
 * upright is a picture you have to tilt your head at. The frame is the card's
 * own shape turned a quarter: as wide as the box, and 380/531 of that tall.
 * The picture inside is sized so that turning it fills the frame exactly —
 * its pre-rotation width is 380/531 of the box, which makes its height the
 * box's width, which is its width once turned.
 */
.hover.landscape { width: 340px; }

.hover.landscape .shot {
    position: relative;
    width: 100%;
    aspect-ratio: 531 / 380;
    overflow: hidden;
    border-radius: 4px 4px 0 0;
}

.hover.landscape .shot img {
    position: absolute;
    inset: 0;
    margin: auto;
    width: 71.56%;
    height: auto;
    border-radius: 4px;
    transform: rotate(90deg);
}

/* What the card says, set to be read rather than photographed. */
.hover-text {
    background: var(--panel);
    border: 1px solid var(--edge);
    border-top: none;
    border-radius: 0 0 4px 4px;
    padding: .5rem .6rem .6rem;
    font-size: .78rem;
    line-height: 1.35;
    color: var(--ink);
}

.hover img + .hover-text { border-top: none; }
.hover-text:first-child { border-top: 1px solid var(--edge); border-radius: 4px; }

.hover-name {
    font-family: var(--display);
    font-size: .9rem;
    color: var(--gold);
}

.hover-type {
    margin-bottom: .35rem;
    font-size: .72rem;
    font-style: italic;
    color: var(--ink-faint);
}

.hover-text p { margin: .3rem 0 0; }

/* A card printed on both sides, pointed at on its front: the two faces side
   by side, each as wide as a single card's picture. */
.hover.faces { width: 440px; }
.hover-faces {
    display: grid;
    grid-template-columns: 1fr 1fr;
}
.hover-faces img:first-child { border-radius: 4px 0 0 0; }
.hover-faces img:last-child { border-radius: 0 4px 0 0; }
.hover-faces img:only-child { border-radius: 4px 4px 0 0; }

/* The back, in words, where there is no picture of it: the shape of a card,
   so the two faces still read as two faces. */
.hover-face-text {
    aspect-ratio: var(--card-ratio);
    overflow: hidden;
    padding: .6rem .65rem;
    background: var(--panel-high);
    border: 1px solid var(--edge);
    border-bottom: none;
    border-radius: 0 4px 0 0;
    font-size: .76rem;
    line-height: 1.35;
    color: var(--ink);
}
.hover-face-text p { margin: .3rem 0 0; }

/* ---------- scrollbars, so the dark does not break ---------- */

::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: var(--ground-deep); }
::-webkit-scrollbar-thumb { background: var(--edge); border-radius: 5px; }
::-webkit-scrollbar-thumb:hover { background: var(--edge-bright); }

@media (max-width: 1100px) {
    body[data-screen="table"], body[data-screen="replay"] { overflow: auto; }
    #table, #replay { height: auto; }
    .table-grid, .builder-grid, .replay-grid { grid-template-columns: minmax(0, 1fr); }
    .flank { height: auto; }
    /* The table is a page that scrolls here, with no leftover height to give
       the log -- uncapped it grows to two hundred lines tall and takes the
       page with it. */
    .log { max-height: 40vh; }
    /* Stacked on a narrow window, the board takes the width it is given and
       the container query has no height to measure. */
    .realm { width: 100%; height: auto; }
    .realm-holder { container-type: normal; }
    .builder-grid { height: auto; }
}

/* The handle that folds the pinned question on a phone; nowhere else. */
.decision .fold {
    display: none;
    position: absolute;
    top: .35rem;
    right: .5rem;
    padding: 0 .4rem;
    font-size: 1rem;
    line-height: 1.4;
    background: none;
    border: none;
    color: var(--ink-faint);
}
.decision { position: relative; }

/* ---------- a phone, held upright ---------- */

/* Below the width of a tablet the table is a page to scroll, laid out for
   a thumb: the board first and full width, the question pinned to the foot
   of the screen where the thumb is, the hand under the board, the two rails
   folded into a line each, the log last (the user, 2026-10-02). Held
   sideways, a phone gets the desktop table instead, scaled to fit, which
   app.js arranges through the viewport (see fitTheViewport). */
@media (max-width: 767px) {
    .bar { flex-wrap: wrap; gap: .3rem .6rem; padding: .4rem .6rem; }
    .bar-left, .bar-right { flex-wrap: wrap; gap: .3rem .5rem; }
    .bar .bug-report { display: none; }
    .bar h1 { font-size: 1.1rem; }
    .bar button { padding: .25rem .5rem; font-size: .8rem; }

    .table-grid {
        display: flex;
        flex-direction: column;
        gap: .6rem;
        padding: .5rem .5rem 48vh;
    }
    /* The flanks and the middle give up their boxes, so what they held can
       be put in a thumb's order. */
    .table-grid > .flank, .table-grid > .middle { display: contents; }
    .realm-holder { order: 1; }
    .hand-strip { order: 2; }
    #rail-you { order: 3; }
    #rail-them { order: 4; }
    #played { order: 5; }
    .log-box { order: 6; }

    /* A rail is a line, not a column: the name, then the numbers. */
    .rail {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
        gap: .3rem .8rem;
        padding: .4rem .6rem;
    }

    /* The question, pinned to the foot of the screen under the thumb, and
       scrolling within itself when the options run long. */
    #decision {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 40;
        max-height: 45vh;
        overflow-y: auto;
        border-radius: var(--radius) var(--radius) 0 0;
        box-shadow: 0 -6px 18px rgba(0, 0, 0, .55);
    }
    #decision.folded { max-height: 2.6rem; overflow: hidden; }
    #decision .fold { display: block; }
    /* The pane that is already a scrolling sheet needs no second one inside. */
    #decision .options { max-height: none; }

    /* The pop-up over a card, which a finger cannot hover: centred, and
       dismissed by a tap anywhere else. */
    .hover.touch {
        left: 50% !important;
        top: 8px !important;
        transform: translateX(-50%);
        max-width: 92vw;
        max-height: 88vh;
        overflow-y: auto;
    }
}

/* ---------- the game hall ---------- */

/* A column: the tables and the controls take what they need, and the chat
   with the roster beside it takes everything left over. Laid out as a grid
   with one row per panel, a fourth list of tables took the row meant for
   the chat, and the evening's talk sat in a strip at the foot of the page
   under a controls panel that had grown to fill the gap. */
.hall {
    display: flex;
    flex-direction: column;
    gap: .75rem;
    padding: .75rem;
    flex: 1;
    min-height: 0;
}

.hall > .panel { flex: 0 0 auto; }
.hall > .hall-bottom { flex: 1 1 auto; min-height: 12rem; }

/* A long list of games must not push the chat off the screen either. */
.hall .panel.tables { max-height: 30vh; overflow-y: auto; }

.hall .panel.tables { padding-bottom: .35rem; }

.hall-table {
    width: 100%;
    border-collapse: collapse;
    font-size: .92rem;
}

.hall-table th {
    text-align: left;
    font-family: var(--display);
    font-weight: normal;
    font-size: .82rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
    border-bottom: 1px solid var(--edge);
    padding: .2rem .5rem .3rem 0;
}

.hall-table td {
    padding: .3rem .5rem .3rem 0;
    border-bottom: 1px solid #1c2628;
    vertical-align: middle;
}

.hall-table tr:last-child td { border-bottom: none; }
.hall-table td:last-child { text-align: right; padding-right: 0; }
.hall-table td.empty {
    color: var(--ink-faint);
    font-style: italic;
    text-align: left;
}
.hall-table button { padding: .15rem .6rem; font-size: .85rem; }

/* The row of controls that makes a table. */
.hall-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: .6rem;
}

.hall-controls label {
    display: flex;
    flex-direction: column;
    gap: .15rem;
    font-size: .78rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
}

.hall-controls select { min-width: 9rem; }
.hall-controls #open-deck, .hall-controls #open-opponent { min-width: 13rem; }
.hall-controls #open-deck-link { min-width: 18rem; }
.hall-controls .divider {
    width: 1px;
    align-self: stretch;
    background: var(--edge);
    margin: 0 .2rem;
}

button.linkish {
    background: none;
    border: none;
    color: var(--gold);
    font-family: var(--display);
    padding: .3rem .2rem;
    text-decoration: underline;
    text-underline-offset: 3px;
}

button.linkish:hover { background: none; color: var(--ink); }

/* The hall's lists, each hidden by its own Hide until the page is reloaded. */
button.linkish.hide-section { font-size: .75rem; margin-left: .75rem; padding: 0 .2rem; vertical-align: middle; }
.hall section.panel[hidden] { display: none; }

/* Chat, and who is here to read it. */
.hall-bottom {
    display: grid;
    grid-template-columns: 1fr 14rem;
    gap: .75rem;
    min-height: 0;
}

.panel.chat {
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding-bottom: .5rem;
}

.chat-lines {
    flex: 1;
    overflow-y: auto;
    margin: 0 0 .5rem;
    padding: 0 .25rem 0 0;
    list-style: none;
    font-size: .92rem;
    line-height: 1.45;
}

.chat-lines li { padding: .05rem 0; }
.chat-when { color: var(--ink-faint); font-variant-numeric: tabular-nums; margin-right: .4rem; }
.chat-who { color: var(--gold); margin-right: .35rem; }
.chat-said { color: var(--ink); }

#chat-form { display: flex; gap: .5rem; }
#chat-form input { flex: 1; }

.panel.present { min-height: 0; overflow-y: auto; }
/* The Private game box, beside Create table rather than among the choices:
   a box with its words beside it, as the bar's toggles are, not a label
   stacked over its field like the choices to its left. */
.hall-controls label.private-game {
    flex-direction: row;
    align-items: center;
    align-self: center;
    gap: .35rem;
    margin: 0;
    font-size: .85rem;
    text-transform: none;
    letter-spacing: 0;
    color: var(--ink-dim);
}

/* Private game and Require password, one under the other beside Create
   table, with the password's own field under them once it is asked for. */
.hall-controls .table-options {
    display: flex;
    flex-direction: column;
    align-self: center;
    gap: .2rem;
}
.hall-controls .table-options input[type=password] { width: 11rem; font-size: .85rem; }

/* A playing table's seats: each player with their Avatar, life and time
   left, one to a line; the clock that is running in gold, as at the table. */
.hall-table .seat {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .1rem .55rem;
}
.hall-table .seat-name { color: var(--ink); }
.hall-table .seat-avatar { color: var(--ink-dim); font-style: italic; }
.hall-table .seat-life,
.hall-table .seat-clock { color: var(--ink-faint); font-variant-numeric: tabular-nums; }
.hall-table .seat.ticking .seat-clock { color: var(--gold); }

/* A panel's title with its own controls beside it: Games played's filters. */
.panel-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .4rem .9rem;
    margin-bottom: .5rem;
}
.panel-head h2 { margin: 0; }
.played-filters { display: flex; align-items: center; gap: .8rem; }

/* What somebody in the hall is doing, quieter than their name beside it. */
#present-list .doing {
    margin-left: .45rem;
    font-size: .75rem;
    font-style: italic;
    color: var(--ink-faint);
}
.list.plain { list-style: none; margin: 0; padding: 0; }
.list.plain li {
    padding: .15rem 0;
    font-size: .92rem;
    color: var(--ink-dim);
    border: none;
}
.list.plain li.you { color: var(--gold); }

/* A select that sits in a toolbar rather than filling a form. */
select.compact { width: auto; max-width: 16rem; }

/* Filters that stay pressed: any of the pressed ones in a group lets a card through. */
.pool-toggles { display: flex; flex-wrap: wrap; gap: .4rem 1.2rem; margin-bottom: .8rem; }
.toggle-group { display: inline-flex; gap: .3rem; }
button.toggle {
    padding: .2rem .6rem;
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    opacity: .7;
}
button.toggle.on { opacity: 1; border-color: var(--gold); color: var(--gold); }
button.toggle.excluded { opacity: 1; border-color: #b0413e; color: #b0413e; text-decoration: line-through; }

.avatar-row { display: flex; align-items: center; justify-content: space-between; gap: .5rem; }
.avatar-row button { padding: 0 .5rem; line-height: 1.4; }

#shift-hint { align-self: center; font-size: .78rem; }

/* ---- takeback: a list of recent actions under the header button ---- */
.takeback-holder { position: relative; }
.takebacks {
  position: absolute; right: 0; top: calc(100% + .4rem); z-index: 30;
  min-width: 18rem; max-width: 28rem; max-height: 60vh; overflow-y: auto;
  background: var(--panel-high, #1a1f23); border: 1px solid var(--gold-dim, #6b5a2e);
  border-radius: .4rem; padding: .35rem; box-shadow: 0 .6rem 1.6rem rgba(0,0,0,.5);
  display: flex; flex-direction: column; gap: .2rem;
}
.takebacks[hidden] { display: none; }
.takebacks-title { font-size: .8rem; letter-spacing: .04em; text-transform: uppercase;
  opacity: .7; padding: .2rem .5rem; }
.takeback-row {
  text-align: left; padding: .4rem .6rem; border-radius: .3rem;
  background: transparent; border: 1px solid transparent; color: inherit; cursor: pointer;
  font: inherit;
}
/* ---- back to the start of a turn: the question put to the other player ---- */
.turn-takeback-ask {
    position: fixed; top: 64px; left: 50%; transform: translateX(-50%); z-index: 60;
    display: flex; gap: 10px; align-items: center; padding: 8px 14px;
    background: var(--panel, #1d1a14); border: 1px solid var(--gold-dim, #6b5a2e); border-radius: 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,.4); font-size: .9rem; max-width: calc(100vw - 32px);
}
.turn-takeback-ask button { padding: 4px 12px; }
.takeback-row:hover { border-color: var(--gold-dim, #6b5a2e); background: rgba(255,255,255,.04); }

/* ---------- a table of more than two ----------

   A free-for-all: four players round the cross. None of this reaches the game
   of two, whose screen is drawn as it always was: every rule here is under
   .four-seats, a seat's own class, or an element only a table of more than
   two shows. */

/* A colour for each seat, the same for everybody looking: gold is whoever the
   board is seen from, and the others are their seats' own. None is near
   another border's colour -- gold (yours), red (theirs), pink (silenced),
   purple (disabled) or white (warded), nor in colour-blind mode vermillion,
   yellow or reddish purple (the user, 9 October 2026): cyan, royal blue,
   green and orange. A set from the
   Okabe-Ito colours for colour-blind eyes, chosen to stay apart from gold and
   from one another under every common kind of colour blindness. */
:root {
    --seat-0: #26c6da;
    --seat-1: #4a72e0;
    --seat-2: #6fbf4a;
    --seat-3: #e08a2e;
    --nobodys: #8a9a9c;
}
html.colorblind {
    --seat-0: #56b4e9;
    --seat-1: #0072b2;
    --seat-2: #009e73;
    --seat-3: #e69f00;
}

.unit.theirs.seat-0, .played-card.theirs.seat-0 { border-color: var(--seat-0); }
.unit.theirs.seat-1, .played-card.theirs.seat-1 { border-color: var(--seat-1); }
.unit.theirs.seat-2, .played-card.theirs.seat-2 { border-color: var(--seat-2); }
.unit.theirs.seat-3, .played-card.theirs.seat-3 { border-color: var(--seat-3); }
.unit.theirs.nobodys { border-color: var(--nobodys); }

/* The big rails of the game of two give way to four compact ones. */
#table.four-seats #rail-them, #table.four-seats #rail-you,
#replay.four-seats #replay-rail-far, #replay.four-seats #replay-rail-near { display: none; }

/* The choices only a table of more than two offers, hidden until it does. */
.toggle[hidden], .hall-controls label[hidden] { display: none; }
/* The options pane has room, and its lines are long enough to wrap on a phone. */
[data-pane="options"] .toggle { display: flex; white-space: normal; align-items: flex-start; margin: .3rem 0; }
[data-pane="options"] .toggle input { margin-top: .15em; }
[data-pane="options"] h3 { margin-top: 1rem; }
[data-pane="options"] .choice-row { display: flex; flex-wrap: wrap; gap: .3rem 1rem; align-items: center; margin: .3rem 0; font-size: .72rem; color: var(--ink-dim); }
[data-pane="options"] .choice-row .toggle { margin: 0; }
[data-pane="options"] select.compact { max-width: 16rem; }

/* Animations switched off under Options: everything holds still. */
html.still *, html.still *::before, html.still *::after { animation: none !important; transition: none !important; }
html.still .side-tab.flash { color: var(--gold); }

/* The pop-up's size, chosen under Options. */
html[data-popup-size="small"] .hover { width: 170px; }
html[data-popup-size="small"] .hover.landscape { width: 260px; }
html[data-popup-size="large"] .hover { width: 300px; }
html[data-popup-size="large"] .hover.landscape { width: 460px; }

/* The four rails, when the squares are too small for the corners: down the
   side column in turn order. */
.seat-rails { display: flex; flex-direction: column; gap: .4rem; flex: 0 0 auto; }
.seat-rails[hidden] { display: none; }

/* One player's rail, compact enough for a cut-out corner of the cross: the
   name in its seat's colour, then life, mana, time and thresholds, then the
   counts. A player out of the game is greyed. */
.seat-rail {
    --seat-colour: var(--edge-bright);
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .15rem;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
    padding: .25rem .45rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-left: 3px solid var(--seat-colour);
    border-radius: var(--radius);
    font-size: .72rem;
    line-height: 1.25;
}
.seat-rail.mine { --seat-colour: var(--gold); }
.seat-rail.seat-0 { --seat-colour: var(--seat-0); }
.seat-rail.seat-1 { --seat-colour: var(--seat-1); }
.seat-rail.seat-2 { --seat-colour: var(--seat-2); }
.seat-rail.seat-3 { --seat-colour: var(--seat-3); }
.seat-rail.turn { box-shadow: inset 0 0 0 1px var(--seat-colour); }
.seat-rail.out { opacity: .45; filter: grayscale(1); }
.seat-rail .name { font-family: var(--display); color: var(--seat-colour); font-size: .9rem; }
.seat-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: .1rem .45rem; }
.seat-tag { font-size: .62rem; letter-spacing: .05em; text-transform: uppercase; color: var(--ink-dim); }
.seat-tag.door-tag { color: var(--danger); }
.seat-vitals { display: flex; align-items: center; flex-wrap: wrap; gap: .1rem .55rem; color: var(--ink-dim); }
.seat-vital b { color: var(--ink); font-size: .92rem; font-variant-numeric: tabular-nums; }
.seat-vital.low b { color: var(--danger); }
.seat-vitals .thresholds { margin-left: auto; gap: 2px; padding-bottom: 0; }
.seat-vitals .pip { width: 18px; height: 18px; background-size: 18px 18px; font-size: .6rem; }
.seat-tallies { display: flex; flex-wrap: wrap; gap: 0 .55rem; color: var(--ink-dim); font-variant-numeric: tabular-nums; }
.seat-tallies .stat b { color: var(--ink); }
.seat-tallies .stat.lookable { cursor: pointer; }
.seat-tallies .stat.lookable.empty { cursor: default; opacity: .6; }
.seat-tallies .stat.lookable:not(.empty):hover b { color: var(--gold); }

/* In a corner of the cross, laid over the two cells the cross leaves out
   there, beside its owner's arm. */
.realm > .seat-rail.in-corner { margin: 1px; z-index: 3; }

/* The hand bar beside the decision, so the cross has the middle column's
   whole height. */
#table.four-seats .flank.yours .hand-strip { flex: 0 0 auto; padding: 0 .5rem; }

/* What the replay says of a player leaving, where it came. */
.replay-left { margin-top: .4rem; font-size: .76rem; color: var(--danger); }

/* A playing table's seat out of the game, in the hall. */
.hall-table .seat.out { opacity: .5; text-decoration: line-through; }
.hall-table td.seat-action { white-space: nowrap; }
.hall-table td.seat-action select { margin-right: .3rem; }

@media (max-width: 767px) {
    #seat-rails { order: 3; }
}
.seat-tag.asked-tag { color: var(--gold); }
/* The window of cards played, given way on a short window at a table of more than two. */
#table.four-seats .played.squeezed { display: none; }

/* ---------- Two-Headed Dragon ----------

   Two teams of two on the nine-by-four board, which the window's width limits
   rather than its height: so the board has the width of the window less one
   column -- the decision, the cards played and the log, stacked -- and each
   team's rails lie across its top and bottom, the other team's above and
   yours below, each over its owner's half, with the team's one life between
   them. The hands lie under the board, yours under your half and your
   partner's under theirs. Colours are by team from whoever the board is seen
   from: theirs gold, their partner green (the seat-2 colour), the other team
   red and blue. None of this reaches the game of two or free-for-all: every
   rule is under .two-heads, which only a table of Two-Headed Dragon has, or
   is for an element only that table shows. */

#table.two-heads .flank.theirs { display: none; }

@media (min-width: 1101px) {
    #table.two-heads .table-grid {
        grid-template-columns: minmax(0, 1fr) var(--flank-right-least);
    }
}

@media (min-width: 768px) {
    #table.two-heads .middle {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        grid-template-rows: auto minmax(0, 1fr) auto auto;
        gap: .45rem .75rem;
    }
    #table.two-heads #rails-above { grid-column: 1 / -1; grid-row: 1; }
    #table.two-heads .realm-holder { grid-column: 1 / -1; grid-row: 2; }
    #table.two-heads #rails-below { grid-column: 1 / -1; grid-row: 3; }
    /* The hand bar the whole width: yours, or your partner's turned to from
       it (the user's ruling of 4 October 2026). */
    #table.two-heads .hand-strip { grid-row: 4; grid-column: 1 / -1; }
    #table.two-heads .partner-strip { grid-row: 4; grid-column: var(--partner-half, 2); }
}

/* A short window gives the board the hands' spare height first: each card's
   head -- its name, cost and thresholds -- still shows. */
@media (min-width: 768px) and (max-height: 720px) {
    #table.two-heads .hand-strip,
    #table.two-heads .partner-strip { height: 80px; }
    #table.two-heads .hand { height: 66px; }
    #table.two-heads #hand-label { letter-spacing: .06em; }
}

/* The header one line high, the board's every pixel being worth four. */
#table.two-heads > .bar h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
#table.two-heads #table-turn { white-space: nowrap; }

/* The rails across the board: one line each, the team's life between. */
.team-rails {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    gap: .45rem;
    align-items: stretch;
    min-width: 0;
}
.team-rails[hidden] { display: none; }

.team-rail {
    --seat-colour: var(--edge-bright);
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: .05rem;
    min-width: 0;
    overflow: hidden;
    padding: .2rem .5rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-left: 3px solid var(--seat-colour);
    border-radius: var(--radius);
    font-size: .72rem;
    line-height: 1.25;
    color: var(--ink-dim);
}
.team-rail.mine { --seat-colour: var(--gold); }
.team-rail.seat-0 { --seat-colour: var(--seat-0); }
.team-rail.seat-1 { --seat-colour: var(--seat-1); }
.team-rail.seat-2 { --seat-colour: var(--seat-2); }
.team-rail.turn { box-shadow: inset 0 0 0 1px var(--seat-colour); }
.team-rail.out { opacity: .45; filter: grayscale(1); }
/* A head that has conceded: still on the board, playing no more. */
.team-rail.conceded { opacity: .6; }
.team-rail .name { font-family: var(--display); color: var(--seat-colour); font-size: .9rem; }
.team-rail .seat-head,
.team-rail .seat-vitals,
.team-rail .seat-tallies,
.team-rail-numbers { display: flex; align-items: center; flex-wrap: wrap; gap: 0 .45rem; }
.team-rail-numbers { gap: 0 .9rem; }
.team-rail .seat-vitals .thresholds { margin-left: 0; gap: 2px; padding-bottom: 0; }
.team-rail .seat-vitals .pip { width: 16px; height: 16px; background-size: 16px 16px; font-size: .58rem; }

.team-life {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: .05rem;
    min-width: 7.5rem;
    padding: .15rem .6rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    font-size: .66rem;
    letter-spacing: .04em;
    color: var(--ink-dim);
    line-height: 1.15;
    text-align: center;
}
.team-life.turn { border-color: var(--gold-dim); box-shadow: inset 0 0 0 1px rgba(201, 162, 39, .18); }
.team-life-said, .team-life-numbers { display: flex; align-items: baseline; gap: .45rem; white-space: nowrap; }
.team-life-label { text-transform: uppercase; }
.team-life-total b { color: var(--ink); font-size: 1.15rem; line-height: 1.1; font-variant-numeric: tabular-nums; }
.team-life-max { color: var(--ink-dim); font-size: .8rem; }
.team-life .seat-vital b { color: var(--ink); font-size: .85rem; font-variant-numeric: tabular-nums; }
.team-life .seat-vital.low b { color: var(--danger); }

/* Your partner's hand: a fan of its own, edged in the partner's green. */
.partner-strip {
    flex: 0 0 auto;
    height: 110px;
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: 0 .75rem;
    background: var(--panel);
    border: 1px solid var(--edge);
    border-left: 3px solid var(--seat-2);
    border-radius: var(--radius);
    min-width: 0;
}
.partner-strip[hidden] { display: none; }
#partner-hand-label {
    flex: 0 0 auto;
    width: 24px;
    align-self: stretch;
    display: flex;
    align-items: center;
    justify-content: center;
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    font-family: var(--body);
    font-size: .66rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--seat-2);
    white-space: nowrap;
    overflow: hidden;
    margin: 0;
}

/* The hand bar's toggle at Two-Headed Dragon: your hand or your partner's,
   the one showing pressed; your partner's in their green, and the bar edged
   in it while theirs is showing, so it is never taken for yours. */
.hand-toggle {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: .3rem;
    align-self: center;
    max-width: 5.5rem;
}
.hand-toggle[hidden] { display: none; }
.hand-toggle button {
    font-size: .68rem;
    padding: .2rem .45rem;
    line-height: 1.15;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--ink-dim);
    background: transparent;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    cursor: pointer;
}
.hand-toggle button[aria-pressed="true"] { color: var(--ink); border-color: var(--gold); background: var(--panel-raised, rgba(255,255,255,.04)); }
.hand-toggle button[data-hand="partner"][aria-pressed="true"] { border-color: var(--seat-2); color: var(--seat-2); }
.hand-strip.showing-partner { border-left: 3px solid var(--seat-2); }
.hand-strip.showing-partner #hand-label { color: var(--seat-2); overflow: hidden; }
#hand-label .hand-label-words { display: block; max-height: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hand .held-by.partners-rule span { color: var(--seat-2); }
@media (min-width: 768px) and (max-height: 720px) {
    .hand-toggle { gap: .2rem; }
    .hand-toggle button { padding: .1rem .4rem; }
}

/* What your partner is being asked, under the words that say you wait. */
.decision .partner-asked { margin-top: .55rem; padding-left: .55rem; border-left: 3px solid var(--seat-2); font-size: .78rem; }
.decision .partner-asked-head { color: var(--seat-2); text-transform: uppercase; letter-spacing: .06em; font-size: .68rem; }
.decision .partner-asked-prompt { color: var(--ink); margin: .15rem 0 .25rem; }
.decision .partner-asked-options { margin: 0; padding-left: 1.1rem; max-height: 9rem; overflow-y: auto; color: var(--ink-dim); }

/* What the shared main phase says beside a partner's own offer. */
.decision .shared-note { font-size: .78rem; color: var(--ink-dim); margin: -.15rem 0 .45rem; }

/* The Team tab's pane, which says whose it is: the team chat box, laid out
   as the table's chat is, its lines never squeezed out of sight. */
.team-note { margin: .45rem 0 0; font-size: .72rem; color: var(--ink-faint); }
#team-chat-lines { min-height: 2.8rem; margin-top: .35rem; }
/* Its unread count gone once read: .unread's display would show it hidden. */
#team-unread[hidden] { display: none; }
#team-chat-form { display: flex; gap: .5rem; }
#team-chat-form input { flex: 1; min-width: 0; }

/* A short window: the cards played give the log and the chats their room
   under the decision, the log saying the same in words. */
@media (min-width: 768px) and (max-height: 760px) {
    #table.two-heads .flank.yours .played { display: none; }
}
.side-tab[hidden] { display: none; }

/* A replay's step where both partners were offered their actions. */

/* A phone: the rails above and below the board, your partner's hand after yours. */
@media (max-width: 767px) {
    #table.two-heads #rails-above,
    #table.two-heads #rails-below { order: 1; }
    #table.two-heads .partner-strip { order: 2; }
}
.team-life .turn-tag { color: var(--gold); }
/* Somebody looking on has no hand to lay out, and the board takes its room. */
#table.two-heads.looking-on .hand-strip { display: none; }

/* ---------- the lobby's tabs (the user, 9 October 2026) ---------- */
.lobby-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem;
    padding: .5rem .75rem 0;
    border-bottom: 1px solid var(--edge);
    background: var(--ground-deep);
}
.lobby-tabs [data-tab] {
    background: var(--panel-high);
    border: 1px solid var(--edge);
    border-bottom: none;
    border-radius: var(--radius) var(--radius) 0 0;
    color: var(--ink-dim);
    padding: .35rem .8rem;
    font-size: .85rem;
}
.lobby-tabs [data-tab]:hover { color: var(--ink); }
.lobby-tabs [data-tab][aria-selected="true"] { background: var(--gold-dim); color: var(--ink); border-color: var(--gold); }
.lobby-tabs [data-tab]:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; }
#lobby [data-pane][hidden] { display: none; }
.tab-pane { flex: 1; min-height: 0; overflow: auto; margin: .75rem; }
.tab-pane h3 { color: var(--gold); font-size: .95rem; margin: 1rem 0 .4rem; }
.wide-table { overflow-x: auto; }
.history-table td, .stats-table td { font-variant-numeric: tabular-nums; }

.league-heading.mine { color: var(--air); }
.league-heading.other { color: var(--good); }
.league-list { border: 1px solid var(--edge); border-radius: var(--radius); padding: .6rem .8rem; }

.format-rule { border-bottom: 1px solid var(--edge); padding: .4rem 0; }
.format-rule summary { cursor: pointer; font-size: 1.05rem; color: var(--ink); }
.format-rule ul { margin: .4rem 0 .2rem 1.2rem; display: grid; gap: .3rem; }
.format-rule li b { color: var(--gold); }
.format-rule .valid { color: var(--good); }

.stats-form, .profile-form { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem 1rem; margin-bottom: .8rem; }
.profile-form { flex-direction: column; align-items: flex-start; max-width: 32rem; }
/* Hidden means hidden: the admin's rename form is kept from everybody else (the user, 9 October 2026). */
.profile-form[hidden], .stats-form[hidden] { display: none; }
.profile-form label { display: flex; flex-direction: column; gap: .2rem; }

.trophy-list { list-style: none; margin: 0; padding: 0; display: grid; gap: .5rem; }
.trophy { display: flex; gap: .75rem; align-items: flex-start; padding: .6rem .8rem; border: 1px solid var(--edge); border-radius: var(--radius); }
.trophy div { display: flex; flex-direction: column; gap: .15rem; }
.trophy.earned { border-color: var(--gold); }
.trophy.locked { color: var(--ink-dim); }
.trophy-mark { font-size: 1.3rem; width: 1.6rem; text-align: center; }
.trophy-riddle { color: var(--ink-dim); }

.trophy-section { list-style: none; }
.trophy-section h3 { margin: 1rem 0 .4rem; }
.trophy-items { list-style: none; margin: 0; padding: 0; display: grid; gap: .4rem;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
.trophy .trophy-mark { min-width: 3.2rem; color: var(--gold); letter-spacing: .05em; }

.league { border-bottom: 1px solid var(--edge); padding: .6rem 0; }
.league:last-child { border-bottom: none; }
.league-name { font-size: 1.2rem; color: var(--ink); margin: 0 0 .2rem; }
.league-when .starts { color: var(--good); }
.league-when .ends { color: var(--danger); }
.league-details { border: 1px solid var(--gold-dim); border-radius: var(--radius); padding: .6rem .8rem; margin-top: .5rem; }
.league-details h4 { margin: .6rem 0 .2rem; color: var(--gold); }
.league-tabs { display: flex; gap: .3rem; margin: .6rem 0 .4rem; }
.league-tabs .selected { background: var(--gold-dim); color: var(--ink); }

/* Moving on the board (prototype): the unit picked up, where it can go, what it can strike. */
.move-picked { outline: 3px solid var(--gold, #d4a93c); outline-offset: 2px; }
.square.move-reach, .square.move-stay { cursor: pointer; }
/* The mulligan chosen from the hand: double-click a card to return it. */
#hand .card.mull-choosable .reach { cursor: pointer; }
#hand .card.mull-picked { outline: 3px solid var(--gold, #d4a93c); outline-offset: 1px; }
/* Dimmed, with the word at the corner the fan leaves showing. */
#hand .card.mull-picked::before {
    content: "Return"; position: absolute; inset: 0; z-index: 2;
    padding: .25rem .3rem; background: rgba(10, 16, 18, .55);
    color: var(--gold, #d4a93c); font-size: .72rem; font-weight: 700; letter-spacing: .05em;
    text-shadow: 0 1px 2px #000; pointer-events: none;
}
/* Over the site's picture, not under it: the picture fills the square. */
.square.move-reach::after,
.square.move-stay::after {
    content: "Move here";
    position: absolute; inset: 0; z-index: 3;
    display: flex; align-items: center; justify-content: center;
    box-shadow: inset 0 0 0 3px rgba(96, 200, 120, .9);
    background: rgba(96, 200, 120, .16);
    color: #eaf7ec; font-size: .8rem; font-weight: 600; letter-spacing: .04em;
    text-shadow: 0 1px 3px rgba(0, 0, 0, .9);
    pointer-events: none;
}
.square.move-stay::after { content: "Stay put"; }
.square.move-reach:hover::after,
.square.move-stay:hover::after { background: rgba(96, 200, 120, .3); box-shadow: inset 0 0 0 4px rgb(96, 200, 120); }
.move-target { outline: 3px solid rgba(220, 70, 60, .95); outline-offset: 1px; cursor: crosshair; }
.move-target:hover { outline-width: 4px; }
@media (prefers-reduced-motion: no-preference) {
    .move-target { transition: outline-width .12s ease; }
}

/* ---------- the physical table: cards picked up and put down (table.js) ---------- */

/* A card with a shape in the question is picked up by the hand. */
#hand .card.draggable .reach, #realm .unit.draggable, [data-pile].draggable { cursor: grab; }
#hand .card.draggable .reach, #realm .unit, [data-pile] { touch-action: none; }
body.dragging-card, body.dragging-card * { cursor: grabbing !important; }

/* The card left behind while its ghost is carried. */
.dragging { opacity: .35; }

/* The ghost under the pointer: the card itself, lifted. Takes no pointer, so
   what is under it is what the drop lands on. */
.drag-ghost {
    position: fixed;
    left: 0;
    top: 0;
    margin: 0;
    z-index: 60;
    pointer-events: none;
    opacity: .92;
    box-shadow: 0 10px 24px rgba(0, 0, 0, .55);
    transform-origin: top left;
}
.drag-ghost.tapped { transform: none; }
.drag-ghost.snapping { transition: transform .2s ease-in; opacity: .6; }
@media (prefers-reduced-motion: reduce) { .drag-ghost.snapping { transition: none; } }

/* Where the card could be put down, and the one place the pointer is over. */
#realm .square.drop-ok {
    border-color: var(--good);
    box-shadow: inset 0 0 0 2px var(--good), inset 0 0 14px rgba(111, 159, 106, .5);
    z-index: 1;
}
#realm [data-card].drop-ok { outline: 3px solid var(--good); outline-offset: 1px; z-index: 3; }
#realm .unit.theirs.drop-ok { outline-color: rgba(220, 70, 60, .95); }
[data-pile].drop-ok b, #hand.drop-ok { outline: 2px solid var(--good); outline-offset: 2px; border-radius: 3px; }
#realm.drop-edge { outline: 2px dashed var(--good); outline-offset: 4px; }
.drop-over, #realm .square.drop-over { filter: brightness(1.35); }
#realm .unit.drop-over { outline-width: 4px; }
[data-pile].drop-over b, #hand.drop-over { outline-width: 3px; }

/* Why the card snapped back, said beside it for a moment. */
.refusal {
    position: fixed;
    z-index: 61;
    max-width: 250px;
    padding: .35rem .55rem;
    border-radius: var(--radius);
    border: 1px solid var(--danger);
    background: var(--panel);
    color: var(--ink);
    font-size: .8rem;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .5);
    pointer-events: none;
    transition: opacity .5s ease;
}
.refusal.fading { opacity: 0; }

/* What a player would keep by hand: life lost, said over the board. */
.toasts {
    position: fixed;
    top: 3.2rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 59;
    display: flex;
    flex-direction: column;
    gap: .3rem;
    pointer-events: none;
}
.toast {
    padding: .35rem .7rem;
    border-radius: var(--radius);
    border: 1px solid var(--gold-dim);
    background: var(--panel);
    color: var(--ink);
    font-size: .85rem;
    box-shadow: 0 6px 18px rgba(0, 0, 0, .5);
    transition: opacity .5s ease;
}
.toast.fading { opacity: 0; }

/* At Death's Door, the life reads as the last of it. */
.vital.door b { color: var(--danger); }
@media (prefers-reduced-motion: no-preference) {
    .vital.door b { animation: door-pulse 1.4s ease-in-out infinite; }
    @keyframes door-pulse { 50% { opacity: .45; } }
}

/* The panel folded to its prompt while the cards answer: the list behind a
   button, the passes where they were. */
.decision.slim .options, .decision.slim .option-find { display: none; }
.decision .list-toggle {
    display: block;
    width: 100%;
    margin: .25rem 0 .35rem;
    padding: .25rem .5rem;
    font-size: .78rem;
    color: var(--ink-faint);
    background: none;
    border: 1px dashed var(--edge);
    border-radius: var(--radius);
    cursor: pointer;
}
.decision .list-toggle:hover { color: var(--ink); border-color: var(--gold-dim); }

/* A question that wants answering before the card can be played. */
@media (prefers-reduced-motion: no-preference) {
    .decision.attention { animation: attention 1.6s ease-in-out; }
    @keyframes attention {
        0%, 100% { box-shadow: 0 0 18px rgba(201, 162, 39, .12); }
        30%, 70% { box-shadow: 0 0 0 3px var(--gold), 0 0 24px rgba(201, 162, 39, .6); }
    }
}



/* The mode switch on the table's bar; the reminder's switch belongs to virtual mode. */
.bar-right .table-mode { font-size: .78rem; }

/* Q or E: a unit turned before it is slid, so the drop reads as its own move. */
#realm .unit.tap-intent, .drag-ghost.tap-intent { transform: rotate(18deg); outline: 2px dashed var(--gold); outline-offset: 1px; }
/* Where a carried unit might be put down, a guess: the engine says where once it is picked up. */
#realm .square.drop-maybe { border-color: var(--gold-dim); box-shadow: inset 0 0 0 1px var(--gold-dim); }

/* What the player did that the rules do not allow, and the choice: correct it, or play on by agreement. */
.agreement {
    position: fixed;
    left: 50%;
    top: 40%;
    transform: translate(-50%, -50%);
    z-index: 62;
    width: min(420px, calc(100vw - 32px));
    padding: .9rem 1rem;
    border-radius: var(--radius);
    border: 1px solid var(--gold);
    background: var(--panel);
    color: var(--ink);
    box-shadow: 0 12px 36px rgba(0, 0, 0, .6);
    display: flex;
    flex-direction: column;
    gap: .6rem;
}
.agreement-did { font-family: var(--display); font-size: 1rem; }
.agreement-why { color: var(--ink-faint); font-size: .85rem; }
.agreement-buttons { display: flex; gap: .5rem; justify-content: flex-end; flex-wrap: wrap; }
.agreement .play-on { border-color: var(--gold-dim); }
.top-box .top-name {
    width: 100%; box-sizing: border-box; font: inherit; padding: .4rem .5rem;
    background: var(--well, rgba(0, 0, 0, .3)); color: inherit; border: 1px solid var(--line, #445);
    border-radius: 4px;
}

/* An optional ability asked quietly: what is happening, and the pass. */
.decision.quiet .must { display: none; }

/* A question the table cannot answer, boxed over the board with its own buttons. */
.question-box { max-height: 80vh; overflow: auto; top: 45%; }
.question-box .options { display: flex; flex-direction: column; gap: .3rem; }

/* The piles on the table, in virtual mode: two card backs and the cemeteries. */
.piles { display: none; flex: 0 0 auto; align-self: center; gap: .5rem; align-items: flex-end; }
#table.virtual .piles { display: flex; }
.pile-chip {
    position: relative;
    width: 58px;
    height: 80px;
    border-radius: 4px;
    border: 1px solid var(--edge-bright);
    background-color: var(--panel-high);
    background-size: cover;
    background-position: center 20%;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    overflow: hidden;
    flex: 0 0 auto;
}
.pile-chip.laid { width: 80px; height: 58px; }
/* The real backs, from the publisher's press kit (the user, 20 October 2026), shrunk to the chip. */
.pile-chip.back {
    background-position: center;
    border-color: var(--gold-dim);
}
.pile-chip.back[data-pile="SPELLBOOK"] { background-image: url("spellbook-back.png"); }
.pile-chip.back[data-pile="ATLAS"] { background-image: url("atlas-back.png"); }
.pile-chip.cemetery.empty { border-style: dashed; cursor: default; opacity: .6; }
.pile-chip .pile-name {
    font-size: .6rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ink-faint);
    padding: 0 .25rem;
    background: rgba(10, 16, 18, .7);
}
.pile-chip .pile-count {
    font-size: .95rem;
    color: var(--ink);
    padding: 0 .25rem .15rem;
    background: rgba(10, 16, 18, .7);
}
.pile-chip.drop-ok { outline: 2px solid var(--good); outline-offset: 2px; }
.pile-chip.draggable { cursor: grab; }
@media (max-width: 767px) { .piles { display: none !important; } }

/* The d20: a round-cornered face beside the piles. */
.pile-chip.die { width: 58px; height: 58px; border-radius: 12px; border-color: var(--gold-dim); justify-content: center; align-items: center; }
.pile-chip.die .pile-count { font-size: 1.3rem; background: none; }
.pile-chip.die .pile-name { background: none; }

/* A deck's two ends: the halves of its back, shown only while a card is carried. */
.pile-zones { position: absolute; inset: 0; display: flex; flex-direction: column; }
.pile-zone {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity .15s ease;
}
.pile-zone.top { align-items: flex-start; }
.pile-zone.bottom { align-items: flex-end; }
.pile-zone-word {
    font-size: .55rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--gold);
    padding: .1rem .3rem;
    background: rgba(10, 16, 18, .75);
    border-radius: 2px;
}
body.dragging-card .pile-zone.drop-ok { opacity: 1; background: rgba(201, 162, 39, .12); box-shadow: inset 0 0 0 1px var(--gold-dim); }
.pile-zone.drop-over { background: rgba(201, 162, 39, .3) !important; box-shadow: inset 0 0 0 2px var(--gold) !important; }
.pile-chip .pile-name, .pile-chip .pile-count { position: relative; z-index: 1; pointer-events: none; }
/* The ends take the pointer only while a card is carried; otherwise the back itself is what is picked up or clicked. */
.pile-zone { pointer-events: none; }
body.dragging-card .pile-zone { pointer-events: auto; }

/* Life, mana and thresholds while the rails are away: a block in the
   margin at the left, under the Show rails button, off the board's height. */
.vitals-line { display: none; position: absolute; left: .6rem; top: 3.2rem; z-index: 3; flex-direction: column; gap: .9rem; width: 150px; pointer-events: none; }
#table.rails-hidden .vitals-line { display: flex; }
#table.rails-hidden .middle { position: relative; }
.vital-side { display: flex; flex-direction: column; gap: .2rem; color: var(--ink-faint); font-size: .85rem; }
.vital-side.turn .vital-name { color: var(--gold); }
.vital-name { color: var(--ink); font-family: var(--display); font-size: 1rem; }
.vital-numbers { display: flex; flex-wrap: wrap; gap: .2rem .7rem; }
.vital-bit b { color: var(--ink); font-size: 1.05rem; margin-left: .15rem; }
.vital-bit.door b { color: var(--danger); }
.vital-bit.clock b { font-variant-numeric: tabular-nums; }
.vital-bit.clock.low b { color: var(--danger); }
.vitals-line .thresholds { display: flex; gap: .3rem; }

/* A bot's announcement over the board while the rails are away. */
.announce-box { top: 28%; }
.announce-box .announced { margin: 0; }
.announce-box .announced-who { color: var(--gold); font-family: var(--display); }
.announce-box .announced-buttons { display: flex; gap: .5rem; justify-content: flex-end; margin-top: .6rem; }

/* Pause / Resume beside Show rails while the bar is away. */
.show-pause { position: fixed; z-index: 21; opacity: .78; top: .6rem; left: 7.2rem; }
.show-pause:hover, .show-pause:focus-visible { opacity: 1; }
/* Leave beside them, so the table can be left with the bar away (the user, 22 October 2026). */
.show-leave { position: fixed; z-index: 21; opacity: .78; top: .6rem; right: .6rem; }
.show-leave:hover, .show-leave:focus-visible { opacity: 1; }

/* The hand bar across the empty corner under the right column, when there is one. */
#table.hand-wide .hand-strip { width: calc(100% + var(--hand-extra, 0px)); position: relative; z-index: 2; }

.vital-hand { font-size: .8rem; color: var(--ink-faint); }
.vital-hand b { color: var(--ink); margin-left: .15rem; }

/* In virtual mode the hand is not marked up: no green on the cards that could be played (the user, 15 October 2026). */
#table.virtual .hand .card.answerable, #table.virtual .hand .card.next-spell.answerable { border-color: var(--edge); box-shadow: none; }

/* With the rails away the question floats beside the board: it may reach
   as high as the board does, and a bot's words and their buttons stack
   rather than squeeze beside each other (the user, 15 October 2026). */
#table.rails-hidden .flank.yours { max-height: calc(100vh - 2rem - var(--under-the-board, 1rem)); }
#table.rails-hidden .decision .announced { flex-direction: column; align-items: stretch; }
#table.rails-hidden .decision .announced-buttons { justify-content: flex-end; margin-top: .4rem; }

/* Anchored at the top of the margin beside the board, growing down toward the hand (the user, 15 October 2026). */
#table.rails-hidden .flank.yours { top: 1rem; bottom: auto; max-height: calc(100vh - 1rem - var(--under-the-board, 1rem)); }

/* The Mortuary's switch, by the piles. */
.pile-note { align-self: center; max-width: 150px; font-size: .66rem; line-height: 1.25; color: var(--gold-dim); }

.decision .search-note { font-size: .78rem; color: var(--gold-dim); margin: -.2rem 0 .4rem; }

/* Round 44 (the user, 21 October 2026): history filters, ratings and the server's days. */
.history-filters { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; align-items: end; margin: 0 0 0.6rem; }
.history-filters label { display: flex; flex-direction: column; gap: 0.15rem; font-size: 0.85em; }
.rating-up { color: #3a8a3a; }
.rating-down { color: #b0413e; }
.stats-rating { margin: 0.4rem 0 0.8rem; font-size: 1.05em; }
.stats-rating b { font-size: 1.3em; }
.day-bars { display: grid; grid-template-columns: auto 1fr auto; gap: 0.2rem 0.6rem; align-items: center; max-width: 36rem; margin: 0.4rem 0 1rem; font-size: 0.85em; }
.day-bars .bar { height: 0.8em; background: #4a7fb5; border-radius: 2px; min-width: 1px; }
.day-bars .bar.players { background: #8a5a9f; }
.league-to-play { margin: 0.4rem 0; }

/* The builder's cost range, keyword chips, legality line and list dialog (the user, 22 October 2026). */
.cost-range { display: inline-flex; align-items: center; gap: 0.2rem; font-size: 0.85em; }
.cost-range input { width: 3.2rem; }
#keyword-chips:empty { display: none; }
.deck-format-check { display: inline-flex; align-items: center; gap: 0.4rem; font-size: 0.85em; }
.deck-legal.legal { color: #3a8a3a; }
.deck-legal.illegal { color: #b0413e; cursor: help; }
.list-dialog textarea { width: 100%; min-width: 28rem; font-family: ui-monospace, Menlo, monospace; font-size: 0.85em; }
.people .show-hand { display: block; margin: 0.4rem 0 0.2rem; font-size: 0.9em; }
.watching-count { font-size: 0.8em; margin-top: 0.2rem; }

/* Challenges and friends (the user, 22 October 2026). */
.present .friends-heading { margin-top: 0.8rem; }
.present .person-buttons { float: right; display: inline-flex; gap: 0.3rem; }
.present .person-buttons button { font-size: 0.75em; padding: 0 0.4rem; }
.present .star.on { color: #d9a93a; }
.present li.offline { opacity: 0.55; }
.challenge-toast { position: fixed; right: 1rem; bottom: 1rem; z-index: 50; background: var(--panel, #1c1c1c); border: 1px solid #555; border-radius: 6px; padding: 0.8rem 1rem; max-width: 22rem; box-shadow: 0 4px 16px rgba(0,0,0,0.5); }
.challenge-toast p { margin: 0 0 0.5rem; }
#report-dialog textarea { width: 100%; min-width: 24rem; }
.people .mute { font-size: 0.75em; padding: 0 0.4rem; margin-left: 0.4rem; }
.people .mute.on { color: #b0413e; }

/* The changelog and its badge (the user, 22 October 2026). */
.badge { display: inline-block; font-size: 0.65em; padding: 0 0.4em; margin-left: 0.3em; border-radius: 0.6em; background: #b0413e; color: #fff; vertical-align: middle; }
.changelog-entry { margin: 0 0 1rem; }
.changelog-entry h3 { margin: 0 0 0.2rem; }
.changelog-entry h3 .tally { font-weight: normal; margin-left: 0.5rem; }
.changelog-entry.new h3::after { content: " new"; font-size: 0.7em; color: #b0413e; }
.changelog-entry ul { margin: 0.2rem 0 0.3rem 1.2rem; }
.changelog-entry details { font-size: 0.9em; }
.changelog-entry details pre { white-space: pre-wrap; font-family: inherit; margin: 0.3rem 0 0; }

/* The tour (the user, 22 October 2026): a hole in a dimmed page, and a callout beside it. */
.tour { position: fixed; inset: 0; z-index: 90; }
.tour-hole { position: absolute; border-radius: 6px; box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.62); pointer-events: none; transition: all 0.25s ease; outline: 2px solid var(--gold, #d9a93a); }
.tour-hole.nothing { outline: none; width: 0; height: 0; }
.tour-callout { position: absolute; max-width: 22rem; background: var(--panel, #1c1c1c); color: inherit; border: 1px solid #666; border-radius: 8px; padding: 0.8rem 1rem; box-shadow: 0 6px 24px rgba(0,0,0,0.6); }
.tour-callout h3 { margin: 0 0 0.4rem; }
.tour-callout p { margin: 0 0 0.6rem; line-height: 1.4; }
.tour-buttons { display: flex; gap: 0.5rem; align-items: center; }
.tour-buttons { flex-wrap: wrap; justify-content: flex-end; }
.tour-buttons button { white-space: nowrap; }
.tour-buttons #tour-where { flex: 1 1 100%; order: -1; font-size: 0.8em; }
.tour-note { position: fixed; left: 50%; bottom: 1.2rem; transform: translateX(-50%); z-index: 95; background: var(--panel, #1c1c1c); border: 1px solid var(--gold, #d9a93a); border-radius: 6px; padding: 0.6rem 1rem; box-shadow: 0 4px 16px rgba(0,0,0,0.5); }
@media (max-width: 767px) {
  .tour-hole { display: none; }
  .tour { background: rgba(0, 0, 0, 0.55); }
  .tour-callout { left: 0.6rem !important; right: 0.6rem; bottom: 0.6rem; top: auto !important; max-width: none; }
}
/* Getting started */
.getting-started li { display: flex; align-items: center; gap: 0.5rem; }
.getting-started li.done { opacity: 0.6; text-decoration: line-through; }
.getting-started .tick { width: 1.2em; display: inline-block; text-align: center; }
.getting-started li button.linkish { margin-left: auto; font-size: 0.8em; }

/* Cards only shown -- a hand a Lookout looks at -- are read, not picked; Done viewing moves on. */
.options.viewing .option { cursor: default; }
.option.done-viewing { margin-top: .4rem; width: 100%; font-weight: 600; }

/* A way to choose, drawn on the board: an arrow in the square the way starts
   from, pointing at the square it steps to, clicked to take it. */
.heading-arrow {
    position: absolute;
    z-index: 6;
    width: 2.2rem;
    height: 2.2rem;
    padding: 0;
    border: 2px solid var(--ground-deep);
    border-radius: 50%;
    background: var(--gold);
    color: var(--ground-deep);
    font-size: 1.25rem;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transform: translate(-50%, -50%) rotate(var(--turn, 0rad));
    box-shadow: 0 2px 8px rgba(0, 0, 0, .55);
}
.heading-arrow:hover, .heading-arrow:focus-visible {
    background: var(--ink);
    outline: 2px solid var(--gold);
    outline-offset: 2px;
}
