/* ============================================================
   The theme.

   One dark ground rather than a light and dark pair. The app commits to a
   look — a lit table in a dark room — and the guides keep their measured
   column on the same ground rather than flipping the whole app to paper for
   the one screen that reads like a page.

   Colour carries meaning, and only one meaning each:

     gold    yours, chosen, on the clock
     blood   harm, danger, a refusal
     moss    healing, whole
     arcane  a spell
     steel   a stance or a guard

   A colour is never the only signal. Every state that a colour marks also
   carries a shape, a word or a number — a player who cannot see the
   difference between gold and grey still reads the screen.
   ============================================================ */

:root {
    color-scheme: dark;

    --ground: #0b0c10;
    --panel: #121419;
    --sunken: #0e1015;
    --raised: #191c23;
    --lifted: #1d2029;

    --line-soft: #22262f;
    --line: #2c313c;
    --line-strong: #3a4150;

    --fg: #eae3d2;
    --muted: #9aa0ae;
    --dim: #838b9b;
    --faint: #6f7686;

    --gold: #d8a657;
    --gold-soft: #ebc07c;
    --gold-dim: #6e5526;
    --gold-wash: #241f17;
    --on-gold: #14161b;

    --blood: #c0453f;
    --blood-fg: #e0665c;
    --blood-dim: #6c2f2c;
    --blood-wash: #1a1315;

    --moss: #86b06c;
    --moss-dim: #3f5235;
    --moss-wash: #121611;

    --arcane: #9b92e0;
    --steel: #7e93b8;

    --radius-chip: 4px;
    --radius-control: 6px;
    --radius-panel: 10px;

    /* The smallest a control is ever drawn. Everything a player presses
       during a fight is at least this tall. */
    --tap: 44px;

    --display: "Cinzel", Georgia, serif;
    --ui: "Alegreya Sans", "Segoe UI", system-ui, sans-serif;
    --prose: "Alegreya", Georgia, serif;

    /* The old names, kept as aliases rather than renamed away. Every rule in
       here that meant "the accent" still means it, and a screen this pass has
       not reached is re-themed by the alias instead of by an edit. */
    --bg: var(--ground);
    --border: var(--line);
    --accent: var(--gold);
    --error: var(--blood-fg);
}

* {
    box-sizing: border-box;
}

html {
    background: var(--ground);
}

body {
    margin: 0;
    min-height: 100vh;
    font-family: var(--ui);
    font-size: 15px;
    line-height: 1.45;
    color: var(--fg);
    background: var(--ground);
}

h1,
h2,
h3,
h4,
h5 {
    font-family: var(--display);
    font-weight: 600;
    letter-spacing: 0.01em;
}

h1 {
    font-size: 1.6rem;
    margin: 0 0 1rem;
}

h2 {
    font-size: 1.2rem;
}

a {
    color: var(--gold);
    text-decoration: none;
}

a:hover {
    color: var(--gold-soft);
}

/* ---------- Controls ----------

   Four tiers, and the default is the second of them. A screen full of filled
   buttons says every control is the point of the screen; one primary per
   panel says which one is. */

input,
select,
textarea,
button {
    font: inherit;
}

button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    min-height: var(--tap);
    padding: 0 1.15rem;
    background: var(--raised);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-control);
    color: var(--fg);
    cursor: pointer;
}

button:hover:not(:disabled) {
    background: var(--lifted);
    border-color: var(--gold-dim);
}

/* The thing the panel is for. */
button.primary {
    background: var(--gold);
    border-color: var(--gold);
    color: var(--on-gold);
    font-weight: 700;
    letter-spacing: 0.02em;
}

button.primary:hover:not(:disabled) {
    background: var(--gold-soft);
    border-color: var(--gold-soft);
}

/* The lesser of two controls sitting side by side: leaving without making
   anything reads as a way out, not as a second thing to press. */
button.secondary,
button.ghost {
    background: transparent;
    border-color: transparent;
    color: var(--muted);
}

button.secondary:hover:not(:disabled),
button.ghost:hover:not(:disabled) {
    background: var(--raised);
    border-color: var(--line);
    color: var(--fg);
}

button.danger {
    background: transparent;
    border-color: var(--blood-dim);
    color: var(--blood-fg);
}

button.danger:hover:not(:disabled) {
    background: var(--blood);
    border-color: var(--blood);
    color: #fff;
}

/* The press that actually does it, once the question has been asked. Filled,
   because at that point it is the primary of the two — and the way out
   beside it has dropped to a ghost. */
