/* style.css :: one dark terminal look for both pages, on top of Bootstrap (vendor/bootstrap, loaded first). */

/* Served from here, not Google Fonts: the CSP is 'self' only, and Google's subsets drop the map's box-drawing glyphs. */
@font-face {
    font-family: "JetBrains Mono";
    src: url("fonts/JetBrainsMono-Regular.woff2") format("woff2");
    font-display: swap;
}

/* The map's 8x8 pixel font (ref/dungeonmode, CC0). Map cells only: game text stays JetBrains Mono, the fallback. */
@font-face {
    font-family: "Dungeon Mode";
    src: url("fonts/dungeon-mode.woff2") format("woff2");
    font-display: swap;
}

:root {
    --bg: #15130f;
    --panel: #1f1c17;
    --line: #3d362b;
    --fg: #e8dfca;
    --dim: #9b907a;
    --accent: #d9a441;
    --error: #e47a63;

    /* Bootstrap in this palette, monospace everywhere, near-square corners. */
    --bs-body-bg: var(--bg);
    --bs-body-color: var(--fg);
    --bs-emphasis-color: var(--fg);
    --bs-secondary-color: var(--dim);
    --bs-secondary-bg: var(--panel);
    --bs-tertiary-bg: var(--panel);
    --bs-border-color: var(--line);
    --bs-body-font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    --bs-font-monospace: var(--bs-body-font-family);
    --bs-success-rgb: 127, 166, 80;
    --bs-warning-rgb: 217, 164, 65;
    --bs-danger-rgb: 228, 122, 99;
    --bs-border-radius: 0.125rem;
    --bs-border-radius-sm: 0.125rem;
    --bs-offcanvas-bg: var(--bg);
}

body { font-variant-ligatures: none; } /* game text, not code: "->" stays two characters */

.play {
    display: flex;
    flex-direction: column;
    height: 100dvh;
    max-width: 60rem;
    margin: 0 auto;
    padding: 1rem;
}

#log {
    flex: 1;
    overflow-y: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

#log .echo { color: var(--dim); margin-top: 0.75rem; }
#log .echo::after { content: attr(data-time); float: right; visibility: hidden; font-size: 0.75rem; }
#log .echo:hover::after, #log .echo.show::after { visibility: visible; }
.error { color: var(--error); }

/* Log line kinds (classify() and roomKinds() in play.js). Room headers and the markers use the Dungeon Mode font. */
#log .room-name { margin-top: 0.75rem; color: var(--accent); font-family: "Dungeon Mode", var(--bs-body-font-family); }
#log .room-name::before, #log .room-name::after {
    content: "════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════"; display: block; overflow: hidden; white-space: nowrap; color: var(--line);
}
#log .room-desc { margin-bottom: 0.5rem; }
#log .l-exit { color: var(--accent); }
#log .l-hint { color: var(--dim); font-style: italic; }
#log .l-npc { color: #b9a3dc; margin: 0.25rem 0; padding-left: 2ch; border-left: 2px solid #5c4f78; }
#log .l-fight { color: var(--error); }
/* Speech bubbles: a box that shrinks to its text, with a tail under the left corner; a shout's box is double-ruled. */
#log .l-say, #log .l-shout { --c: #a6c48a; position: relative; width: fit-content; max-width: 100%; color: var(--c);
    border: 2px solid var(--c); padding: 0 1ch; margin: 0.4rem 0 0.8rem 1ch; }
#log .l-shout { --c: #e8a23a; font-weight: bold; border: 4px double var(--c); }
#log .me { --c: #7d9168; }
#log .l-shout.me { --c: #a8763a; }
#log .l-say::after, #log .l-shout::after { content: ""; position: absolute; left: 1ch; top: 100%;
    border: 5px solid transparent; border-top-color: var(--c); border-bottom-width: 0; }
#log .l-atk { padding-left: 1.5ch; text-indent: -1.5ch; }
#log .l-atk::before { font-family: "Dungeon Mode", var(--bs-body-font-family); display: inline-block; width: 1.5ch;
    text-indent: 0; content: "†"; }
