/* Pocket GameMaster — visual theme, layered over Bootstrap.
   Design tokens + a serif display face for a tabletop-book feel, an arcane-violet
   accent, warm parchment surfaces, and an atmospheric landing hero. A future
   "selectable themes" feature (ROADMAP) can swap these tokens. */

:root {
    --pgm-accent: #6d28d9;          /* arcane violet */
    --pgm-accent-dark: #5b21b6;
    --pgm-ink: #20242e;
    --pgm-paper: #f6f4ef;           /* warm parchment */
    --pgm-display: Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif;
    --pgm-line: rgba(32, 36, 46, .08);   /* hairline borders */
    --pgm-shadow: rgba(32, 36, 46, .05); /* card shadow */
}

/* Dark mode (ADR-033). Bootstrap 5.3 recolors its OWN components off `data-bs-theme="dark"`;
   here we make the custom PGM tokens dark-aware so the parchment surfaces, hairlines, and accent
   follow suit. The `.pgm-auth-shell` hero is intentionally dark in both themes. */
[data-bs-theme="dark"] {
    --pgm-accent: #8b5cf6;          /* violet, brightened for a dark ground */
    --pgm-accent-dark: #a78bfa;     /* links/hover — lighter so they read on dark */
    --pgm-ink: #e7e4f0;             /* light ink */
    --pgm-paper: #17181f;           /* dark surface (replaces parchment) */
    --pgm-line: rgba(255, 255, 255, .10);
    --pgm-shadow: rgba(0, 0, 0, .45);
    color-scheme: dark;             /* native controls, scrollbars, form widgets follow */
}

body {
    background-color: var(--pgm-paper);
    color: var(--pgm-ink);
}

h1, h2, h3, h4, .navbar-brand, .card-title, .display-3, .display-6 {
    font-family: var(--pgm-display);
    letter-spacing: .2px;
}

.card {
    border: 1px solid var(--pgm-line);
    border-radius: .6rem;
    box-shadow: 0 1px 2px var(--pgm-shadow), 0 8px 24px var(--pgm-shadow);
}

a { color: var(--pgm-accent-dark); }

.btn-primary {
    --bs-btn-bg: var(--pgm-accent);
    --bs-btn-border-color: var(--pgm-accent);
    --bs-btn-hover-bg: var(--pgm-accent-dark);
    --bs-btn-hover-border-color: var(--pgm-accent-dark);
    --bs-btn-active-bg: var(--pgm-accent-dark);
    --bs-btn-active-border-color: var(--pgm-accent-dark);
    --bs-btn-disabled-bg: var(--pgm-accent);
    --bs-btn-disabled-border-color: var(--pgm-accent);
}
.btn-outline-primary {
    --bs-btn-color: var(--pgm-accent-dark);
    --bs-btn-border-color: var(--pgm-accent);
    --bs-btn-hover-bg: var(--pgm-accent);
    --bs-btn-hover-border-color: var(--pgm-accent);
    --bs-btn-active-bg: var(--pgm-accent-dark);
}
.badge.bg-primary { background-color: var(--pgm-accent) !important; }