button.danger.filled {
    background: var(--blood);
    border-color: var(--blood);
    color: #fff;
    font-weight: 700;
}

/* A control that cannot be pressed keeps its label legible. The old rule
   dropped it to 45% opacity, which said "broken" rather than "refused" — and
   the reason a thing is refused is printed beside it everywhere in this app,
   so the label is the half a player still has to read. */
button:disabled {
    background: var(--lifted);
    border-color: var(--line);
    color: var(--faint);
    cursor: not-allowed;
}

/* Focus is a gold ring, never a removed outline. Two shadows so the ring
   stands clear of whatever surface the control sits on. */
:focus-visible {
    outline: none;
    box-shadow:
        0 0 0 2px var(--ground),
        0 0 0 4px var(--gold);
}

input,
select,
textarea {
    min-height: var(--tap);
    padding: 0 0.75rem;
    background: var(--sunken);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-control);
    color: var(--fg);
}

input[type="number"] {
    width: 5rem;
    font-variant-numeric: tabular-nums;
}

form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.5rem;
    margin-bottom: 1.5rem;
}

label {
    color: var(--muted);
}

/* ---------- The shell ---------- */

.top-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1.5rem;
    min-height: 64px;
    padding: 0 1.25rem;
    background: var(--panel);
    border-bottom: 1px solid var(--line);
}

.brand {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    font-family: var(--display);
    font-size: 0.95rem;
    font-weight: 600;
    letter-spacing: 0.2em;
    color: var(--fg);
}

.brand svg {
    flex: none;
}

/* The tabs are the app's navigation, so the current one has to read as
   *where you are* rather than as a control that has stopped working. It used
   to be a `disabled` button: out of the tab order, and announced as dimmed. */
.tabs {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 2px;
}

.tabs button {
    height: var(--tap);
    padding: 0 1rem;
    background: transparent;
    border-color: transparent;
    color: var(--muted);
    font-size: 0.92rem;
    letter-spacing: 0.04em;
}

.tabs button:hover {
    background: var(--raised);
    border-color: transparent;
    color: var(--fg);
}

.tabs button[aria-current="page"] {
    background: var(--lifted);
    box-shadow: inset 0 -2px 0 0 var(--gold);
    color: var(--gold-soft);
    cursor: default;
}

.account {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 0 auto;
    color: var(--dim);
    font-size: 0.85rem;
}

.page {
    padding: 1.5rem 1.25rem 3rem;
}

/* Most screens are a single readable column. The world is the exception —
   it is a map and the place it puts you in, side by side. */
.page > * {
    max-width: 46rem;
    margin-inline: auto;
}

.page > .world {
    max-width: none;
}

/* ---------- Surfaces ---------- */

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

.panel-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-bottom: 0.75rem;
}

.eyebrow {
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--dim);
}

.panel-note {
    margin-left: auto;
    color: var(--muted);
    font-size: 0.8rem;
}

ul {
    list-style: none;
    padding: 0;
    margin: 0 0 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

li {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 0.7rem 0.9rem;
}

li li {
    margin-top: 0.5rem;
    background: var(--raised);
}

.page > ul {
    margin-inline: auto;
}

.error {
    border-left: 3px solid var(--blood);
    background: var(--blood-wash);
    border-radius: 0 var(--radius-control) var(--radius-control) 0;
    padding: 0.6rem 0.8rem;
    color: var(--blood-fg);
    font-size: 0.9rem;
}

.hint {
    color: var(--muted);
    font-size: 0.88rem;
}

.attributes {
    color: var(--muted);
    font-size: 0.85rem;
    margin: 0.4rem 0;
}

.attribute-roll {
    flex-basis: 100%;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.attribute-total {
    color: var(--muted);
    font-size: 0.85rem;
    margin: 0;
}

.attribute-inputs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.attribute-inputs label {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.7rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--dim);
}

.attribute-inputs input[type="number"] {
    width: 4rem;
    text-align: center;
}

/* Already the one being played. Disabled says "there is nothing to press
   here", and the gold says which one it is — the pair is the whole state. */
button.playing.selected:disabled {
    background: var(--gold);
    border-color: var(--gold);
    color: var(--on-gold);
    font-weight: 700;
}

/* A row of controls that act on the page rather than on any one row of it. */
.page-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 auto 1.5rem;
}

/* ---------- Health, and the marks a body carries ---------- */

.bar {
    display: block;
    width: 8rem;
    max-width: 100%;
    height: 5px;
    border-radius: 3px;
    background: var(--line);
    overflow: hidden;
}