#log .l-hit { color: var(--error); }
#log .l-miss { color: var(--dim); }
#log .l-crit { color: var(--error); font-weight: bold; }
#log .l-crit::before { content: "╳"; }
.hp-ok { color: #7fa650; }
.hp-low { color: var(--error); }
#log .l-here, #log .l-foe, #log .l-item { padding-left: 1.5ch; text-indent: -1.5ch; }
#log .l-here::before, #log .l-foe::before, #log .l-item::before {
    font-family: "Dungeon Mode", var(--bs-body-font-family); display: inline-block; width: 1.5ch; text-indent: 0;
}
#log .l-here { color: #8fc1d4; }
#log .l-here::before { content: "☺"; }
#log .l-foe { color: var(--error); }
#log .l-foe::before { content: "☠"; }
#log .l-item { color: #c8b27a; }
#log .l-item::before { content: "•"; }

#hints {
    margin: 0;
    padding: 0.25rem 0;
    list-style: none;
    border-top: 1px solid var(--line);
    color: var(--dim);
}

#hints li { cursor: pointer; }
#hints li:hover { color: var(--fg); }
#hints b { display: inline-block; min-width: 11ch; color: var(--accent); font-weight: normal; }

#prompt {
    display: flex;
    gap: 0.5rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--line);
    color: var(--accent);
}

#cmd {
    flex: 1;
    min-width: 0;
    background: transparent;
    border: 0;
    border-bottom: 1px solid transparent;
    color: var(--fg);
    font: inherit;
    outline: none;
}

#cmd:focus-visible { border-bottom-color: var(--accent); }

/* Quick commands from actions() in game.php: tap to send, or to start typing one that needs more. */
#actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    padding: 0.5rem 0;
    border-top: 1px solid var(--line);
}

#actions:empty { display: none; }
/* Beside the pad, one row level with each of its two. */
#actions .rows { display: flex; flex: 1; flex-direction: column; gap: 0.25rem; min-width: 0; }
#actions .rows .more { flex: 0 0 auto; }
#actions .rows .more:last-child { margin-top: auto; }
#actions .rows .more:only-child { margin-top: 0; }
/* The exits pad (pad() in play.js): fixed squares on the left, the other buttons wrapping beside it. */
#actions .pad { display: grid; grid-template-columns: repeat(3, 2.5rem); grid-auto-rows: 2.5rem; gap: 0.25rem; }
#actions .pad .btn { padding: 0; --bs-btn-disabled-color: var(--dim); --bs-btn-disabled-border-color: var(--line); }
#actions .more { display: flex; flex: 1; flex-wrap: wrap; align-content: flex-start; gap: 0.25rem; }
#actions .more:empty { display: none; }
#actions .more select { flex: 1; min-width: 0; background-color: var(--bg); color: var(--accent); border-color: var(--line); }

#hero-toggle, #map-toggle, #chat-toggle, #actions .btn {
    --bs-btn-color: var(--accent);
    --bs-btn-border-color: var(--line);
    --bs-btn-hover-color: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
    --bs-btn-active-color: var(--accent);
    --bs-btn-active-border-color: var(--accent);
}

/* A choice as a form (#panel, panel() in game.php): in the log's place while open, its footer always in view. */
#panel { --bs-card-bg: var(--panel); flex: 1; min-height: 0; overflow-y: auto; }
#panel-title { color: var(--accent); }
#panel-title:focus { outline: none; } /* focused for screen readers, not a control */
#panel-count { color: var(--accent); }
#panel fieldset + fieldset { margin-top: 0.75rem; }
#panel legend { font-size: 0.875rem; color: var(--dim); margin-bottom: 0.25rem; }
#panel .opt { display: flex; align-items: flex-start; gap: 0.5rem; padding: 0.375rem 0.25rem; margin: 0;
    border-top: 1px solid var(--line); cursor: pointer; }