/* Landing / auth pages — atmospheric hero (AuthLayout wraps these) */
.pgm-auth-shell {
    background:
        radial-gradient(1100px 560px at 50% -12%, rgba(109, 40, 217, .28), transparent 60%),
        linear-gradient(180deg, #12131a 0%, #1b1d29 100%);
    color: #eae7f2;
}
.pgm-auth-shell h1.display-3 {
    color: #fff;
    text-shadow: 0 2px 28px rgba(109, 40, 217, .55);
}
.pgm-auth-shell .text-muted { color: #b7b2c6 !important; }
/* The hero behind this is always dark, but the CARD must still follow the theme: it used to be a
   hardcoded light #fbfaf7 while its text used var(--pgm-ink), which flips to LIGHT in dark mode —
   i.e. light text on a light card. Using --pgm-paper keeps the pair consistent in both themes. */
.pgm-auth-shell .card {
    background-color: var(--pgm-paper);
    color: var(--pgm-ink);
    border: 1px solid rgba(255, 255, 255, .12);
}
/* Inputs inside the card inherit the theme too, so placeholders/values stay legible. */
.pgm-auth-shell .card .form-control,
.pgm-auth-shell .card .form-select {
    background-color: color-mix(in srgb, var(--pgm-paper) 94%, var(--pgm-ink) 6%);
    color: var(--pgm-ink);
    border-color: color-mix(in srgb, var(--pgm-paper) 70%, var(--pgm-ink) 30%);
}
.pgm-auth-shell .card .text-muted { color: color-mix(in srgb, var(--pgm-ink) 65%, transparent) !important; }

/* Sidebar brand a touch larger */
.sidebar .navbar-brand { font-size: 1.15rem; }

/* Live-mic indicator (ADR-041): a player's video frame lights up while they are speaking, so an
   always-on mic is visible at a glance — and visible to the whole table, not just to that player.
   The transition keeps it from strobing on short bursts of speech. */
/* Camera tile.
   Height is set DIRECTLY, never as a ratio of width. Bootstrap's .ratio-4x3 sets height via
   padding-top:75%, so a narrower window (fewer grid columns → each card WIDER) made every tile
   taller and pushed the room and GM panels off the bottom of the screen. Clamping to viewport
   height instead means resizing horizontally no longer changes vertical layout at all. */
.pgm-cam-slot {
    position: relative;
    height: clamp(84px, 11vh, 132px);
    overflow: hidden;
    outline: 3px solid transparent;
    outline-offset: 1px;
    transition: outline-color .12s ease-in, box-shadow .12s ease-in;
}
/* LiveKit injects a <video> into the slot; cover it without letterboxing or stretching. */
.pgm-cam-slot > video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.pgm-cam-slot > .pgm-cam-placeholder {
    position: absolute;
    inset: 0;
}
/* The GM's tile is a bit taller and visually distinct — it is the table's focal point, and it
   carries a portrait or camera rather than a character sheet. */
.pgm-gm-slot {
    height: clamp(110px, 15vh, 180px);
}
.pgm-gm-slot > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.pgm-cam-slot.pgm-speaking {
    outline-color: #22c55e;                          /* green = transmitting */
    box-shadow: 0 0 14px rgba(34, 197, 94, .65);
}
/* Hard mute must read as clearly OFF, never as "just not talking right now". */
.pgm-cam-slot.pgm-muted {
    outline-color: #dc3545;
    outline-style: dashed;
    box-shadow: none;
}

/* A recessed, theme-aware panel (play transcript, log panes, …). Use this instead of a hardcoded
   light colour like #f8f9fa, which turns into light-text-on-light in dark mode. */
.pgm-surface {
    background-color: color-mix(in srgb, var(--pgm-paper) 92%, var(--pgm-ink) 8%);
    color: var(--pgm-ink);
}

/* Outline drag & drop: while a room is being dragged, every group card advertises itself as a target. */
.pgm-droppable { outline: 2px dashed var(--pgm-accent); outline-offset: 3px; }
.pgm-droppable:hover { background-color: rgba(128, 128, 128, .10); }

/* Auto-growing prose textareas (room description, GM notes, …). `field-sizing: content` makes the
   box grow with its text in supporting browsers; min/max keep it sane and let it scroll past the cap.
   pgm-autogrow.js drives the same behaviour where field-sizing isn't supported yet.
   https://developer.mozilla.org/docs/Web/CSS/field-sizing */
textarea.pgm-autogrow {
    field-sizing: content;
    min-height: 4.5rem;
    max-height: 60vh;
    overflow-y: auto;
}

/* Room-graph Map (ADR-034 Phase 2) — theme-aware SVG graph. */
.pgm-room-map { background: var(--pgm-paper); user-select: none; }
/* Edges need to read against the paper AND against the node cards they pass over — the hairline
   --pgm-line was far too faint to trace. Mid-grey works in both themes; the halo keeps a line
   legible where it crosses a card. */
.pgm-map-edge {
    stroke: #8b8fa3;
    stroke-width: 2px;
    stroke-linecap: round;
    paint-order: stroke;
}
.pgm-map-arrow { fill: #8b8fa3; }
/* Nodes paint after edges, so a line passing behind a card is hidden by it rather than crossing it. */
.pgm-map-node { cursor: pointer; }
/* The card frame (fill shows as a border around the thumbnail + behind the caption). */
.pgm-map-node .pgm-node-card { fill: var(--pgm-paper); stroke: var(--pgm-accent); stroke-width: 1.5px; }
.pgm-map-node:hover .pgm-node-card { stroke-width: 3px; filter: brightness(1.1); }
.pgm-map-node .pgm-node-caption { fill: var(--pgm-ink); font-size: 13px; pointer-events: none; }
.pgm-map-node .pgm-node-img { pointer-events: none; }
.pgm-map-node .pgm-node-noimg { fill: rgba(128, 128, 128, .14); }        /* placeholder when no image */
.pgm-map-node .pgm-node-noimg-icon { font-size: 30px; opacity: .45; pointer-events: none; }
/* State frames — the coloured padding reads as a border around the scene thumbnail. */
.pgm-map-node.start .pgm-node-card { fill: #198754; stroke: #198754; stroke-width: 3px; }
.pgm-map-node.start .pgm-node-caption { fill: #fff; }
.pgm-map-node.deadend .pgm-node-card { stroke: #fd7e14; stroke-width: 3px; }
.pgm-map-node.unreachable .pgm-node-card { stroke: #dc3545; stroke-width: 2px; stroke-dasharray: 5 3; }
.pgm-map-node.connecting .pgm-node-card { stroke: var(--pgm-accent); stroke-width: 3.5px; }
.pgm-map-node.faded { opacity: .18; }               /* group highlight: non-group rooms recede */
.pgm-map-node.moving { opacity: .85; cursor: grabbing; }
/* A pinned room (hand-placed by the author) gets a subtle marker so you can tell it from an
   auto-placed one — "Re-arrange" clears every pin. */
.pgm-map-node.pinned .pgm-node-card { stroke-dasharray: none; filter: drop-shadow(0 2px 4px rgba(0,0,0,.35)); }
/* The link handle: drag from here to another room to create an exit. */
.pgm-node-link { fill: var(--pgm-accent); opacity: .35; cursor: crosshair; }
.pgm-map-node:hover .pgm-node-link { opacity: 1; }
.pgm-node-link-icon { fill: #fff; font-size: 10px; pointer-events: none; opacity: 0; }
.pgm-map-node:hover .pgm-node-link-icon { opacity: 1; }
.pgm-map-key { font-weight: bold; }
.pgm-map-key.start { color: #198754; }
.pgm-map-key.deadend { color: #fd7e14; }
.pgm-map-key.unreachable { color: #dc3545; }

/* Spoken narration reveals one word at a time as the voice reaches it (ADR-041). A hard pop draws
   the eye to the mechanism instead of the story, so each word fades up as it arrives.

   Deliberately `inline`, NOT `inline-block`: an inline-block box collapses the whitespace at its own
   edges, which ran every word together into one unreadable string. Staying inline means the words
   flow, wrap and inherit exactly like plain text — the only thing that changes is opacity. That also
   rules out transforms (they don't apply to inline boxes), which is fine: the ask was a fade. */
.pgm-word {
    animation: pgm-word-in 260ms ease-out both;
    /* Preserve the trailing space baked into each word, and any newlines the narration carries.
       Without this the browser collapses the separator and every word runs together. */
    white-space: pre-wrap;
}

@keyframes pgm-word-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Motion here is decoration. For anyone who has asked the OS to reduce it, keep the reveal but make
   it near-instant rather than removing the cue entirely.
   https://developer.mozilla.org/docs/Web/CSS/@media/prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
    .pgm-word { animation-duration: 80ms; }
}

/* ── Ember indicator (ADR-053) ──────────────────────────────────────────────
   Quiet by default: this is a resource meter, not a call to action, and a
   balance that shouts at a player mid-session is worse than one they forget
   about. It only raises its voice when it is nearly out. */
.pgm-embers {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .15rem .6rem;
    margin-right: .75rem;
    border-radius: 999px;
    font-variant-numeric: tabular-nums;   /* the number must not jitter as it counts down */
    font-size: .9rem;
    line-height: 1.6;
    /* Explicit colours, not currentColor. Inheriting the bar's colour made this dark-on-dark and
       all but invisible: the top bar sets a colour for ITS content, and a pill that borrows it has
       no contrast against a background derived from the same value. A meter you cannot read is
       worse than no meter, because you believe you are watching it. */
    /* Light theme by default. The first attempt used one pale-orange colour for both themes and
       was unreadable on the light top bar (#f7f7f7) — orange on near-white. Each theme needs its
       own value; there is no single ember colour that reads on both. */
    color: #a85b00;
    background: rgba(240, 173, 78, .18);
    border: 1px solid rgba(200, 130, 30, .45);
    transition: color .3s ease, background-color .3s ease, border-color .3s ease;
}

[data-bs-theme="dark"] .pgm-embers {
    color: #ffc078;
    background: rgba(240, 173, 78, .16);
    border-color: rgba(240, 173, 78, .40);
}

.pgm-embers-icon { font-size: .95em; }

/* Running low — warm, not alarming. */
.pgm-embers-low {
    color: #8a4500;
    background: rgba(240, 173, 78, .38);
    border-color: rgba(200, 130, 30, .75);
}

[data-bs-theme="dark"] .pgm-embers-low {
    color: #ffd8a8;
    background: rgba(240, 173, 78, .30);
    border-color: rgba(240, 173, 78, .70);
}

/* Burned out. The icon changes to a dark moon as well, so this reads without relying on colour. */
.pgm-embers-out {
    color: #495057;
    background: rgba(108, 117, 125, .18);
    border-color: rgba(108, 117, 125, .40);
}

[data-bs-theme="dark"] .pgm-embers-out {
    color: #ced4da;
    background: rgba(173, 181, 189, .18);
    border-color: rgba(173, 181, 189, .35);
}

/* ── A grouping row inside a table ──────────────────────────────────────────
   Bootstrap's .table-light forces white regardless of the active theme, which is
   wrong for a header that only needs to sit slightly apart from its rows. Tinted
   from the theme instead, so it reads as a divider in both. */
.pgm-row-group > td {
    background-color: rgba(0, 0, 0, .04);
    letter-spacing: .02em;
    text-transform: uppercase;
    opacity: .75;
}

[data-bs-theme="dark"] .pgm-row-group > td {
    background-color: rgba(255, 255, 255, .06);
}

/* ── Sidebar: separating everyday navigation from admin ─────────────────────
   Tinted from the current theme rather than a fixed grey, for the same reason
   the status categories are: a hard-coded colour is right in one theme and
   wrong in the other. */
.pgm-nav-divider {
    height: 1px;
    margin: .75rem 1rem .25rem;
    background: rgba(255, 255, 255, .18);
}

.pgm-nav-section {
    padding: .1rem 1.5rem .35rem;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    opacity: .55;
}

/* The sidebar keeps its dark treatment in light mode, so the divider only needs
   flipping where the surrounding chrome actually changes. */
[data-bs-theme="light"] .pgm-nav-divider {
    background: rgba(255, 255, 255, .22);
}

/* ── Transcript entries ─────────────────────────────────────────────────────
   Full width made the old tight stacking unreadable: without separation the
   whole session became one block of text, and the boundary between a player
   speaking and the game master answering — the most useful structure in the
   panel — disappeared. A hairline and real breathing room, tinted from the
   theme rather than a fixed grey. */
.pgm-line {
    padding: .45rem .25rem;
    border-top: 1px solid rgba(0, 0, 0, .07);
    line-height: 1.55;
}

/* No rule above the first line — a divider at the very top separates nothing. */
.pgm-line:first-child { border-top: 0; }

[data-bs-theme="dark"] .pgm-line { border-top-color: rgba(255, 255, 255, .09); }

/* The game master's lines get a little more air: they are what people are
   actually reading, and they arrive word by word. */
.pgm-line-gm { padding-block: .6rem; }

/* ── Who is speaking ────────────────────────────────────────────────────────
   A colour per player so the table is readable at a glance. Applied to the NAME
   and a left accent only — colouring the body text would trade legibility for
   identification, and the body is the part being read.

   Two palettes, because one set cannot serve both themes: pastels wash out to
   near-white on a light background, and saturated colours glare on a dark one.
   Same hue order in both, so a player's colour stays recognisably "the green
   one" whichever theme you use. */
.pgm-line { border-left: 3px solid transparent; padding-left: .55rem; }

.pgm-actor-0 { --pgm-speaker: #b3261e; }   /* red    */
.pgm-actor-1 { --pgm-speaker: #1e6b3a; }   /* green  */
.pgm-actor-2 { --pgm-speaker: #1a4f8a; }   /* blue   */
.pgm-actor-3 { --pgm-speaker: #8a6100; }   /* amber  */
.pgm-actor-4 { --pgm-speaker: #6b3fa0; }   /* violet */
.pgm-actor-5 { --pgm-speaker: #0f6b6b; }   /* teal   */

[data-bs-theme="dark"] .pgm-actor-0 { --pgm-speaker: #ff9a8f; }
[data-bs-theme="dark"] .pgm-actor-1 { --pgm-speaker: #86d9a4; }
[data-bs-theme="dark"] .pgm-actor-2 { --pgm-speaker: #8fbcf5; }
[data-bs-theme="dark"] .pgm-actor-3 { --pgm-speaker: #f2c86b; }
[data-bs-theme="dark"] .pgm-actor-4 { --pgm-speaker: #c9a6f0; }
[data-bs-theme="dark"] .pgm-actor-5 { --pgm-speaker: #7fd6d6; }

.pgm-speaker { color: var(--pgm-speaker); }

/* The accent repeats the name's colour down the left edge, so a run of lines
   from one player reads as a block without tinting a word of the text. */
.pgm-line[class*="pgm-actor-"] { border-left-color: var(--pgm-speaker); }

/* The game master is deliberately NOT in the palette: it is not one of the
   players, and giving it a colour would put it in the same visual category. */
.pgm-line-gm { border-left-color: transparent; }