.bar > i {
    display: block;
    height: 100%;
    background: var(--moss);
}

/* Half health or less. The colour is the second signal — the number beside
   it is the first, and it is always there. */
.bar.hurt > i {
    background: var(--blood);
}

.hp {
    color: var(--muted);
    font-size: 0.8rem;
    font-variant-numeric: tabular-nums;
}

.health {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
}

/* Harm is red-bordered, help is green, and a modifier that harms what it
   names stays grey with a signed number. The sign does the work, not the
   colour alone. */
.chip {
    height: 20px;
    padding: 0 0.45rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-chip);
    color: var(--muted);
    font-size: 0.68rem;
    line-height: 18px;
    white-space: nowrap;
}

.chip.harm {
    border-color: var(--blood-dim);
    color: var(--blood-fg);
}

.chip.help {
    border-color: var(--moss-dim);
    color: var(--moss);
}

/* ---------- Combat ----------

   The turn is the unit a player thinks in, so the controls and the log both
   have to make its edges visible. */

.combat-state {
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

/* Whose turn it is, what is left of it, and the one control that ends it.
   Gold along the top edge: this panel is the clock. */
.combat-head {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 1rem;
    border-top: 2px solid var(--gold);
}

.combat-head .whose-turn {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.combat-head .whose-turn strong {
    font-family: var(--display);
    font-size: 1.15rem;
    font-weight: 600;
}

.combat-head .budget {
    margin-left: auto;
    align-items: flex-end;
}

.combat-head .end-turn {
    margin: 0;
}

.budget {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    margin: 0;
    color: var(--muted);
    font-size: 0.85rem;
}

.budget .spent-so-far {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

.budget .penalty {
    color: var(--blood-fg);
    font-size: 0.8rem;
}

.pips {
    display: inline-flex;
    gap: 0.25rem;
}

.pip {
    width: 0.65rem;
    height: 0.65rem;
    border-radius: 50%;
    background: var(--gold);
    display: inline-block;
}

.pip.spent {
    background: none;
    border: 1px solid var(--line-strong);
}

/* The battlefield: who is standing where, what they have left, and what is
   riding on them — one panel rather than a roster above a row of bands.
   Where the fight sits and how it is going are the same glance. */
.band-strip {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: 0.6rem;
}

.band-strip .band {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    padding: 0.6rem;
    background: var(--sunken);
    border: 1px solid var(--line-soft);
    border-radius: 8px;
}

/* The band whoever is on the clock is standing in. Worth marking for the
   reason the map marks *here*: every question about reach is asked from it. */
.band-strip .band.here {
    border-color: var(--gold-dim);
    box-shadow: inset 0 0 0 1px var(--gold-dim);
}

.band-strip .band.here > .eyebrow {
    color: var(--gold);
}

.band-strip .empty-band {
    padding: 0.9rem 0;
    text-align: center;
    color: var(--faint);
    font-size: 0.8rem;
    font-style: italic;
}

.fighter {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 0.4rem 0.55rem;
    background: var(--raised);
    border-left: 3px solid var(--line-strong);
    border-radius: var(--radius-chip);
}

.fighter.side-party {
    border-left-color: var(--gold);
}

.fighter.side-opposition {
    border-left-color: var(--blood);
}

/* Down, and still on the field: a body beside somebody upright is a legal
   fight, and the only one a resurrection has anybody to raise in. */
.fighter.fallen {
    opacity: 0.6;
}

.fighter-name {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    font-size: 0.85rem;
    font-weight: 500;
}

.on-clock {
    height: 16px;
    padding: 0 0.4rem;
    border-radius: 3px;
    background: var(--gold);
    color: var(--on-gold);
    font-size: 0.62rem;
    line-height: 16px;
    font-weight: 700;
    letter-spacing: 0.06em;
}

.fighter .health {
    gap: 0.4rem;
}

.fighter .bar {
    width: 5.5rem;
    height: 4px;
}

.fighter .defense {
    color: var(--dim);
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
}

/* An action is a card, not a word on a pill: the name, what it costs, and
   one line of what it does or why it is refused. The old row of one-word
   buttons made the cost a parenthesis and the reason a tooltip, and a
   tooltip is not there on a touch screen at all. */
.action-buttons {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 0.6rem;
    margin: 0;
}

.action-buttons .action {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 0.3rem;
    min-height: 4.4rem;
    padding: 0.5rem 0.7rem;
    text-align: left;
    background: var(--raised);
    border: 1px solid var(--line-strong);
    border-left-width: 3px;
    border-radius: 8px;
    color: var(--fg);
}

.action .action-head {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    width: 100%;
}

.action .action-name {
    font-size: 0.95rem;
    font-weight: 600;
}

/* What the action *is*, when that is not the same as what it does: the free
   attack, a stance, a bottle and how many are left. */
.action .tag {
    height: 15px;
    padding: 0 0.3rem;
    border: 1px solid var(--line-strong);
    border-radius: 3px;
    color: var(--muted);
    font-size: 0.62rem;
    line-height: 13px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* What it costs, in the same pips the turn budget is counted in — so
   "two of the three I have" is one comparison rather than two readings. */
.action .cost {
    display: inline-flex;
    gap: 3px;
    margin-left: auto;
}

.action .cost i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--gold);
    display: block;
}

.action .cost i.unaffordable {
    background: none;
    border: 1px solid var(--line-strong);
}

/* The line that carries the reason. Every card has one, whether it is open
   or refused — a control that is merely unpressable reads as a bug. */
.action .why {
    color: var(--muted);
    font-size: 0.78rem;
    line-height: 1.35;
}

.action.selected {
    background: var(--gold-wash);
    border-color: var(--gold);
    color: var(--gold-soft);
    box-shadow: 0 0 0 1px var(--gold-dim);
}

.action.selected .why {
    color: var(--gold-soft);
}

.action:disabled {
    background: #14161b;
    border-color: var(--line);
    color: var(--dim);
}

.action:disabled .cost i {
    background: var(--line-strong);
}

/* Locked out by an augment's cooldown — the one state whose end is a number,
   so the card says both that it cannot be pressed and when it can be. */
.action.cooling {
    border-style: dotted;
}

.action.cooling .why,
.action.cooling .cooldown {
    color: var(--blood-fg);
}

.action .cooldown {
    margin-left: auto;
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}

/* The rail says what kind of action it is. It is never the only signal —
   the card's own line says what the action does in words. */
.action.basic {
    border-left-color: var(--dim);
}

.action.rail-attack {
    border-left-color: var(--blood);
}

.action.rail-spell {
    border-left-color: var(--arcane);
}

.action.rail-aid {
    border-left-color: var(--moss);
}

.action.rail-stance {
    border-left-color: var(--steel);
}

/* Footwork reads as a different kind of action from a swing: it spends the
   same budget and changes nothing about anybody's health. */
.action.walk {
    background: var(--sunken);
    border-style: dashed;
    border-left-color: var(--gold-soft);
    color: var(--gold-soft);
}

.action-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    margin-top: 0.75rem;
    padding-top: 0.7rem;
    border-top: 1px dashed var(--line);
    color: var(--muted);
    font-size: 0.72rem;
}

.action-legend span {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

.action-legend i {
    width: 3px;
    height: 14px;
    display: block;
    background: var(--line-strong);
}

.action-legend i.basic {
    background: var(--dim);
}

.action-legend i.rail-attack {
    background: var(--blood);
}

.action-legend i.rail-spell {
    background: var(--arcane);
}

.action-legend i.rail-aid {
    background: var(--moss);
}

.action-legend i.rail-stance {
    background: var(--steel);
}

.action-legend i.walk {
    background: none;
    border-left: 3px dashed var(--gold-soft);
}

/* Where the chosen action lands. A set you choose from stays a row of
   buttons: the choice reads back at the player instead of hiding inside a
   closed control. */
.targets {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.8rem;
    padding-top: 0.8rem;
    border-top: 1px dashed var(--line);
}

.targets > span:first-child {
    color: var(--gold-soft);
    font-size: 0.88rem;
}

.targets button {
    display: inline-flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0.1rem;
    min-height: 36px;
    padding: 0.25rem 0.8rem;
    background: var(--sunken);
    font-size: 0.85rem;
    text-align: left;
}

.targets button small {
    color: var(--dim);
}

/* The fight's reason, on the row. Same rule as the action card's own line:
   a control that is merely unpressable reads as a bug, and a `title` reaches
   neither a touch screen nor a keyboard. */
.targets button .why {
    color: var(--muted);
    font-size: 0.78rem;
    line-height: 1.3;
    white-space: normal;
}

/* A band your own side is standing in. The blast catches them too, so the
   button has to say so before the action is spent rather than after — this
   is the placement decision, not a mistake to be undone. */
.targets.zones .friendly-fire {
    border-color: var(--blood);
    color: var(--blood-fg);
}

/* An enemy nobody can reach still has to be visible — knowing something is
   out there and needs closing on is the whole point of the ground. */
.targets button.unreachable {
    border-style: dashed;
    color: var(--faint);
    cursor: not-allowed;
}

/* Leaving a fight is not one of its actions — no cost, outside the initiative
   order — so it does not sit in the action row, and it is not a panel of its
   own either: a bordered box around one destructive button gives it the
   weight of a decision the screen is asking for. */
.forfeit {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    padding: 0 0.2rem;
}

.forfeit .hint {
    margin: 0;
}

.log-panel .combat-log {
    margin: 0;
    gap: 0.3rem;
    max-height: 22rem;
    overflow-y: auto;
}

.combat-log li {
    background: var(--raised);
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-control);
    padding: 0.4rem 0.7rem;
    font-size: 0.88rem;
}

/* A rule between one turn and the next. The log reads newest-first, so this
   sits above the exchange it closed. */
.combat-log .turn-break {
    background: none;
    border: 0;
    border-top: 2px solid var(--gold);
    border-radius: 0;
    margin-top: 0.5rem;
    padding: 0.35rem 0 0.25rem;
    color: var(--gold);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

/* An effect an action left on a body it struck. Indented under the blow that
   left it — the log reads newest-first, so a rider is pushed ahead of its
   blow and lands directly beneath it. */
.combat-log .rider {
    margin-left: 1.5rem;
    background: none;
    border: 0;
    border-left: 2px solid var(--line-strong);
    border-radius: 0;
    color: var(--muted);
    font-size: 0.82rem;
}

/* The band count is picked with buttons rather than a menu: how much ground
   a fight covers is one glance, and every option is worth seeing at once. */
.bands {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-right: 0.4rem;
}

.bands .band {
    min-width: 2.5rem;
    padding: 0 0.6rem;
}

.bands .band.selected,
.party .member.selected,
.travellers .member.selected {
    background: var(--gold);
    border-color: var(--gold);
    color: var(--on-gold);
    font-weight: 700;
}

/* The party is picked with toggles rather than a menu, for the same reason
   the map is: a party is a set, and a row of buttons reads the selection
   back at the player where a multi-select only reads it back to itself. */
.party,
.travellers {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
}

.party .member,
.travellers .member {
    gap: 0.5rem;
    padding: 0 0.85rem;
}

/* A character's initial, in the display face — the one ornament in the app,
   and it is doing a job: it makes a name findable in a row of them. */
.sigil {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    flex: none;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    color: var(--muted);
    font-family: var(--display);
    font-size: 0.7rem;
}

.member.selected .sigil {
    background: var(--on-gold);
    border-color: var(--on-gold);
    color: var(--gold);
}

/* ---------- The travel screen ---------- */

.world {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* Where you are and what is happening to you, on one line above the split.
   It is persistent: the character and their health stay put while the stage
   below changes. */
.context-strip {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
    padding: 0.5rem 0.9rem;
    background: var(--sunken);
    border: 1px solid var(--line-soft);
    border-radius: var(--radius-panel);
}

/* The place itself is **not** repeated here. The stage's own card names it
   in the display face directly below, and saying it twice in two sizes reads
   as two different facts. What the strip owes is the pair the card cannot
   give: what the world is doing to you, and what is left of you. */
.context-strip .health {
    margin-left: auto;
}

.status-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    height: 26px;
    padding: 0 0.7rem;
    border: 1px solid var(--moss-dim);
    border-radius: 999px;
    background: var(--moss-wash);
    color: var(--moss);
    font-size: 0.8rem;
    letter-spacing: 0.04em;
}

.status-pill i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    display: block;
}

.status-pill.fighting {
    border-color: var(--blood-dim);
    background: var(--blood-wash);
    color: var(--blood-fg);
}

/* Who is walking, on its own slim row above the split — outside it, because
   picking somebody is what opens the split at all. */
.party-panel {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.75rem;
    padding: 0.5rem 0.9rem;
}

.world-split {
    display: grid;
    grid-template-columns: 25rem 1fr;
    gap: 1rem;
    align-items: start;
}

@media (max-width: 62rem) {
    .world-split {
        grid-template-columns: 1fr;
    }
}

.world-map {
    display: flex;
    flex-direction: column;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius-panel);
    overflow: hidden;
}