#panel .opt:first-of-type { border-top: 0; }
#panel .opt .form-check-input { flex: none; margin: 0.3rem 0 0; float: none; }
#panel .opt small { display: block; }
#panel .opt:has(input:disabled:not(:checked)) { opacity: 0.5; cursor: default; } /* the limit is reached */
#panel .assign + .btn { margin-top: 0.75rem; }
#panel .opt .badge { margin-left: auto; color: var(--dim); border: 1px solid var(--line); font-weight: normal; }
#panel .form-check-input { background-color: var(--bg); border-color: var(--dim); }
#panel .form-check-input:checked { background-color: var(--accent); border-color: var(--accent); }
#panel .assign { display: grid; grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr)); gap: 0.5rem; }
#panel .form-select { background-color: var(--bg); color: var(--fg); }
#panel .card-footer { position: sticky; bottom: 0; background: var(--panel); display: flex; flex-wrap: wrap;
    align-items: center; gap: 0.5rem; }
#panel-error { color: var(--error); }
#panel-error:empty { display: none; }
#panel-cmd { color: var(--dim); margin-right: auto; overflow-wrap: anywhere; }
#panel .btn, #status .btn {
    --bs-btn-color: var(--accent);
    --bs-btn-border-color: var(--line);
    --bs-btn-hover-color: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
    --bs-btn-active-color: var(--accent);
    --bs-btn-active-border-color: var(--accent);
}
#panel #panel-ok { --bs-btn-bg: var(--accent); --bs-btn-color: var(--bg); --bs-btn-hover-bg: var(--fg);
    --bs-btn-hover-color: var(--bg); --bs-btn-active-bg: var(--fg); --bs-btn-active-color: var(--bg); }

/* The hero sheet (#hero): a drawer on phones (Bootstrap offcanvas-lg), a column beside the log from 992px. */
#sheet { --bs-card-bg: var(--panel); }
#hero-name { color: var(--accent); }
#sheet .progress { --bs-progress-height: 0.375rem; --bs-progress-bg: var(--line); }
#sheet .stat small { font-size: 0.7rem; }
#status { display: flex; flex-wrap: wrap; gap: 0.25rem; } /* not d-flex: its !important would beat [hidden] */
#map, .map { color: var(--dim); white-space: pre; }
/* The explored map can outgrow its box: it scrolls, kept centred on @ (play.js), at most 21 rows of 8/9-em cells. */
.map-grid { position: relative; overflow: auto; max-height: calc(21 * 12px * 8 / 9); }
#map { padding-inline: 0.5rem; }
.map { margin-top: 0.25rem; }
.map .map-grid.board { max-height: none; } /* sized by fit() in play.js */
.map-text { font-size: 0.8rem; white-space: pre-wrap; } /* a fight's legend can be long */
/*
 * cmd_map(): square cells 8/9 em, the font's own cell, so wall glyphs join. It's pixel art, so a font pixel must be a
 * whole number of device pixels: 12px here (4 per pixel on 3x phones), 13.5px on wide screens (3 per pixel on 2x),
 * 18px for the sheet's map (2 CSS px per pixel, whole on 1x to 3x). A map wider than its box scrolls; a fight's board
 * is sized to fill its box instead (fit() in play.js).
 */