.world-map .realm {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--line-soft);
    font-family: var(--display);
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.world-map .charted {
    margin-left: auto;
    color: var(--dim);
    font-size: 0.7rem;
    letter-spacing: 0;
    text-transform: none;
}

.map-frame {
    padding: 0.6rem 0.75rem 0;
}

/* Travel is refused while a fight lasts — `AreaRefusal::InCombat`. The map
   stays on screen dimmed rather than disappearing, because where the fight
   sits is still worth seeing, and the refusal is printed underneath it
   rather than left to be inferred from a map that has quietly gone dead. */
.world-map.locked .map-frame {
    opacity: 0.45;
}

.world-map .refusal {
    margin: 0 1rem 0.9rem;
}

.map-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 0.9rem;
    margin-top: auto;
    padding: 0.7rem 1rem;
    border-top: 1px solid var(--line-soft);
    color: var(--muted);
    font-size: 0.7rem;
}

.map-legend span {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.map-legend i {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    display: block;
}

.map-legend i.here {
    background: var(--gold);
}

.map-legend i.can-go {
    border: 2px dashed var(--gold);
}

.map-legend i.visited {
    border: 2px solid var(--dim);
}

.map-legend i.cleared {
    background: var(--line-strong);
}

.world-stage {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    min-width: 0;
}

/* Where you are standing, said once and properly: the region above it, the
   place in the display face, and the world's own refusals under it. */
.place-card {
    border-top: 2px solid var(--gold);
}

.place-card .region {
    margin: 0 0 0.35rem;
}

.place-card h2 {
    margin: 0;
    font-size: 1.5rem;
}

.world .region {
    font-size: 0.7rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--dim);
}

/* The refusal is prose, not a disabled control: `docs/adr/0021` says a
   refused offer still crosses, and a node that is merely unclickable does
   not say why. */
.refusal {
    margin: 0.6rem 0 0;
    border-left: 3px solid var(--blood);
    background: var(--blood-wash);
    border-radius: 0 var(--radius-control) var(--radius-control) 0;
    padding: 0.55rem 0.75rem;
    color: var(--blood-fg);
    font-size: 0.88rem;
}

/* Nothing is happening, and saying so is better than an empty column that
   reads as something that failed to load. */
.no-fight {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    min-height: 8rem;
    padding: 1.5rem;
    background: var(--sunken);
    border: 1px dashed var(--line-soft);
    border-radius: var(--radius-panel);
    color: var(--dim);
    text-align: center;
}

.no-fight small {
    color: var(--faint);
}

.map {
    display: block;
    width: 100%;
    height: auto;
}

.map .edge {
    stroke: var(--line);
    stroke-width: 2;
}

/* One-way, derived from the resolved exits rather than read off the file. */
.map .edge.one-way {
    stroke-dasharray: 4 3;
}

/* What a place *is* — unknown, visited, cleared, here. Whether it is
   *offered* is the dashed ring below, and drawing the two as one fact made a
   place stop looking walkable the moment it was first arrived at. */