/* line-height as the cell, too: the body's 1.5 drew each glyph a third of a cell below the square it taps. */
.map-row {
    font-family: "Dungeon Mode", var(--bs-body-font-family);
    font-size: 12px;
    height: calc(8em / 9);
    line-height: calc(8em / 9);
}
.map-row span { display: inline-block; width: calc(8em / 9); height: 100%; vertical-align: top; text-align: center; }
.map-row .w { color: #827050; }
.map-row .rock { color: #2a2620; }
.map-row .cave { color: #5f5546; }
.map-row .tw { color: var(--town-edge, #b08840); } /* the town's borders: brown, dirt roads */
.map-row .hedge { color: #5c6b35; }
.map-row .f { color: #5e5443; }
.map-row .s { color: rgb(var(--bs-success-rgb)); }
.map-row .me { color: var(--accent); }
.map-row .dead { color: #c0392b; } /* my skull and other heroes' bodies */
.map-row .st { color: #7fb2e0; }
.map-row .foe { color: var(--error); }
.map-row .ally { color: rgb(var(--bs-info-rgb)); }
.map-row .tree { color: #4f7a3a; }
.map-row .brush { color: #6b6a35; }
.map-row .water { color: #3f6f8f; }
.map-row .area { color: #ff8a1f; }
.map-row .road { color: #7a6a4a; }
.map-row .grass { color: #4f7a3a; }
.map-row .bld, .map-row .roof { color: #a8845a; }
.map-row .win { color: #e8c860; }
.map-row .door { color: #c9a05a; }
.map-row .npc { color: rgb(var(--bs-info-rgb)); }
.map-row .sign { color: #d8d0b8; }
.map-row .icon { color: #f6efd6; text-shadow: 0 0 1px #f6efd6; } /* a building's sign: bold and bright */
/* Each building has its own colours (see tints() in play.js). */
.map-row .roof.t-inn { color: #b5503c; } .map-row .bld.t-inn { color: #8a6a48; }
.map-row .roof.t-temple { color: #b8b0a0; } .map-row .bld.t-temple { color: #8c8678; }
.map-row .roof.t-smith { color: #8f3a2a; } .map-row .bld.t-smith { color: #6a5048; }
.map-row .roof.t-armor { color: #5a7a9a; } .map-row .bld.t-armor { color: #6a7480; }
.map-row .roof.t-apoth { color: #4f8a5a; } .map-row .bld.t-apoth { color: #76806a; }
.map-row .roof.t-curio { color: #8a5aa0; } .map-row .bld.t-curio { color: #7a6a84; }
.map-row .roof.t-keep { color: #9a9488; } .map-row .bld.t-keep { color: #7a7468; }
.map-row .roof.t-barracks { color: #a08a5a; } .map-row .bld.t-barracks { color: #7a6c50; }
.map-row .stone { color: #9a9a9a; }
.map-row .ember { color: #ff8a1f; }
.map-row .plank { color: #a0724a; } /* a bridge's planks */
.map-row .notice { color: #e8c860; }
.map-row .spoke { color: #c9a05a; } /* the tan-yellow of doors */
/* A feature's own colour (features.tone), after the glyph classes so it wins. */
.map-row .stack > .grow { position: absolute; left: 0; top: 0; width: calc(8em / 9); height: calc(8em / 9); line-height: calc(8em / 9); z-index: 1; } /* a big feature, scaled whole (features.size) */
.map-row .tone-wood { color: #a0724a; }
.map-row .tone-water { color: #4169e1; }
.map-row .tone-fire { color: #ff8a1f; }
/* A stacked square (the room's overlay layer): a second glyph over the first, each its own colour. */
.map-row .stack { position: relative; }
.map-row .stack > .over { position: absolute; left: 0; top: 0; }
.map-row .lbl { color: var(--dim); font-family: var(--bs-body-font-family); }
.map-row [data-cmd], #map .map-grid:not(.board) .me { cursor: pointer; } /* the minimap's @ opens the battle map */
/* The labels at a place's exits (labelExits() in play.js): small text outside the border. */
.map-row.exit-row, .map-row.has-exit { position: relative; }
.exit-label { position: absolute; white-space: nowrap; font-family: var(--bs-body-font-family); font-size: 0.7rem; color: var(--dim); }
.map-row .exit-label { width: auto; height: auto; }
.exit-row .exit-label { transform: translateX(-50%); }
.exit-label.west { right: calc(100% + 0.3rem); top: 0; }
.exit-label.east { left: calc(100% + 0.3rem); top: 0; }
.map-grid.labelled { padding-inline: 3.8rem; }

/* The sheet's map takes whatever height the column (or drawer) has left, centred while it fits, scrolling when not. */
#map { flex: 1; }
/* The button above the sidebar map that toggles the minimap and a place's detail map. */
.map-back { align-self: flex-start; margin: 0 0 0.25rem 0.5rem; }
#map:empty { display: none; } /* until a hero exists */
#map { display: flex; flex-direction: column; }
#map .map-grid { flex: 1; max-height: none; min-height: 12rem; display: flex; flex-direction: column; }
/* Auto margins rather than justify-content: centre only while it fits, so the overflow stays scrollable. */
#map .map-grid > * { flex: none; width: max-content; margin-inline: auto; }
#map .map-grid > :first-child { margin-top: auto; }
#map .map-grid > :last-child { margin-bottom: auto; }
#map .map-row { font-size: 18px; }

/* The hero bar (#herobar): name, counts, status and the Sheet button on top, HP and XP bars below. */
#herobar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem 1rem; }
#herobar .bar-block { flex: 1 1 10rem; }
#sheet-toggle {
    --bs-btn-color: var(--accent);
    --bs-btn-border-color: var(--line);
    --bs-btn-hover-color: var(--accent);
    --bs-btn-hover-border-color: var(--accent);
    --bs-btn-active-color: var(--accent);
    --bs-btn-active-border-color: var(--accent);
}
#sheet-more { max-height: 60dvh; overflow-y: auto; }
#side > #map { --bs-card-bg: var(--panel); }

/* Phones: the drawer shows the sheet's details always, so no Sheet button. */
@media (max-width: 61.99rem) {
    #sheet-more { display: block !important; }
    #side > * { margin-top: 0.5rem; }
}

@media (min-width: 62rem) {
    /* Left: hero bar, log (or a choice panel), buttons, hints, prompt. Right: #side, the map over table talk. */
    .play {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 34rem;
        grid-template-rows: auto minmax(0, 1fr) auto auto auto;
        column-gap: 1.5rem;
        max-width: 125rem; /* 2000px */
    }

    .map-row { font-size: 13.5px; }
    .map-grid { max-height: calc(21 * 13.5px * 8 / 9); }

    /* The drawer's wrappers drop out so the sheet and #side are grid items of .play. */
    #hero, #hero .offcanvas-body { display: contents !important; } /* .offcanvas-body is d-flex, itself !important */
    .play > * { grid-column: 1; }
    #sheet { grid-row: 1; position: relative; }
    #log, #panel { grid-row: 2; }
    #actions { grid-row: 3; }
    #hints { grid-row: 4; }
    #prompt { grid-row: 5; }
    #sheet-more { position: absolute; top: 100%; left: 0; right: 0; z-index: 5; background: var(--panel); border: 1px solid var(--line); }

    #side { grid-column: 2; grid-row: 1 / -1; min-height: 0; }
    #map { min-height: 0; }
    #chat { flex: none; }
    #side #chat-log { min-height: 10rem; max-height: 14rem; }
    /* The account link sits at the foot of the column. */
    #hero .aside { position: static; }
}

.login {
    max-width: 22rem;
    margin: 15vh auto 0;
    padding: 0 1rem;
}

.login.wide { max-width: 34rem; }
.login h1 { color: var(--accent); font-size: 1.5rem; font-weight: normal; }
.login label { display: block; margin: 0.75rem 0; }

.login input {
    display: block;
    width: 100%;
    margin-top: 0.25rem;
    padding: 0.5rem;
    background: var(--panel);
    border: 1px solid var(--line);
    color: var(--fg);
    font: inherit;
}

.login input:focus-visible, .login button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.login .credits { margin-top: 3rem; font-size: 0.75rem; color: var(--dim); }
.login .credits a { color: inherit; overflow-wrap: anywhere; }

.login button {
    margin-top: 0.5rem;
    padding: 0.5rem 1.25rem;
    background: var(--accent);
    color: var(--bg);
    border: 0;
    font: inherit;
    cursor: pointer;
}

.aside { margin-top: 1rem; font-size: 0.875rem; }
.aside a { color: var(--dim); }
.aside a:hover { color: var(--fg); }
/* Pinned to the foot of the hero column (and the phone drawer), visible even when the sheet scrolls. */
#hero .aside { position: sticky; bottom: 0; padding: 0.5rem 0; background: var(--bg); }
.login .done { color: var(--accent); }
.login small { display: block; color: var(--dim); }

#chat-log { max-height: 12rem; }
.chat-line { overflow-wrap: anywhere; }
#chat-log b:not(.text-info) { color: var(--accent); }