.map .node {
    fill: var(--panel);
    stroke: var(--line);
    stroke-width: 2;
}

.map .node.visited {
    stroke: var(--dim);
}

.map .node.cleared {
    fill: var(--line-strong);
    stroke: var(--line-strong);
}

.map .node.here {
    fill: var(--gold);
    stroke: var(--gold);
}

.map .node.can-go {
    stroke: var(--gold);
    stroke-dasharray: 3 2;
}

.map .place text {
    fill: var(--fg);
    font-size: 9px;
    font-family: var(--ui);
}

.map .place text.unknown {
    fill: var(--dim);
    font-style: italic;
}

/* A node the player travels by is a control, not a picture. */
.map .place.live {
    cursor: pointer;
}

.map .place.live:focus {
    outline: none;
    box-shadow: none;
}

.map .place.live:focus circle.node {
    stroke: var(--gold-soft);
    stroke-width: 4;
}

.map .place.live:hover circle.node {
    filter: brightness(1.2);
}

/* Rest lands on your own node, from the same offer list travel comes from. */
.map .rest-ring {
    fill: none;
    stroke: var(--moss);
    stroke-width: 1;
    stroke-dasharray: 2 3;
}

.map text.rest-label {
    fill: var(--moss);
    font-size: 8px;
    letter-spacing: 0.06em;
}

/* A dash says a passage is one-way; the head says which way. With the map as
   the only travel control, that is the difference between somewhere you may
   go and somewhere you came from. */
.map .edge-head {
    fill: var(--line-strong);
}

/* ---------- The character sheet ---------- */

/* The button that opens the sheet, in the persistent strip. The badge is the
   one number on it — what is waiting inside. */
.sheet-open {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.sheet-open .badge,
.sheet-tabs .dot {
    background: var(--blood);
    color: #fff;
    border-radius: 999px;
}

.sheet-open .badge {
    min-width: 1.15rem;
    padding: 0 0.3rem;
    font-size: 0.75rem;
    line-height: 1.15rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.sheet-tabs .dot {
    display: inline-block;
    width: 0.45rem;
    height: 0.45rem;
    margin-left: 0.35rem;
    vertical-align: middle;
}

/* Drawn over the map rather than in place of it, so the fight, the map and
   the picked character stay exactly where they were. */
.character-sheet {
    width: min(62rem, 92vw);
    max-height: 88vh;
    overflow-y: auto;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-panel);
    padding: 1rem 1.25rem;
    background: var(--panel);
    color: var(--fg);
}

.character-sheet::backdrop {
    background: rgb(0 0 0 / 65%);
}

.sheet-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    border-bottom: 1px solid var(--line);
    padding-bottom: 0.6rem;
    margin-bottom: 0.75rem;
}

.sheet-head h2 {
    margin: 0;
}

/* A segmented control rather than four loose buttons: these are views of one
   character, and the group has to read as one thing. */
.sheet-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 2px;
    padding: 3px;
    background: var(--sunken);
    border: 1px solid var(--line-soft);
    border-radius: 8px;
}

.sheet-tabs button {
    min-height: 36px;
    padding: 0 0.85rem;
    background: transparent;
    border-color: transparent;
    color: var(--muted);
    font-size: 0.88rem;
}

.sheet-tabs button:disabled {
    background: var(--lifted);
    border-color: var(--line-strong);
    color: var(--gold-soft);
}

/* Items and consumables side by side: two lists on one pane, neither big
   enough to own a tab. */
.sheet-inventory {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
}

.sheet-inventory > section {
    flex: 1 1 18rem;
}

/* ---------- Talents ---------- */

.talents .branch-list li {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    flex-wrap: wrap;
}

.talents .branch-name,
.talents .talent-name {
    font-weight: 600;
}

.talents .branch-detail,
.talents .talent-detail {
    color: var(--muted);
    font-size: 0.9em;
    flex: 1;
}

/* Why a greyed control is greyed, printed beside it rather than hung in a
   `title`. */
.talents .why {
    color: var(--muted);
    font-size: 0.8em;
    line-height: 1.35;
}

/* In the two rows that lay their controls out sideways, the reason takes the
   whole line, so it never competes for width with the button it belongs to.
   The augment card already stacks, so it needs nothing. */
.talents .branch-list .why,
.talents .talent-actions .why {
    flex-basis: 100%;
}

/* Something already bought reads as owned rather than on offer. */
.talents .talent-row.owned .talent-name::before,
.talents .talent-heading.owned .talent-name::before {
    content: "✓ ";
    color: var(--gold);
}

/* Buy and sell sit together: they are the same decision read in two
   directions, and a sale is only ever one rank of what the button beside it
   bought. */
.talents .talent-actions {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-bottom: 0.6rem;
}

/* Master/detail: the column answers "where is a decision waiting" and the
   pane answers "what is the decision". The column is the half that decided
   the shape, so it keeps its width on a narrow screen and the pane reflows. */
.talents .talent-split {
    display: grid;
    grid-template-columns: minmax(10rem, 13rem) 1fr;
    gap: 1rem;
    align-items: start;
    margin-bottom: 1.5rem;
}

@media (max-width: 34rem) {
    .talents .talent-split {
        grid-template-columns: 1fr;
    }
}

.talents .talent-nav {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

/* A nav row is a control, not a chip: it carries two lines and reads left,
   so the button defaults would make it a centred pill. */
.talents .talent-row {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 0.1rem;
    text-align: left;
    padding: 0.45rem 0.6rem;
    background: var(--raised);
    color: var(--fg);
    border: 1px solid var(--line);
}

.talents .talent-row.showing {
    border-color: var(--gold);
    background: var(--gold-wash);
}

.talents .talent-row .talent-detail {
    font-size: 0.8em;
    flex: none;
}

/* The whole point of the column: something to spend is legible without
   opening the row. A mark rather than a colour alone, since a colour is the
   one thing a player may not be able to see. */
.talents .talent-row.waiting .talent-detail::after {
    content: " ●";
    color: var(--gold);
}

.talents .talent-heading {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    flex-wrap: wrap;
}

.talents .hint {
    margin: 0.4rem 0;
}

/* What is already bought reads louder than what is next. The muted register
   belongs to a purchase not yet made; this is the one line describing the
   points already spent, and on a fully invested talent it is the only one. */
.talents .hint.held {
    color: var(--fg);
}

.talents .augments {
    margin-top: 1rem;
    border-top: 1px solid var(--line);
    padding-top: 0.75rem;
}

.talents .augments h5 {
    margin: 0 0 0.4rem;
}

.talents .augment-progress {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--muted);
    font-size: 0.85rem;
    margin: 0 0 0.6rem;
}

/* A slot is a shape whether or not anything is in it — that is the whole
   point. An empty one has to be as visible as a full one, or the row reads
   as a list of what is on rather than as a decision with room left. */
.talents .slots {
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.talents .slot {
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 0.15rem 0.7rem;
    font-size: 0.85rem;
}

.talents .slot.filled {
    border-color: var(--gold);
    color: var(--gold);
    font-weight: 600;
}

.talents .slot.empty {
    border-style: dashed;
    color: var(--muted);
}

/* The price of the whole row, pulled up under it so it reads as belonging to
   the slots rather than as a line of its own. */
.talents .combined-price {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin: -0.4rem 0 0.75rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--blood-fg);
}

.talents .augment-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: 0.6rem;
}

.talents .augment {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.25rem;
    background: var(--raised);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 0.6rem 0.75rem;
}

.talents .augment.active {
    border-color: var(--gold);
    background: var(--gold-wash);
}

/* Locked reads as not-yet-yours rather than as broken: the card is still
   fully legible, because what it grants and what it costs are exactly what
   the point is being spent on. */
.talents .augment.locked .augment-name {
    color: var(--muted);
}

.talents .augment-name {
    font-weight: 600;
}

.talents .augment .grants {
    font-size: 0.9em;
}

/* The price, in the colour a refusal already uses — an augment is a trade,
   and the half that takes should not read like the half that gives. */
.talents .augment .pays {
    color: var(--blood-fg);
    font-size: 0.85em;
}

/* ---------- Guides ----------

   Long-form prose, so this is the one place the app reads like a document
   rather than a form: the serif face, a measured column and a generous line
   height. The ground does not change — the app commits to one. */

.guide-index ul {
    list-style: none;
    padding: 0;
}

.guide-index li p {
    margin: 0.25rem 0 0;
    color: var(--muted);
}

.guide-index li button {
    min-height: 0;
    padding: 0;
    background: none;
    border: 0;
    color: var(--gold);
    font-family: var(--display);
    font-size: 1.05rem;
    font-weight: 600;
}

.guide-index li button:hover {
    background: none;
    border-color: transparent;
    color: var(--gold-soft);
}

.guide {
    max-width: 42rem;
    font-family: var(--prose);
    font-size: 1.05rem;
    line-height: 1.7;
}

.guide h1,
.guide h2,
.guide h3 {
    font-family: var(--display);
}

/* The app styles every `li` as a card, which is right for a character list
   and wrong for prose. Guides opt back out into ordinary bullets. */
.guide ul,
.guide ol {
    list-style: revert;
    padding-left: 1.5rem;
    display: block;
    margin: 1rem 0;
}

.guide li {
    background: none;
    border: none;
    border-radius: 0;
    padding: 0;
    margin-bottom: 0.4rem;
}

.guide h1 {
    margin-top: 1rem;
}

.guide h2 {
    margin-top: 2rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--line);
}

.guide table {
    border-collapse: collapse;
    width: 100%;
    margin: 1rem 0;
    font-family: var(--ui);
    font-size: 0.95rem;
}

.guide th,
.guide td {
    border: 1px solid var(--line);
    padding: 0.4rem 0.6rem;
    text-align: left;
}

.guide th {
    background: var(--raised);
}

.guide code {
    background: var(--raised);
    padding: 0.1rem 0.3rem;
    border-radius: var(--radius-chip);
    font-size: 0.9em;
}

.guide pre {
    background: var(--sunken);
    border: 1px solid var(--line-soft);
    padding: 0.75rem 1rem;
    border-radius: var(--radius-control);
    overflow-x: auto;
}

.guide pre code {
    background: none;
    padding: 0;
}

.guide blockquote {
    margin: 1rem 0;
    padding-left: 1rem;
    border-left: 3px solid var(--gold-dim);
    color: var(--muted);
}

/* ---------- Sign-in ----------

   The one screen with nothing behind it, so it centres on the ground rather
   than sitting under a bar that has nothing to navigate to yet. */

.login {
    max-width: 24rem;
    margin: 12vh auto 0;
    padding: 1.5rem;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius-panel);
}

.login h1 {
    text-align: center;
}

.login form {
    flex-direction: column;
    align-items: stretch;
}

.login input {
    width: 100%;
}
