/*
 * Ishar browser-client HUD layout + widgets.
 *
 * The session owns the viewport. Desktop is a three-region dashboard —
 * individually collapsible side columns around a terminal that always gets the
 * leftover space; the compass rose is pinned to the bottom of the left column.
 * Phones are terminal-first: panels live behind a thumb-reach bottom dock and
 * open one at a time as a bottom sheet, plus a translucent tap-to-move rose
 * overlaid on the terminal. In .hud-off the grid collapses to just the terminal.
 *
 * Colors come from the shared design tokens (--ac-*, defined in
 * apps/core/static/css/style.css and loaded on every page — see
 * docs/design/tokens.md). The --hud-* set below covers only HUD-domain
 * meanings (vitals, resources, world flavor) with no site-wide equivalent.
 */

:root {
    --hud-hp: var(--ac-danger);
    --hud-mp: var(--ac-info);
    --hud-mv: var(--ac-ok);
    --hud-gold: #cdcd00;
    --hud-gold-wash: rgba(205, 205, 0, .1);
    --hud-xp: #9a86e0;
    --hud-tgt: #a0408a;
    --hud-mm: #a05ad0;
    --hud-edge: #d08a3a;
    --hud-event: #e8b04b;
    --hud-moon: #9aa6c8;
    --hud-moon-down: rgba(154, 166, 200, .22);
    --hud-hostile: var(--ac-danger);
    --hud-friendly: var(--ac-ok);
    --hud-group: #3fb6a8;
    --hud-dock-h: 3.5rem;
    /* Map terrain fills (hud-map.js reads these once via getComputedStyle —
       canvas needs literals). Muted and desaturated on purpose: the map is
       background; amber (current room / path) is the only thing that pops.
       Forest/Mountain Path reuse forest/hill. Documented in tokens.md. */
    --hud-ter-indoor: #26262c;
    --hud-ter-city: #33333b;
    --hud-ter-field: #2b3a28;
    --hud-ter-forest: #243626;
    --hud-ter-hill: #38332a;
    --hud-ter-mountain: #3c3c40;
    --hud-ter-water: #24384d;
    --hud-ter-deep: #1d2e42;
    --hud-ter-under: #1a2a3c;
    --hud-ter-desert: #40382a;
    --hud-ter-beach: #3d3a2e;
    --hud-ter-swamp: #2c3626;
}

/* ----- Page chrome: compact the shell so the session gets the screen ----- */
html.connect-page,
html.connect-page body {
    overflow: hidden;
    overscroll-behavior: none;
    height: 100%;
}
body.connect-page #logo { height: 2.4rem; }
body.connect-page .navbar { padding-top: .25rem; padding-bottom: .25rem; }
body.connect-page main > nav[aria-label="breadcrumb"] { display: none; }
body.connect-page footer { display: none; }
body.connect-page #content { padding: .5rem !important; }

/* ----- App grid ----- */
#connect-app {
    display: grid;
    gap: 6px;
    color: var(--ac-text);
    /* height is set by JS (fitAppHeight) */
}
#connect-app.hud-off {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas: "topbar" "center";
}
#connect-app.hud-on {
    grid-template-columns: 1fr;
    grid-template-rows: auto minmax(0, 1fr) auto;
    grid-template-areas: "topbar" "center" "dock";
}
#hud-topbar { grid-area: topbar; }
#hud-left   { grid-area: left; }
#hud-center { grid-area: center; }
#hud-right  { grid-area: right; }
#hud-dock   { grid-area: dock; }

.hud-off #hud-left,
.hud-off #hud-right,
.hud-off #hud-actionrow,
.hud-off #hud-dock,
.hud-off #hud-sheet,
.hud-off #hud-overlay,
.hud-off #hud-menu,
.hud-off #rose-overlay,
.hud-off #rose-toggle,
.hud-off .col-toggle,
.hud-off #hud-xpstrip,
.hud-off #vitals-bar { display: none; }

@media (max-width: 767.98px) {
    #connect-app { gap: 4px; }
    #connect-app.hud-on #hud-left,
    #connect-app.hud-on #hud-right { display: none; }
}

/* Desktop: collapsible columns around the terminal. */
@media (min-width: 768px) {
    #hud-dock, #hud-sheet, #rose-overlay, #rose-toggle { display: none !important; }
    #connect-app.hud-on {
        grid-template-columns: minmax(200px, 235px) minmax(0, 1fr) minmax(220px, 260px);
        grid-template-rows: auto minmax(0, 1fr);
        grid-template-areas:
            "topbar topbar topbar"
            "left   center right";
    }
    #connect-app.hud-on.l-closed {
        grid-template-columns: minmax(0, 1fr) minmax(220px, 260px);
        grid-template-areas: "topbar topbar" "center right";
    }
    #connect-app.hud-on.r-closed {
        grid-template-columns: minmax(200px, 235px) minmax(0, 1fr);
        grid-template-areas: "topbar topbar" "left center";
    }
    #connect-app.hud-on.l-closed.r-closed {
        grid-template-columns: 1fr;
        grid-template-areas: "topbar" "center";
    }
    #connect-app.hud-on.l-closed #hud-left,
    #connect-app.hud-on.r-closed #hud-right { display: none; }
}
@media (min-width: 1200px) {
    #connect-app.hud-on {
        grid-template-columns: minmax(215px, 260px) minmax(0, 1fr) minmax(240px, 300px);
    }
    #connect-app.hud-on.r-closed {
        grid-template-columns: minmax(215px, 260px) minmax(0, 1fr);
    }
}

/* ----- Top bar ----- */
#hud-topbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 2px 4px;
    position: relative;
}
#vitals-bar { display: contents; }

#connection-status {
    order: 1;
    display: inline-flex; align-items: center; gap: 6px;
    font-size: .8rem; font-weight: 700; white-space: nowrap;
}
.status-dot { width: .55rem; height: .55rem; border-radius: 50%; background: currentColor; flex: none; }
.status-connecting .status-dot { animation: hud-pulse 1.2s ease-in-out infinite; }
.status-connected { color: var(--ac-ok); }
.status-disconnected { color: var(--ac-danger); }
.status-connecting { color: var(--ac-accent); }

.v-identity { order: 2; display: flex; flex-direction: column; gap: 0; line-height: 1.1; min-width: 0; }
.v-name { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 14rem; }
.v-sub { font-size: .7rem; white-space: nowrap; }

.v-bars { order: 3; display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px; flex: 1 1 240px; min-width: 200px; }
.v-res { order: 4; display: flex; align-items: center; gap: 14px; }
.v-stat { display: flex; flex-direction: column; align-items: flex-end; line-height: 1.1; font-size: .82rem; font-weight: 700; color: var(--hud-gold); white-space: nowrap; }
.v-stat-label { font-size: .56rem; text-transform: uppercase; letter-spacing: .06em; color: var(--ac-dim); font-weight: 600; }

.v-targets { order: 4; display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.v-tgt { font-size: .7rem; font-weight: 700; padding: 1px 8px; border-radius: 999px; border: 1px solid; max-width: 12rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.v-tgt.hostile { color: var(--hud-hostile); border-color: rgba(214, 75, 75, .5); background: var(--ac-danger-wash); }
.v-tgt.friendly { color: var(--hud-friendly); border-color: rgba(76, 187, 23, .5); background: var(--ac-ok-wash); }
/* The hostile chip is a button (tap = cycle); keep the pill look. */
button.v-tgt { font-family: inherit; margin: 0; cursor: pointer; }
button.v-tgt:hover { border-color: rgba(214, 75, 75, .8); }
/* Target-of-target readout beside the Foe bar: who your foe is swinging at. */
.v-foe-tgt { flex: none; font-size: .7rem; color: var(--ac-dim); white-space: nowrap; align-self: center; }
.v-foe-tgt.you { color: var(--hud-hostile); font-weight: 700; }

.topbar-actions { order: 5; display: flex; gap: 6px; margin-left: auto; }

.v-world {
    order: 6; flex-basis: 100%;
    display: flex; align-items: center; gap: 10px;
    font-size: .76rem; white-space: nowrap;
    overflow-x: auto; scrollbar-width: none;
}
.v-world::-webkit-scrollbar { display: none; }
.v-clock { color: var(--ac-text); white-space: nowrap; }
.v-season { color: var(--ac-accent); font-weight: 700; white-space: nowrap; padding: 1px 8px; border: 1px solid rgba(255, 170, 119, .45); background: var(--ac-wash); border-radius: 999px; cursor: pointer; }
.v-season:hover { border-color: var(--ac-accent); color: var(--ac-accent-2); }
.v-season:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 2px; }
.v-event { color: var(--hud-event); white-space: nowrap; }
.v-moons { display: inline-flex; align-items: center; gap: 5px; }
.v-moon { color: var(--hud-moon); font-weight: 700; font-size: 1.05em; line-height: 1; cursor: default; }
.v-moon.is-down { color: var(--hud-moon-down); }

@media (max-width: 767.98px) {
    #hud-topbar { gap: 8px; }
    .status-text, .v-res, .v-world, .v-targets, .ui-toggle-label,
    .topbar-actions .col-toggle { display: none; }
    .v-name { max-width: 9rem; }
    .v-bars { order: 6; flex-basis: 100%; min-width: 0; flex-wrap: wrap; gap: 6px; }
}

/* ----- Vitals / XP bars ----- */
.vbar { display: flex; align-items: center; gap: 5px; flex: 1 1 110px; min-width: 110px; max-width: 260px; }
.vbar-label { font-size: .7rem; font-weight: 700; color: var(--ac-dim); width: 26px; }
.vbar-track {
    position: relative; flex: 1; height: 16px;
    background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: 3px; overflow: hidden;
}
.vbar-fill { position: absolute; inset: 0 auto 0 0; height: 100%; transition: width .2s ease; opacity: .85; }
.vbar.hp .vbar-fill { background: var(--hud-hp); }
.vbar.mp .vbar-fill { background: var(--hud-mp); }
.vbar.mv .vbar-fill { background: var(--hud-mv); }
.vbar.tgt .vbar-fill { background: var(--hud-tgt); }
.vbar.mm .vbar-fill { background: var(--hud-mm); }
.vbar.edge .vbar-fill { background: var(--hud-edge); }
.vbar-text {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    font-size: .68rem; font-weight: 700; text-shadow: 0 0 2px #000, 0 0 2px #000;
}
@media (max-width: 767.98px) {
    .vbar { min-width: 96px; }
    .vbar-track { height: 14px; }
}

/* Hunger / thirst reserve icon riding the end of the HP (food) and MV (water)
   bars. Quiet and dim when the reserve is healthy; it warms to amber as it
   runs low and reddens when the game would warn you're "very hungry/thirsty",
   so it only pulls the eye when there's something to act on. */
.vbar-reserve { flex: 0 0 auto; display: inline-flex; align-items: center; line-height: 0; }
.vbar-reserve-icon { width: .82rem; height: .82rem; }
.vbar-reserve[data-state="ok"]   { color: var(--ac-dim); opacity: .65; }
.vbar-reserve[data-state="low"]  { color: var(--hud-edge); opacity: 1; }
.vbar-reserve[data-state="crit"] { color: var(--ac-danger); opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
    .vbar-reserve[data-state="crit"] { animation: reserve-pulse 1.5s ease-in-out infinite; }
    @keyframes reserve-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
}

/* ----- Left column: scrolling stack + pinned compass rose ----- */
#hud-left {
    display: flex; flex-direction: column; gap: 6px;
    min-height: 0; overflow: hidden;
}
#hud-left-scroll {
    flex: 1 1 auto; min-height: 0;
    overflow-y: auto; overflow-x: hidden;
    display: flex; flex-direction: column; gap: 6px; padding-right: 2px;
}
#panel-room.panel-rose { flex: 0 0 auto; }

/* ----- Panels ----- */
.panel {
    background: var(--ac-panel); border: 1px solid var(--ac-border);
    border-radius: var(--ac-radius-sm); padding: 0;
}
/* Collapsible header: a container row with a toggle button + optional actions. */
.panel-h {
    display: flex; align-items: center; gap: 4px; width: 100%;
    border-bottom: 1px solid var(--ac-border);
}
.panel-h-toggle {
    flex: 1; min-width: 0;
    display: flex; align-items: center; gap: 5px;
    font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
    color: var(--ac-accent);
    background: none; border: 0; padding: 6px 8px; margin: 0; cursor: pointer; text-align: left;
}
.panel-h-toggle:hover { color: var(--ac-accent-2); }
.panel-caret { flex: none; width: .8rem; font-size: .7rem; color: var(--ac-dim); }
.panel-h-title { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.panel-h-actions { flex: none; display: flex; gap: 4px; padding-right: 6px; }
.panel-h-btn {
    font-size: .64rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
    padding: 2px 7px; cursor: pointer;
    background: var(--ac-elev); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: 3px;
}
.panel-h-btn:hover { border-color: var(--ac-accent); color: var(--ac-accent); }
/* Panel bodies get the inner padding the header spans full-bleed over. */
.panel > *:not(.panel-h):not(.rose-head):not(.rose-body) { margin-left: 8px; margin-right: 8px; }
.panel > ul.row-list, .panel > ul.kv, .panel > ul.aff-list, .panel > ul.grp-list,
.panel > ul.who-list, .panel > ul.occ-list { margin-top: 5px; margin-bottom: 6px; }
.panel > .panel-empty { margin: 6px 8px; }

.sub-h { font-size: .68rem; font-weight: 700; color: var(--ac-dim); text-transform: uppercase; margin: 7px 8px 3px; }
.sub-h.collapse {
    display: flex; align-items: center; gap: 4px; width: calc(100% - 16px);
    background: none; border: 0; cursor: pointer; text-align: left; padding: 4px 0;
}
.sub-h.collapse:hover { color: var(--ac-text); }
.panel-empty { color: var(--ac-dim); font-size: .8rem; font-style: italic; padding: 2px 0; }
.dim { color: var(--ac-dim); font-size: .82em; }
.tag { font-size: .68rem; color: var(--ac-dim); background: var(--ac-bg); border-radius: 3px; padding: 0 4px; }
.tag.cond-ok { color: var(--ac-ok); }
.tag.cond-mid { color: var(--hud-edge); }
.tag.cond-low { color: var(--ac-danger); }

/* ----- Center column ----- */
/* min-width:0 stops the terminal cell from being sized by its content's
   intrinsic width (grid/flex children default to min-width:auto), which would
   let a wide line push the whole column past the viewport and drag the
   tap-to-move overlay off-screen with it. */
#hud-center { display: flex; flex-direction: column; gap: 6px; min-height: 0; min-width: 0; }
#terminal-wrapper { position: relative; flex: 1; min-height: 0; min-width: 0; overflow: hidden; }
#terminal-container { height: 100%; background: #000; border-radius: var(--ac-radius-sm); overflow: hidden; }
#terminal-container .xterm { height: 100%; padding: 4px; }
#command-form { display: flex; gap: 8px; align-items: center; position: relative; }
#command-input { flex: 1; font-family: monospace; font-size: 16px; padding: 6px 8px; }
#send-btn { flex: none; }
#history-btn { flex: none; }
#scroll-bottom-btn { position: absolute; bottom: 8px; right: 12px; z-index: 10; opacity: .9; font-size: .8rem; }
@media (max-width: 767.98px) {
    #command-form { gap: 6px; }
    .send-label { display: none; }
}

/* Recent-commands popover + gear settings popover. */
#history-pop {
    position: absolute; left: 0; right: 0; bottom: calc(100% + 6px);
    max-height: 40vh; overflow-y: auto; z-index: 1030; padding: 4px;
    background: var(--ac-panel); border: 1px solid var(--ac-border-2);
    border-radius: var(--ac-radius); box-shadow: 0 -10px 30px rgba(0, 0, 0, .55);
}
.hist-item {
    display: block; width: 100%; text-align: left; cursor: pointer;
    background: none; border: 0; color: var(--ac-text);
    font-family: monospace; font-size: .9rem; padding: 8px 10px;
    border-radius: var(--ac-radius-sm);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hist-item:hover { background: var(--ac-elev); }
.hist-item:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: -2px; }
.hist-empty { color: var(--ac-dim); font-size: .8rem; font-style: italic; padding: 8px 10px; }
@media (pointer: coarse) { .hist-item { min-height: 44px; } }

#term-search {
    position: absolute; top: 8px; right: 12px; z-index: 20;
    display: flex; gap: 4px; align-items: center; padding: 4px;
    background: var(--ac-panel); border: 1px solid var(--ac-border-2);
    border-radius: var(--ac-radius-sm); box-shadow: 0 6px 20px rgba(0, 0, 0, .55);
    max-width: calc(100% - 24px);
}
#term-search[hidden] { display: none; }
#term-search-input {
    width: 200px; max-width: 40vw; min-width: 0;
    font-family: monospace; font-size: 16px; padding: 4px 8px;
    background: var(--ac-bg); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
#term-search-input:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: -1px; }

#settings-pop {
    position: absolute; top: calc(100% + 4px); right: 0; z-index: 1030;
    min-width: 260px; padding: 6px;
    background: var(--ac-panel); border: 1px solid var(--ac-border-2);
    border-radius: var(--ac-radius); box-shadow: 0 10px 30px rgba(0, 0, 0, .55);
}
.setting-row {
    display: flex; gap: 10px; align-items: center; cursor: pointer;
    padding: 8px 10px; border-radius: var(--ac-radius-sm);
    font-size: .85rem; color: var(--ac-text);
}
.setting-row:hover { background: var(--ac-elev); }
.setting-row input { flex: none; margin: 0; }
.setting-row input:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 2px; }
@media (pointer: coarse) { .setting-row { min-height: 44px; } }

/* Grouped settings (e.g. the notifications cluster) under a small heading. */
.setting-group { margin-top: 4px; padding-top: 2px; border-top: 1px solid var(--ac-border); }
.setting-group-h {
    padding: 6px 10px 2px; font-size: .7rem; font-weight: 700;
    letter-spacing: .04em; text-transform: uppercase; color: var(--ac-dim);
}
/* A row that mixes a checkbox with an inline numeric control — not a single
   label, so its own cursor stays a default and each control labels itself. */
.setting-row-inline { cursor: default; flex-wrap: wrap; }
.setting-row-inline label { cursor: pointer; }
.setting-num {
    width: 3.6em; flex: none; text-align: right;
    font-family: monospace; font-size: .85rem; padding: 3px 6px;
    background: var(--ac-bg); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.setting-num:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 1px; }
.setting-suffix { color: var(--ac-dim); }

/* ----- Compass rose (bottom-left desktop) ----- */
.rose-head { display: flex; align-items: flex-start; gap: 6px; padding: 6px 8px 2px; line-height: 1.2; }
.rose-titles { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; }
.rose-name { font-size: .74rem; font-weight: 700; color: var(--ac-accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rose-area { font-size: .68rem; }
.rose-body { padding: 2px 8px 8px; }
/* Rose | Map micro-tabs in the pinned Room panel header. */
.rose-tabs { display: flex; gap: 2px; flex: 0 0 auto; }
.rose-tabs button {
    border: 1px solid var(--ac-border); background: var(--ac-bg); color: var(--ac-dim);
    border-radius: 3px; font-size: .64rem; font-weight: 700; padding: 2px 6px;
    cursor: pointer; line-height: 1.4;
}
.rose-tabs button:hover { border-color: var(--ac-accent); color: var(--ac-text); }
.rose-tabs button.active { background: var(--ac-elev); color: var(--ac-accent); border-color: var(--ac-border-2); }
.rose-tabs button:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 1px; }

/* ----- Minimap (Map tab of the Room panel) ----- */
.map-mini { position: relative; height: 178px; }
.map-mini .map-canvas { display: block; width: 100%; height: 100%; border-radius: 3px; background: var(--ac-bg); }
.map-mini.unseen .map-canvas { opacity: .35; }
.map-hint {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    color: var(--ac-dim); font-size: .7rem; pointer-events: none;
}
.map-hint[hidden] { display: none; }
/* Current room's note under the rose/minimap: one quiet clamped line. */
.rose-note {
    display: block; width: calc(100% - 16px); margin: 0 8px 8px; padding: 3px 6px;
    text-align: left; font-size: .66rem; color: var(--ac-dim);
    background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: 3px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; cursor: pointer;
}
.rose-note:hover { color: var(--ac-text); border-color: var(--ac-border-2); }

/* ----- Big map overlay (OVERLAYS app "map", Ctrl+M) ----- */
#hud-overlay[data-app="map"] { width: min(920px, calc(100vw - 32px)); max-height: min(84vh, 760px); }
/* Character overlay is two columns on desktop, so it wants more width. */
#hud-overlay[data-app="train"] { width: min(720px, calc(100vw - 32px)); }
.map-app { display: flex; flex-direction: column; min-height: 0; }
.map-toolbar { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 2px 0 8px; }
.map-zone {
    font-size: .72rem; font-weight: 700; color: var(--ac-accent);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 40%;
}
/* Cross-zone: the map is looking at a neighbor, not the player's zone. */
.map-zone.offzone::after {
    content: " · viewing"; color: var(--ac-dim); font-weight: 400;
}
/* The zone picker is the signposted way across a border — tint it accent. */
.map-zones { color: var(--ac-accent); }
/* Jump-to-marker (last death / group-mate) shares the accent-tint signposting. */
.map-jump { color: var(--ac-accent); }
.map-jump[hidden] { display: none; }
.map-z { display: inline-flex; gap: 2px; }
.map-search {
    flex: 1 1 8rem; min-width: 6rem; max-width: 14rem; font-size: 16px;
    padding: 3px 8px; background: var(--ac-bg); color: var(--ac-text);
    border: 1px solid var(--ac-border-2); border-radius: var(--ac-radius-sm);
}
.map-search:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 1px; }
.map-count { font-size: .68rem; min-width: 2.2em; }
.map-btn {
    border: 1px solid var(--ac-border); background: var(--ac-elev); color: var(--ac-text);
    border-radius: 3px; font-size: .74rem; font-weight: 700; padding: 3px 9px; cursor: pointer;
}
.map-btn:hover { border-color: var(--ac-accent); color: var(--ac-accent); }
.map-btn.active { color: var(--ac-accent); border-color: var(--ac-accent); }
.map-btn:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 1px; }
.map-big { position: relative; height: min(62vh, 560px); min-height: 220px; }
.map-big .map-canvas {
    display: block; width: 100%; height: 100%; border-radius: 3px;
    background: var(--ac-bg); touch-action: none; cursor: grab;
}
.map-tip-anchor { position: absolute; pointer-events: none; visibility: hidden; }
/* In the phone sheet the map shares the viewport with the dock. */
#hud-sheet .map-big { height: 46vh; }

/* Note editor popover (above the overlay window, below #hud-menu's tier). */
.map-note-pop {
    position: fixed; z-index: 1039; left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(340px, calc(100vw - 32px));
    display: flex; flex-direction: column; gap: 8px; padding: 10px;
    background: var(--ac-panel); border: 1px solid var(--ac-border-2);
    border-radius: var(--ac-radius); box-shadow: 0 16px 44px rgba(0, 0, 0, .6);
}
.map-note-pop[hidden] { display: none; }
.note-title { font-size: .72rem; font-weight: 700; color: var(--ac-accent); }
.note-text {
    font-size: 16px; padding: 6px 8px; resize: vertical; min-height: 5.5em;
    background: var(--ac-bg); color: var(--ac-text);
    border: 1px solid var(--ac-border-2); border-radius: var(--ac-radius-sm);
}
.note-text:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 1px; }
.note-actions { display: flex; gap: 6px; justify-content: flex-end; }
.note-del { color: var(--ac-danger); }

/* Zone picker popover — a filterable list of adjacent + explored zones. Sits
   on the note-editor's tier, above the overlay window. */
.map-zone-pop {
    position: fixed; z-index: 1039;
    width: min(300px, calc(100vw - 16px));
    display: flex; flex-direction: column; gap: 6px; padding: 8px;
    background: var(--ac-panel); border: 1px solid var(--ac-border-2);
    border-radius: var(--ac-radius); box-shadow: 0 16px 44px rgba(0, 0, 0, .6);
}
.map-zone-pop[hidden] { display: none; }
.zone-pick-head { display: flex; gap: 6px; align-items: center; }
.zone-pick-search { flex: 1 1 auto; max-width: none; }
.zone-pick-list {
    display: flex; flex-direction: column; gap: 1px;
    max-height: min(46vh, 320px); overflow-y: auto;
}
/* overflow:hidden on a row zeroes its automatic min-height, so without this the
   flex column shrinks rows to fit the cap — squashing names — instead of
   scrolling. Children keep their natural height; the list scrolls. */
.zone-pick-h, .zone-pick-row, .zone-pick-empty { flex-shrink: 0; }
.zone-pick-h {
    font-size: .62rem; font-weight: 700; letter-spacing: .05em;
    text-transform: uppercase; color: var(--ac-dim);
    padding: 6px 4px 2px; position: sticky; top: 0; background: var(--ac-panel);
}
.zone-pick-row {
    text-align: left; padding: 7px 8px; cursor: pointer;
    font-size: .74rem; color: var(--ac-text);
    background: transparent; border: 0; border-radius: var(--ac-radius-sm);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.zone-pick-row:hover { background: var(--ac-elev); color: var(--ac-accent); }
.zone-pick-row:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: -2px; }
.zone-pick-empty { padding: 10px 4px; font-size: .72rem; color: var(--ac-dim); }
@media (pointer: coarse) {
    .zone-pick-row { padding: 11px 8px; }
}

/* Overlay footer: show-path step list / walking progress. */
.map-foot {
    display: flex; align-items: center; gap: 8px; padding: 8px 0 2px;
    font-size: .72rem; color: var(--ac-text); flex-wrap: wrap;
}
.map-foot[hidden] { display: none; }

/* Autowalk cancel chip, pinned above the action row. The whole chip is
   the cancel button (44px coarse target) — player control in one tap. */
.map-walk {
    display: block; width: 100%; min-height: 30px; margin: 4px 0 0;
    padding: 5px 10px; text-align: center; cursor: pointer;
    font-size: .72rem; font-weight: 700; color: var(--ac-accent-2);
    background: var(--ac-wash); border: 1px solid var(--ac-accent);
    border-radius: var(--ac-radius-sm);
}
.map-walk[hidden] { display: none; }
.map-walk:hover { background: var(--ac-elev); }
.map-walk:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 1px; }

@media (pointer: coarse) {
    .rose-tabs button, .map-btn { padding: 8px 12px; }
    .rose-note { padding: 8px; }
    .map-walk { min-height: 44px; }
}
.compass {
    display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px;
    max-width: 170px; margin: 0 auto;
}
.exit {
    border: 1px solid var(--ac-border); background: var(--ac-elev); color: var(--ac-text);
    border-radius: 3px; font-size: .72rem; font-weight: 700; padding: 5px 0; cursor: pointer;
}
.exit:hover { border-color: var(--ac-accent); color: var(--ac-accent); }
/* Absent exit: still drawn (fixed layout) but clearly inactive. */
.exit.none { color: var(--ac-dim); background: var(--ac-bg); border-color: var(--ac-border); cursor: default; opacity: .4; }
.exit.hub { color: var(--ac-dim); cursor: default; }
.ud-row, .named-row { display: flex; gap: 4px; justify-content: center; margin-top: 5px; flex-wrap: wrap; }
/* Reserve the named-exit row's height so its presence/absence doesn't move the
   fixed compass above it (the panel is pinned to the column bottom). */
.named-row { min-height: 1.9rem; align-items: center; }
.exit.ud, .exit.named { padding: 4px 8px; }

/* ----- Mobile tap-to-move rose overlay ----- */
#rose-overlay {
    position: absolute; top: 6px; left: 50%; transform: translateX(-50%);
    z-index: 15; padding: 4px;
    background: rgba(12, 12, 13, .35);
    border: 1px solid rgba(255, 170, 119, .25); border-radius: var(--ac-radius-sm);
    opacity: .42; transition: opacity .15s ease;
}
#rose-overlay[hidden] { display: none; }
#rose-overlay:focus-within, #rose-overlay:active { opacity: .96; }
#rose-overlay .compass.overlay { max-width: none; grid-template-columns: repeat(3, 30px); gap: 2px; }
#rose-overlay .exit {
    padding: 6px 0; font-size: .68rem; background: rgba(28, 28, 34, .8);
    border-color: rgba(255, 255, 255, .12);
}
#rose-overlay .exit.none { color: var(--ac-dim); background: rgba(28, 28, 34, .4); border-color: rgba(255, 255, 255, .06); opacity: .5; }
#rose-overlay .exit.hub { background: transparent; border-color: transparent; }
#rose-overlay .ud-row { margin-top: 2px; gap: 2px; }
#rose-overlay .exit.ud { padding: 5px 8px; font-size: .64rem; }
#rose-toggle {
    position: absolute; top: 6px; right: 6px; z-index: 16;
    display: none; opacity: .6;
}
#rose-toggle[aria-pressed="true"] { color: var(--ac-accent); opacity: .85; }
@media (max-width: 767.98px) {
    #connect-app.hud-on #rose-toggle { display: inline-flex; }
}

/* ----- Occupants ----- */
.occ-list { list-style: none; margin: 0; padding: 0; }
.occ-row {
    display: flex; align-items: center; gap: 6px; padding: 4px 4px; border-radius: 3px;
    cursor: pointer; font-size: .82rem; border-left: 3px solid transparent;
}
.occ-row:hover { background: var(--ac-elev); }
.occ-row.hostile { border-left-color: var(--hud-hostile); }
.occ-row.friendly { border-left-color: var(--hud-friendly); }
.occ-row.neutral { border-left-color: var(--ac-border-2); }
.occ-row.is-dead { opacity: .5; cursor: default; }
/* The ⚔ target's row — the Alt+T cycle is legible in the panel, not just the chip. */
.occ-row.is-tgt { background: var(--ac-danger-wash); }
.occ-icon { flex: none; width: 1rem; text-align: center; color: var(--ac-dim); }
.occ-row.hostile .occ-icon { color: var(--hud-hostile); }
.occ-row.friendly .occ-icon { color: var(--hud-friendly); }
.occ-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.occ-marks { flex: none; color: var(--ac-accent); font-size: .78rem; }
.occ-shop { flex: none; color: var(--hud-gold); font-weight: 700; font-size: .78rem; }
.occ-loyal { flex: none; color: var(--hud-friendly); font-size: .78rem; }
.occ-pos { flex: none; color: var(--ac-dim); font-size: .68rem; font-style: italic; }
.occ-fight { flex: none; color: var(--ac-dim); font-size: .68rem; }
.occ-fight.you { color: var(--hud-hostile); font-weight: 700; }
.tgt-chips { display: flex; flex-wrap: wrap; gap: 4px; margin: 5px 0 2px; }
.tgt-chip {
    font-size: .68rem; font-weight: 700; padding: 1px 7px; border-radius: 999px;
    border: 1px solid; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tgt-chip.hostile { color: var(--hud-hostile); border-color: rgba(214, 75, 75, .5); background: var(--ac-danger-wash); }
.tgt-chip.friendly { color: var(--hud-friendly); border-color: rgba(76, 187, 23, .5); background: var(--ac-ok-wash); }

/* Trailing "⋯" actions button on any interactive row. */
.row-more {
    flex: none; background: none; border: 0; color: var(--ac-dim);
    font-weight: 700; cursor: pointer; padding: 0 4px; line-height: 1; border-radius: 3px;
}
.row-more:hover { color: var(--ac-accent); background: var(--ac-bg); }

/* ----- Generic rows (equipment / inventory) ----- */
/* The row class is `.item-row`, NOT `.row`: Bootstrap's grid `.row` is loaded
   globally, and its `.row > * { width: 100% }` would stack every cell (slot,
   name, condition, ⋯) onto its own line. flex-wrap:nowrap keeps a row a row. */
.row-list { list-style: none; margin: 0; padding: 0; }
.row-list.sub { margin: 1px 0 3px 14px; }
.item-row {
    display: flex; align-items: center; gap: 6px; padding: 3px 4px; border-radius: 3px;
    cursor: pointer; font-size: .82rem; flex-wrap: nowrap;
}
.item-row:hover { background: var(--ac-elev); }
.item-row.sub { font-size: .78rem; color: var(--ac-dim); }
.item-row.comp { color: var(--ac-text); }
.row-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slot { color: var(--ac-dim); font-size: .68rem; width: 56px; flex: none; text-transform: capitalize; }

/* Condition as a single colour-coded dot (numeric % lives in the title).
   Fixed width so it shares the lead column with a container's expand caret,
   keeping item names aligned down the list. */
.cond-dot { flex: none; width: .9rem; text-align: center; font-size: .55rem; line-height: 1; color: var(--ac-dim); }
.cond-dot.cond-ok { color: var(--ac-ok); }
.cond-dot.cond-mid { color: var(--hud-edge); }
.cond-dot.cond-low { color: var(--ac-danger); }

/* Expand caret on an open container row; toggles its contents (packs start
   collapsed). Shares the lead column's width with .cond-dot. */
.row-caret {
    flex: none; width: .9rem; padding: 0; background: none; border: 0;
    color: var(--ac-dim); cursor: pointer; font-size: .7rem; line-height: 1; text-align: center;
}
.row-caret:hover { color: var(--ac-accent); }
/* Container state glyph (🔒 / 📦) for a closed or empty container. */
.row-glyph { flex: none; color: var(--ac-dim); font-size: .82em; }

/* Ground items + harvest nodes (Room.Contents) in the Room panel. The lead
   icon shares the caret/dot column width so names align; the harvest chip
   ("⛏ rN") takes the standard tier-* text colors. */
.gnd-icon { flex: none; width: .9rem; text-align: center; font-size: .72rem; line-height: 1; color: var(--ac-dim); }
.gnd-icon.corpse { color: var(--ac-danger); }
.gnd-icon.node { color: var(--ac-accent); }
.tag.harvest { background: var(--ac-bg); }
.tag.harvest.tier-open { color: var(--ac-ok); }
.tag.dim { color: var(--ac-dim); }
.coins { margin: 5px 8px; font-size: .78rem; color: var(--hud-gold); }
.comp-section { margin-top: 2px; }

/* Inline pin chip on a consumable row: ☆ pins to the action bar, ★ is pinned. */
.item-pin {
    flex: none; background: none; border: 1px solid transparent; color: var(--ac-dim);
    cursor: pointer; padding: 0 4px; line-height: 1; border-radius: 3px; font-size: .82em;
}
.item-pin:hover { color: var(--ac-accent); border-color: rgba(255, 170, 119, .4); }
.item-pin.on { color: var(--hud-gold); }

/* ----- Bags overlay: aggregated worn + carried storage ----- */
/* Each container is a card — a tappable header (its own open/close/get-all
   menu) tagged by provenance ("worn: Back" / "carried"), over its contents or a
   locked/closed note. Loose carried items follow under a "Loose in inventory"
   sub-head. See decisions.md 2026-07-19 (HUD Bags overlay). */
.bag { border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm); margin-bottom: 8px; overflow: hidden; }
.bag-h {
    display: flex; align-items: center; gap: 7px; width: 100%; padding: 6px 8px;
    background: var(--ac-elev); border: 0; text-align: left; font: inherit;
    color: var(--ac-text); cursor: pointer;
}
.bag-h:hover { background: var(--ac-panel); }
.bag-ic { flex: none; color: var(--ac-dim); font-size: .82rem; line-height: 1; }
.bag-nm { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 700; font-size: .8rem; }
.bag-prov { flex: none; font-size: .6rem; padding: 1px 5px; border-radius: 3px; border: 1px solid var(--ac-border-2); color: var(--ac-dim); }
.bag-prov.worn { color: var(--hud-event); border-color: rgba(232, 176, 75, .4); }
.bag-lock { flex: none; font-size: .66rem; color: var(--ac-warn); white-space: nowrap; }
.bag .row-list { padding: 2px 6px 4px; }
.bag-items { list-style: none; margin: 0; padding: 4px 8px; }
.bag-items li.dim { color: var(--ac-dim); font-style: italic; font-size: .78rem; padding: 2px 0; }

/* ----- Character overlay: worn gear beside the stat sheet -----
   Mobile-first: one stacked column (the phone sheet). At the desktop
   breakpoint the two columns sit side by side with a divider between them. */
/* minmax(0,…) lets the track shrink below content so long gear names ellipsis
   instead of forcing the panel wider than the phone sheet. */
.char-cols { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }
.char-h {
    margin: 0 0 6px; font-size: .68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .08em; color: var(--ac-dim);
}
@media (min-width: 768px) {
    .char-cols { grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr); column-gap: 20px; align-items: start; }
    .char-col:first-child { border-right: 1px solid var(--ac-border); padding-right: 20px; }
}

/* ----- Key/value lists (train / status) ----- */
.kv { list-style: none; margin: 0; padding: 0; }
.kv li { display: flex; justify-content: space-between; font-size: .8rem; padding: 2px 0; border-bottom: 1px dotted var(--ac-border); }
.kv li span:first-child { color: var(--ac-dim); }
.action-btn {
    display: block; width: calc(100% - 16px); margin: 5px 8px; padding: 5px; cursor: pointer;
    background: var(--hud-gold-wash); color: var(--hud-gold); border: 1px solid var(--hud-gold); border-radius: 3px; font-weight: 700; font-size: .78rem;
}

/* ----- Right column (desktop): Tracked Spells over Chat, no tab bar ----- */
#hud-right { display: flex; flex-direction: column; gap: 6px; min-height: 0; }
/* Chat fills the column below Tracked Spells: a flex stack of header · filter
   tabs · scrolling log · input. The inner .chat-log is the scroll container
   (appendChat pins to its scrollTop); collapsed, the pane shrinks to its head.
   flex-basis 0 (not auto) is load-bearing: it makes Chat size to the *leftover*
   space, not to its message history — otherwise a long log inflates Chat's basis
   and the flex-shrink split lets it crowd Tracked Spells below its 42% cap. */
#hud-right .panel-chat { flex: 1 1 0; min-height: 0; display: flex; flex-direction: column; }
#hud-right .panel-chat.collapsed { flex: 0 0 auto; }
/* Tracked Spells is pinned above Chat (order, since placePanels can't preserve
   DOM order across a phone↔desktop swap) and height-capped so a long maintained
   list scrolls rather than crowding Chat out. */
#hud-right .panel-tracked {
    order: -1; flex: 0 1 auto; min-height: 0; max-height: 42%;
    display: flex; flex-direction: column;
}
#hud-right .panel-tracked > .aff-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; }

/* ----- Abilities browser (bounded, searchable) ----- */
#panel-abilities { padding: 6px; }
.ab-controls { flex: none; margin-bottom: 5px; }
/* Search box + filter chips — shared by the abilities overlay and the
   professions recipe browser so the two filter surfaces read identically. */
.ab-search, .recipe-search {
    width: 100%; font-size: 16px; padding: 5px 8px;
    background: var(--ac-bg); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.ab-search:focus-visible, .recipe-search:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: -1px; }
.ab-chips, .recipe-chips { flex: none; display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.ab-chip, .recipe-chip {
    font-size: .66rem; font-weight: 700; padding: 3px 9px; cursor: pointer;
    background: var(--ac-panel); color: var(--ac-dim);
    border: 1px solid var(--ac-border); border-radius: 999px;
}
.ab-chip:hover, .recipe-chip:hover { border-color: var(--ac-accent); color: var(--ac-accent); }
.ab-chip.on, .recipe-chip.on { color: var(--ac-accent); border-color: var(--ac-accent); background: var(--ac-wash); }
.ab-chip.ab-fav { color: var(--hud-gold); }
.ab-chip.ab-fav.on { color: var(--hud-gold); border-color: var(--hud-gold); background: var(--hud-gold-wash); }
.ab-chip.ab-usable.on,
.recipe-chip.avail.on { color: var(--ac-ok); border-color: rgba(76, 187, 23, .5); background: var(--ac-ok-wash); }
.ab-scroll { flex: 1; min-height: 0; overflow-y: auto; }
.ab-list { list-style: none; margin: 0; padding: 0; }
.ab-row {
    display: flex; align-items: center; gap: 6px; padding: 5px 6px; border-radius: 3px;
    cursor: pointer; font-size: .82rem; border-left: 3px solid transparent;
}
.ab-row:hover { background: var(--ac-elev); }
.ab-row.off { opacity: .5; }
.ab-row.cat-damage { border-left-color: var(--ac-danger); }
.ab-row.cat-heal { border-left-color: var(--ac-ok); }
.ab-row.cat-misc { border-left-color: var(--ac-info); }
.ab-row.cat-skill { border-left-color: var(--ac-border-2); }
.ab-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ab-right { flex: none; display: flex; align-items: center; gap: 6px; }
.ab-block { font-size: .66rem; color: var(--ac-danger); font-variant-numeric: tabular-nums; }
.ab-pct { font-size: .68rem; color: var(--ac-dim); font-variant-numeric: tabular-nums; }
.ab-star { background: none; border: 0; color: var(--ac-dim); cursor: pointer; font-size: .9rem; padding: 0 2px; line-height: 1; }
.ab-star.on { color: var(--hud-gold); }
.ab-star:hover { color: var(--ac-accent); }
/* Passive / craft / enchant abilities: tagged and visibly non-activatable. */
.ab-type { font-size: .58rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ac-dim); background: var(--ac-bg); border-radius: 3px; padding: 0 5px; }
.ab-row.ab-passive .ab-name { color: var(--ac-dim); font-style: italic; }

/* ----- Tracked Spells (maintained magic; a persistent right-column panel) -----
   One row per spell you maintain: icon · name + target · timer · release,
   expiry-sorted. The target is colour-coded by relationship, and a row within
   AFFECT_SOON of dropping warms to the caution colour. */
.aff-list { list-style: none; margin: 0; padding: 0; }
.aff {
    display: flex; align-items: center; gap: 7px;
    font-size: .8rem; padding: 4px 6px; margin-bottom: 3px;
    border-left: 3px solid var(--ac-info); border-radius: 2px; background: var(--ac-elev);
}
.aff.soon { border-left-color: var(--ac-warn); background: rgba(255, 136, 0, .1); }
.aff-ic { flex: none; width: 20px; height: 20px; color: var(--ac-info); }
.aff-ic .gi { width: 20px; height: 20px; }
.aff-body { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.25; }
.aff-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aff-tgt { font-size: .68rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aff-tgt.self { color: var(--ac-dim); }
.aff-tgt.mate { color: var(--hud-group); }
.aff-tgt.foe  { color: var(--hud-tgt); }
.aff-time { flex: none; color: var(--ac-dim); font-size: .72rem; font-variant-numeric: tabular-nums; }
.aff.soon .aff-time { color: var(--ac-warn); font-weight: 700; }
.aff-rel {
    flex: none; font-size: .6rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
    padding: 2px 6px; cursor: pointer; color: var(--ac-dim);
    background: var(--ac-panel); border: 1px solid var(--ac-border-2); border-radius: 4px;
}
.aff-rel:hover { color: var(--ac-accent); border-color: var(--ac-accent); }

/* ----- Ambient self-affect strip (topbar, by the vitals) -----
   Bare icon tiles for the buffs/debuffs on you; a countdown chip appears and
   the tile pulses only within AFFECT_SOON of dropping, so a quest group's ~10
   buffs stay a compact wrapping row. Buff green, debuff red. */
.v-affects {
    order: 4; display: flex; flex-wrap: wrap; align-items: center; gap: 4px;
    padding-left: 8px; border-left: 1px solid var(--ac-border); max-width: 22rem;
}
.v-affects[hidden] { display: none; }
.self-aff {
    position: relative; flex: none; width: 26px; height: 26px;
    display: flex; align-items: center; justify-content: center;
    border: 1px solid var(--ac-border-2); border-radius: 5px; background: var(--ac-elev);
}
.self-aff .gi { width: 15px; height: 15px; }
.self-aff.buff   { color: var(--ac-ok);     border-color: rgba(76, 187, 23, .5);  background: var(--ac-ok-wash); }
.self-aff.debuff { color: var(--ac-danger); border-color: rgba(214, 75, 75, .5);  background: var(--ac-danger-wash); }
.self-aff-chip {
    position: absolute; bottom: -4px; right: -4px;
    font-size: .5rem; font-weight: 800; line-height: 1.3; padding: 0 2px;
    background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: 3px;
    color: var(--hud-event); font-variant-numeric: tabular-nums;
}
.self-aff.debuff .self-aff-chip { color: var(--ac-danger); border-color: rgba(214, 75, 75, .5); }
@media (max-width: 767.98px) {
    .v-affects { order: 7; flex-basis: 100%; max-width: none; padding-left: 0; border-left: 0; }
}
@media (prefers-reduced-motion: no-preference) {
    .self-aff.alarm { animation: self-aff-pulse 1.2s ease-in-out infinite; }
    @keyframes self-aff-pulse {
        0%, 100% { box-shadow: 0 0 0 0 rgba(232, 176, 75, 0); }
        50%      { box-shadow: 0 0 7px 1px rgba(232, 176, 75, .65); }
    }
}

/* ----- Group (the party pane) ----- */
.grp-list { list-style: none; margin: 0; padding: 0; }
.grp {
    display: flex; align-items: flex-start; gap: 6px; padding: 4px 4px;
    border-radius: 3px; cursor: pointer; border-left: 3px solid transparent;
}
.grp:hover { background: var(--ac-elev); }
.grp.grp-self { cursor: default; }
.grp.grp-self:hover { background: none; }
.grp.tanking { border-left-color: var(--hud-hostile); }
.grp-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.grp-line { display: flex; align-items: baseline; gap: 4px; min-width: 0; }
.grp-name { font-size: .8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* hp readout triage-tints like the in-game group display's condition colors */
.grp-hp-num { margin-left: auto; font-size: .72rem; color: var(--ac-dim); font-weight: 700; flex: none; }
.grp-hp-num.cond-ok { color: var(--ac-ok); }
.grp-hp-num.cond-mid { color: var(--hud-event); }
.grp-hp-num.cond-low { color: var(--hud-hostile); }
.grp-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.grp-chips > span {
    font-size: .64rem; padding: 0 5px; border-radius: 999px; border: 1px solid var(--ac-border);
    color: var(--ac-dim); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.grp-tank { color: var(--hud-hostile) !important; border-color: rgba(214, 75, 75, .5) !important; background: var(--ac-danger-wash); font-weight: 700; }
.grp-fight { color: var(--ac-text) !important; }
.grp-threat.threat-low { color: var(--ac-ok) !important; border-color: rgba(76, 187, 23, .5) !important; }
.grp-threat.threat-warn { color: var(--hud-event) !important; border-color: rgba(232, 176, 75, .5) !important; }
.grp-threat.threat-high { color: var(--hud-hostile) !important; border-color: rgba(214, 75, 75, .5) !important; }
.grp-bars { display: flex; gap: 2px; }
.mini { width: 26px; height: 7px; background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: 2px; overflow: hidden; display: inline-block; }
.mini span { display: block; height: 100%; }
.mini.hp span { background: var(--hud-hp); }
.mini.mp span { background: var(--hud-mp); }
.mini.mv span { background: var(--hud-mv); }

/* Compact (raid) group density — one scannable line per member: name · HP bar
   (triage-tinted) · % · one status marker · away. The header toggle (.grp-dens)
   flips it; low-HP/tank sort to the top and the list scrolls in-column so a
   full raid doesn't shove Here/Room off the side. */
.grp-dens.on { border-color: var(--ac-accent); color: var(--ac-accent); }
#hud-left-scroll .grp-cmp-list { max-height: 44vh; overflow-y: auto; }
.grp.grp-cmp { align-items: center; gap: 6px; padding: 3px 6px; }
.grp-cn { flex: 0 0 34%; max-width: 40%; font-size: .76rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.grp-cbar { flex: 1 1 auto; min-width: 24px; height: 11px; background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: 5px; overflow: hidden; }
.grp-cbar > span { display: block; height: 100%; background: var(--hud-hp); }
.grp-cbar > span.cond-ok { background: var(--ac-ok); }
.grp-cbar > span.cond-mid { background: var(--hud-event); }
.grp-cbar > span.cond-low { background: var(--hud-hostile); }
.grp-cp { flex: none; min-width: 32px; text-align: right; font-size: .7rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ac-dim); }
.grp-cp.cond-ok { color: var(--ac-ok); }
.grp-cp.cond-mid { color: var(--hud-event); }
.grp-cp.cond-low { color: var(--hud-hostile); }
.grp-ct { flex: none; font-size: .58rem; padding: 0 5px; border-radius: 999px; border: 1px solid var(--ac-border); color: var(--ac-dim); }
.grp-ct.mark-tank { color: var(--hud-hostile); border-color: rgba(214, 75, 75, .5); background: var(--ac-danger-wash); font-weight: 700; }
.grp-ct.mark-cc { color: var(--hud-event); border-color: rgba(232, 176, 75, .5); font-weight: 700; }
.grp-range { flex: none; font-size: .58rem; color: var(--ac-dim); }

/* ----- Who ----- */
.who-list { list-style: none; margin: 0; padding: 0; }
.who-row { padding: 4px 2px; border-bottom: 1px solid var(--ac-elev); }
.who-name { font-weight: 700; }
.who-title { font-size: .76rem; color: var(--ac-dim); font-style: italic; }
.who-act { display: flex; gap: 4px; margin-top: 3px; }
.who-act button { font-size: .68rem; padding: 2px 7px; cursor: pointer; background: var(--ac-elev); color: var(--ac-text); border: 1px solid var(--ac-border); border-radius: 3px; }
.who-act button:hover { border-color: var(--ac-accent); color: var(--ac-accent); }
.who-hidden { color: var(--ac-dim); font-size: .74rem; padding: 4px 2px; }

/* ----- Chat: filter tabs · colour-coded log · channel-targeted input ----- */
/* Filter tabs: a full-width segmented control (All / Public / Tells / Group),
   single-select. Same chip language as the abilities filter, laid out as equal
   segments rather than wrapping pills. */
.chat-tabs { flex: none; display: flex; gap: 3px; padding: 5px 6px; border-bottom: 1px solid var(--ac-border); }
.chat-tab {
    flex: 1 1 0; min-width: 0; padding: 3px 4px; cursor: pointer;
    font-size: .66rem; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
    background: var(--ac-panel); color: var(--ac-dim);
    border: 1px solid var(--ac-border); border-radius: 999px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.chat-tab:hover { border-color: var(--ac-accent); color: var(--ac-accent); }
.chat-tab.on { color: var(--ac-accent); border-color: var(--ac-accent); background: var(--ac-wash); }

.chat-log { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 6px 8px; font-size: .82rem; line-height: 1.35; }
.chat-line { padding: 1px 0; word-wrap: break-word; }
/* The channel tag is tinted by filter category, so a glance sorts the log even
   with All selected: public amber, tells violet, group teal. */
.chat-ch { font-weight: 700; }
.chat-ch.ch-public { color: var(--ac-accent); }
.chat-ch.ch-tells  { color: var(--hud-mm); }
.chat-ch.ch-group  { color: var(--hud-group); }
.chat-txt { color: var(--ac-text); }

/* Channel-targeted input: pick a channel, type, it routes without the verb. */
.chat-in { flex: none; display: flex; gap: 5px; align-items: center; padding: 5px 6px; border-top: 1px solid var(--ac-border); }
.chat-ch-select {
    flex: none; max-width: 38%; padding: 4px 6px; cursor: pointer;
    font-size: .72rem; font-weight: 700;
    background: var(--ac-bg); color: var(--ac-accent);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.chat-msg {
    flex: 1 1 auto; min-width: 0; padding: 5px 8px; font-size: 16px;
    background: var(--ac-bg); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.chat-ch-select:focus-visible, .chat-msg:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: -1px; }
/* Phone sheet: the sheet body scrolls, so bound the log's own height to keep the
   filter tabs and input on-screen instead of pushing the input off the sheet. */
#hud-sheet-body .chat-log { max-height: 42vh; }

/* ----- Action bar (WoW-style icon slots) ----- */
/* game-icons.net glyphs recolor via fill:currentColor (see the sprite at
   img/game-icons.svg + its ATTRIBUTION). Base sizing for the sprite <use>. */
.gi { fill: currentColor; display: block; width: 1em; height: 1em; }

/* Always a single horizontally-scrolling row — assigned slots can exceed the
   visible width, and the bar must never wrap into extra rows and eat terminal
   height. Numbered slots address hotkeys (Alt/Ctrl+1..0). */
#hud-hotbar { display: flex; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; gap: 5px; flex: none; padding: 1px 0; }
#hud-hotbar::-webkit-scrollbar { display: none; }
#hud-hotbar.empty { display: none; }

.skill {
    position: relative; flex: 0 0 auto; box-sizing: border-box;
    width: 46px; height: 46px; padding: 0; cursor: pointer; overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    background: var(--ac-elev); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-bottom: 2px solid var(--ac-border-2);
    border-radius: var(--ac-radius-sm);
    transition: border-color .12s ease, transform .12s ease, box-shadow .12s ease;
}
.skill:hover { border-color: var(--ac-accent); }
.skill .skill-icon { width: 30px; height: 30px; color: var(--ac-text); opacity: .92; pointer-events: none; }
/* Category colours the glyph (school-at-a-glance) + the bottom accent rule. */
.skill.cat-damage { border-bottom-color: var(--ac-danger); }
.skill.cat-heal   { border-bottom-color: var(--ac-ok); }
.skill.cat-misc   { border-bottom-color: var(--ac-info); }
.skill.cat-skill  { border-bottom-color: var(--ac-border-2); }
.skill.cat-damage .skill-icon { color: #e6836b; }
.skill.cat-heal   .skill-icon { color: #7fc99a; }
.skill.cat-misc   .skill-icon { color: #7fb2e6; }
.skill.cat-skill  .skill-icon { color: var(--ac-text); }

/* Slot number, top-left, on a small scrim so it reads over any glyph. */
.skill-key {
    position: absolute; top: 1px; left: 2px; z-index: 2;
    font-size: .6rem; font-weight: 700; line-height: 1;
    color: var(--ac-text); padding: 1px 3px; border-radius: 3px;
    background: rgba(0, 0, 0, .5); font-variant-numeric: tabular-nums; pointer-events: none;
}
/* Cooldown seconds / block reason, centred over a scrim. */
.skill-cd {
    position: absolute; inset: 0; z-index: 3; display: none;
    align-items: center; justify-content: center;
    font-size: .92rem; font-weight: 700; color: #fff; text-shadow: 0 1px 2px #000;
    background: rgba(0, 0, 0, .32); font-variant-numeric: tabular-nums; pointer-events: none;
}
.skill.cooling .skill-cd, .skill.blocked .skill-cd { display: flex; }
.skill.blocked .skill-cd { color: var(--ac-danger); font-size: .58rem; text-transform: uppercase; letter-spacing: .02em; padding: 0 2px; text-align: center; }
.skill.off { cursor: not-allowed; }
.skill.off .skill-icon { opacity: .4; }

/* Radial cooldown sweep: a darkened wedge that drains as the timer runs.
   --sweep is the remaining fraction as an angle (set by hud.js each tick). */
.skill-sweep {
    position: absolute; inset: 0; z-index: 1; display: none; pointer-events: none;
    border-radius: inherit;
    background: conic-gradient(from 0deg, rgba(6, 8, 12, .66) var(--sweep, 0deg), transparent 0);
}
.skill.sweeping .skill-sweep { display: block; }

/* Empty numbered slot — a faint drop/assign target (custom mode). */
.skill--empty { background: var(--ac-bg); border-style: dashed; opacity: .55; }
.skill--empty:hover { opacity: .9; border-color: var(--ac-accent); }
.skill--empty .skill-key { background: none; color: var(--ac-dim); top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: .8rem; }

/* Page toggle (bar 1/2) sits at the head of the row. */
.skill--pager { background: var(--ac-panel); border-bottom-color: var(--ac-accent); }
.skill--pager .skill-icon { width: 20px; height: 20px; color: var(--ac-accent); opacity: .85; }
.skill--pager .skill-key { top: auto; bottom: 1px; left: 50%; transform: translateX(-50%); background: none; color: var(--ac-accent); }

/* Lock toggle (leads the row). Locked = fire on tap; unlocked = edit mode. */
.skill--lock { background: var(--ac-panel); }
.skill--lock .skill-icon { width: 20px; height: 20px; color: var(--ac-dim); opacity: .9; }
.skill--lock.on { border-bottom-color: var(--ac-accent); }
.skill--lock.on .skill-icon { color: var(--ac-accent); }

/* Item slots (pinned consumables): the same chrome, a gold accent + glyph to
   read distinct from a skill, and a live count badge (bottom-right) that greys
   the tile via .off at zero stock. */
.skill--item { border-bottom-color: var(--hud-gold); }
.skill--item .skill-icon { color: var(--hud-gold); }
.skill-count {
    position: absolute; bottom: 1px; right: 2px; z-index: 2;
    font-size: .6rem; font-weight: 700; line-height: 1;
    color: var(--ac-text); padding: 1px 3px; border-radius: 3px;
    background: rgba(0, 0, 0, .5); font-variant-numeric: tabular-nums; pointer-events: none;
}
.skill-count[hidden] { display: none; }
.skill--item.off .skill-count { color: var(--ac-danger); }

/* Edit mode: taps rearrange (they don't fire), so signal it — grab cursors and
   a highlighted "picked" slot waiting for its destination. */
#hud-hotbar.editing .skill[data-ability], #hud-hotbar.editing .skill[data-item-slot],
#hud-hotbar.editing .skill--empty { cursor: grab; }
#hud-hotbar.editing .skill.dragging { cursor: grabbing; }
.skill.picked { box-shadow: 0 0 0 2px var(--ac-accent); border-color: var(--ac-accent); }

/* Keyboard-fire + drag affordances. */
.skill.fired { transform: translateY(-1px); box-shadow: 0 0 0 2px var(--ac-accent) inset; border-color: var(--ac-accent); }
.skill.dragging { opacity: .45; }
.skill.drop-target { border-color: var(--ac-accent); box-shadow: 0 0 0 2px var(--ac-accent-wash, rgba(255, 170, 119, .35)); }

@property --sweep { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
@media (prefers-reduced-motion: no-preference) {
    .skill-sweep { transition: --sweep 1s linear; }
}

/* ----- XP: a hairline ambient strip below the terminal (Char.Train.xp_pct) ----- */
/* A 5px track that grows with the terminal, its progress-to-level caption sitting
   *beside* it (not baked into a taller bar). Violet (--hud-xp) is the one HUD hue
   used nowhere else, so it reads unambiguously as XP without competing with the
   amber accent, the green vitals, or the terminal text — and stays quiet. */
#hud-xpstrip { flex: none; display: flex; align-items: center; gap: 8px; }
#hud-xpstrip[hidden] { display: none; }
#hud-xpstrip .xp-track {
    flex: 1 1 auto; height: 5px; overflow: hidden;
    background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: 3px;
}
#hud-xpstrip .xp-fill {
    display: block; height: 100%;
    background: var(--hud-xp); opacity: .8; transition: width .2s ease;
}
#hud-xpstrip .xp-label {
    flex: none; display: flex; gap: 4px; white-space: nowrap;
    font-size: .58rem; font-weight: 600; letter-spacing: .03em; color: var(--ac-dim);
}
#hud-xpstrip .xp-pct { color: var(--hud-xp); font-weight: 700; }
@media (prefers-reduced-motion: reduce) {
    #hud-xpstrip .xp-fill { transition: none; }
}

/* ----- Action row: skill bar + micro-menu (overlay app launchers) ----- */
/* The micro-menu is the WoW-style cluster of small icon buttons at the right
   end of the action-bar row; each opens a transient overlay app (see
   docs/design/decisions.md "The HUD extension model"). On phones it is
   hidden — the dock is the phone's micro-menu. */
#hud-actionrow { display: flex; gap: 8px; align-items: center; flex: none; min-width: 0; }
#hud-actionrow #hud-hotbar { flex: 1 1 auto; min-width: 0; }

/* ----- Attack cluster: the attack/assist tile + the ⚔ target chip it fires at.
   Heads the action row; the chip is the phone's target readout (the vitals
   target chips are desktop-only). Armed = a target is set (kill); otherwise
   the tile assists (joins the group's fight). ----- */
#hud-attack { display: flex; align-items: center; gap: 5px; flex: none; min-width: 0; }
#hud-attack[hidden] { display: none; }
.skill--attack .skill-icon { color: var(--ac-text); }
.skill--attack.armed { border-bottom-color: var(--ac-danger); }
.skill--attack.armed .skill-icon { color: var(--hud-hostile); }
/* Order-followers tile: accent (not danger) to read apart from the attack
   tile it sits beside; armed once a ⚔ target gives the order a subject. */
.skill--order[hidden] { display: none; }
.skill--order .skill-icon { color: var(--ac-dim); }
.skill--order.armed { border-bottom-color: var(--ac-accent); }
.skill--order.armed .skill-icon { color: var(--ac-accent); }
.atk-chip { display: flex; align-items: stretch; min-width: 0; }
.atk-tgt {
    min-width: 0; max-width: 9rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-family: inherit; font-size: .7rem; font-weight: 700; line-height: 1.2;
    margin: 0; padding: 2px 8px; cursor: pointer;
    color: var(--ac-dim); background: var(--ac-elev);
    border: 1px solid var(--ac-border); border-radius: 999px;
}
.atk-tgt:hover { border-color: var(--ac-accent); color: var(--ac-text); }
.atk-tgt.hostile {
    color: var(--hud-hostile); background: var(--ac-danger-wash);
    border-color: rgba(214, 75, 75, .5); border-radius: 999px 0 0 999px; border-right: 0;
}
.atk-tgt.hostile:hover { color: var(--hud-hostile); border-color: rgba(214, 75, 75, .8); }
.atk-tgt.fired { border-color: var(--ac-accent); }
.atk-x {
    flex: none; margin: 0; padding: 2px 8px 2px 6px; cursor: pointer;
    font-family: inherit; font-size: .7rem; font-weight: 700; line-height: 1.2;
    color: var(--hud-hostile); background: var(--ac-danger-wash);
    border: 1px solid rgba(214, 75, 75, .5); border-left: 0; border-radius: 0 999px 999px 0;
}
.atk-x:hover { color: #fff; }
#hud-micro { display: flex; gap: 4px; flex: none; margin-left: auto; }
.micro-btn {
    position: relative; width: 32px; height: 32px; padding: 0; cursor: pointer; overflow: hidden;
    display: flex; align-items: center; justify-content: center;
    background: var(--ac-elev); color: var(--ac-dim);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.micro-btn[hidden] { display: none; }
.micro-btn:hover { border-color: var(--ac-accent); color: var(--ac-text); }
.micro-btn[aria-pressed="true"] { color: var(--ac-accent); border-color: var(--ac-accent); }
.micro-btn .bi { width: 1rem; height: 1rem; }
/* Dot badge: the app's feed changed while its window was closed. */
.micro-btn.unread::after {
    content: ""; position: absolute; top: 3px; right: 3px;
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--ac-accent); box-shadow: 0 0 0 2px var(--ac-elev);
}
/* Progress strip: a long-running activity (active craft/harvest) filling up. */
.micro-strip {
    position: absolute; left: 0; bottom: 0; height: 3px; width: 0;
    background: var(--hud-event); pointer-events: none;
}
.micro-strip[hidden] { display: none; }
@media (max-width: 767.98px) { #hud-micro { display: none; } .atk-tgt { max-width: 7rem; } }

/* ----- Overlay window (micro-menu apps, desktop) ----- */
#hud-overlay {
    position: fixed; z-index: 1038;   /* above the sheet/popovers, below #hud-menu */
    left: 50%; top: 50%; transform: translate(-50%, -50%);
    width: min(520px, calc(100vw - 32px));
    max-height: min(72vh, 620px);
    display: flex; flex-direction: column;
    background: var(--ac-panel); border: 1px solid var(--ac-border-2);
    border-radius: var(--ac-radius); box-shadow: 0 16px 44px rgba(0, 0, 0, .6);
}
#hud-overlay[hidden] { display: none; }
.overlay-head {
    flex: none; display: flex; align-items: center; gap: 8px;
    padding: 8px 10px 6px; border-bottom: 1px solid var(--ac-border);
}
.overlay-title {
    font-size: .72rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .09em; color: var(--ac-dim);
}
#hud-overlay-body { overflow-y: auto; min-height: 0; padding: 6px 10px 10px; }
#hud-overlay-body .panel { display: none; background: transparent; border: 0; }
#hud-overlay-body .panel.overlay-active { display: block; }
/* The overlay body is the scroll container (like the sheet body), so pin the
   Abilities search + filter chips to the top instead of scrolling them away. */
#hud-overlay-body .ab-controls,
#hud-overlay-body .ab-chips {
    position: sticky; top: 0; z-index: 1; background: var(--ac-panel);
}

/* ----- Professions overlay app ----- */
.craft-activity {
    margin: 6px 0 10px; padding: 8px;
    background: var(--ac-elev); border: 1px solid var(--ac-border);
    border-radius: var(--ac-radius-sm);
}
.craft-label { font-size: .78rem; color: var(--ac-text); margin-bottom: 6px; }
.craft-track {
    position: relative; height: 16px;
    background: var(--ac-bg); border: 1px solid var(--ac-border);
    border-radius: 3px; overflow: hidden;
}
.craft-fill { position: absolute; inset: 0 auto 0 0; height: 100%; background: var(--hud-event); opacity: .85; }
.craft-time {
    position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
    font-size: .68rem; font-weight: 700; text-shadow: 0 0 2px #000, 0 0 2px #000;
    font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: no-preference) {
    .micro-strip, .craft-fill { transition: width 1s linear; }
}
.prof-row { padding: 8px 2px; border-bottom: 1px solid var(--ac-border); }
.prof-row:last-of-type { border-bottom: 0; }
/* The header is the recipe-list disclosure — a full-width unstyled button. */
.prof-head {
    display: flex; align-items: baseline; gap: 8px; width: 100%;
    background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
    color: var(--ac-text);
}
.prof-caret { color: var(--ac-dim); font-size: .8rem; }
.prof-name { font-weight: 700; font-size: .9rem; color: var(--ac-text); }
.prof-tier { flex: none; }
.prof-rank { margin-left: auto; font-size: .74rem; color: var(--ac-dim); font-variant-numeric: tabular-nums; }
.prof-track {
    position: relative; height: 8px; margin: 6px 0;
    background: var(--ac-bg); border: 1px solid var(--ac-border);
    border-radius: 3px; overflow: hidden;
}
.prof-fill { position: absolute; inset: 0 auto 0 0; height: 100%; background: var(--ac-accent); opacity: .7; }
.prof-foot { display: flex; align-items: center; gap: 8px; }
.prof-recipes { font-size: .74rem; color: var(--ac-dim); font-variant-numeric: tabular-nums; }
.prof-actions { margin-left: auto; display: flex; gap: 6px; }
.prof-btn {
    font-size: .72rem; padding: 3px 8px; cursor: pointer;
    background: var(--ac-elev); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.prof-btn:hover { border-color: var(--ac-accent); }
.prof-empty, .prof-hint { font-size: .76rem; color: var(--ac-dim); padding: 6px 2px; }
.prof-hint { border-top: 1px solid var(--ac-border); margin-top: 8px; font-family: monospace; }

/* Recipe browser (Char.Recipes) inside a profession row. */
.recipe-controls { margin: 4px 0 6px; padding-left: 14px; }
.recipe-list { margin-top: 2px; padding-left: 14px; }

/* Category = a collapsible section header (a thematic break, not a lost
   all-caps line): a full-width disclosure with a caret, name, and a count. */
.recipe-cat {
    display: flex; align-items: center; gap: 6px; width: 100%;
    margin: 8px 0 2px; padding: 4px 2px 5px; cursor: pointer; text-align: left;
    background: none; border: 0; border-bottom: 1px solid var(--ac-border);
    color: var(--ac-text);
}
.recipe-cat-caret { flex: none; width: .9rem; color: var(--ac-dim); font-size: .72rem; }
.recipe-cat-name {
    flex: 1; min-width: 0; font-size: .68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .07em; color: var(--ac-accent-2);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.recipe-cat-count {
    flex: none; font-size: .62rem; font-weight: 700; color: var(--ac-dim);
    background: var(--ac-bg); border-radius: 999px; padding: 0 6px;
    font-variant-numeric: tabular-nums;
}
.recipe-cat:hover .recipe-cat-name { color: var(--ac-accent); }
.recipe-cat.collapsed { border-bottom-color: transparent; }

.recipe-row { display: flex; align-items: center; gap: 6px; padding: 3px 0; }
/* The name is the component / batch-craft disclosure — the TOUCH path to
   "what am I missing?" and the queue (the hover title is desktop convenience). */
.recipe-toggle {
    flex: 1; min-width: 0; display: block; text-align: left;
    background: none; border: 0; padding: 0; cursor: pointer;
}
.recipe-name { font-size: .82rem; display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Rank: a bare tier-colored number (no "r" prefix). */
.recipe-rank { flex: none; font-variant-numeric: tabular-nums; }
/* Craftable count: visually distinct from the rank — a washed pill, green
   when ready (×N / ✓), red "Missing" when short. */
.recipe-avail { flex: none; font-weight: 700; font-variant-numeric: tabular-nums; }
.recipe-avail.ok { color: var(--ac-ok); background: var(--ac-ok-wash); }
.recipe-avail.missing { color: var(--ac-danger); background: var(--ac-danger-wash); }

.recipe-comps { padding: 2px 0 6px 10px; border-left: 2px solid var(--ac-border); margin-left: 2px; }
.recipe-comp { font-size: .74rem; padding: 1px 0; font-variant-numeric: tabular-nums; }
.recipe-comp.ok { color: var(--ac-ok); }
.recipe-comp.missing { color: var(--ac-danger); }
.recipe-comp.loc { color: var(--ac-dim); }

/* What an enchant recipe does (the info Effects block). Accent-tinted border
   reads it as the outcome, distinct from the plain-bordered component cost. */
.recipe-effects { padding: 2px 0 6px 10px; border-left: 2px solid var(--ac-accent); margin-left: 2px; margin-bottom: 4px; }
.recipe-effects-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ac-dim); }
.recipe-effect { font-size: .74rem; padding: 1px 0; color: var(--ac-text); }

/* What a craft recipe produces (the info Result block). Informational-blue
   border sets "what you get" apart from the amber "what it does" effects. */
.recipe-result { padding: 2px 0 6px 10px; border-left: 2px solid var(--ac-info); margin-left: 2px; margin-bottom: 4px; }
.recipe-result-label { font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; color: var(--ac-dim); }
.recipe-result-name { font-size: .78rem; color: var(--ac-text); }
.recipe-result-meta { font-size: .7rem; color: var(--ac-dim); font-variant-numeric: tabular-nums; }
.recipe-result-prop { font-size: .74rem; padding: 1px 0; color: var(--ac-text); }

/* Batch-craft queue (targetless recipes): stepper + editable count + Max +
   Craft ×N. Mirrors the game's `<verb> <recipe> <count>` chain (cap 99). */
.recipe-queue {
    display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
    margin: 2px 0 6px 10px; padding: 6px 8px;
    background: var(--ac-elev); border: 1px solid var(--ac-border);
    border-radius: var(--ac-radius-sm);
}
.recipe-queue-label { font-size: .72rem; color: var(--ac-dim); }
.recipe-qty-btn { min-width: 26px; text-align: center; font-weight: 700; padding: 3px 6px; }
.recipe-qty-num {
    width: 3ch; text-align: center; font-size: 16px; padding: 3px 4px;
    font-variant-numeric: tabular-nums;
    background: var(--ac-bg); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.recipe-qty-num:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: -1px; }
.recipe-queue-craft { margin-left: auto; font-weight: 700; color: var(--ac-accent); border-color: var(--ac-border-2); }
.recipe-queue-craft.off { opacity: .45; }

.prof-btn.off { opacity: .45; }

/* Profession difficulty buckets (docs/gmcp_feeds.md) — the same palette the
   game's recipe/harvest lists color by. The .menu-item compounds outrank the
   menu's own color rule (defined later) for the disenchant entry. */
.tier-trivial, .menu-item.tier-trivial { color: var(--ac-dim); }
.tier-easy,    .menu-item.tier-easy    { color: var(--ac-ok); }
.tier-medium,  .menu-item.tier-medium  { color: var(--hud-gold); }
.tier-hard,    .menu-item.tier-hard    { color: var(--hud-edge); }
.tier-blocked, .menu-item.tier-blocked { color: var(--ac-danger); }

/* Tablets show the micro-menu with a coarse pointer — bump its launchers too. */
@media (pointer: coarse) {
    .prof-btn { min-height: 40px; padding: 6px 12px; }
    .recipe-chip { min-height: 34px; }
    .recipe-cat { min-height: 42px; }
    .recipe-qty-btn { min-width: 40px; }
    .micro-btn { width: 42px; height: 42px; }
}

/* ----- Context / action menu ----- */
#hud-menu {
    position: fixed; z-index: 1040; min-width: 172px; max-width: min(80vw, 260px);
    max-height: calc(100dvh - 16px); overflow-y: auto;
    padding: 4px; background: var(--ac-panel);
    border: 1px solid var(--ac-border-2); border-radius: var(--ac-radius);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .6);
}
#hud-menu[hidden] { display: none; }
.menu-title {
    font-size: .7rem; font-weight: 700; color: var(--ac-dim);
    padding: 5px 8px 6px; border-bottom: 1px solid var(--ac-border);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.menu-item {
    display: block; width: 100%; text-align: left; cursor: pointer;
    background: none; border: 0; color: var(--ac-text);
    font-size: .82rem; padding: 8px 10px; border-radius: var(--ac-radius-sm);
}
.menu-item:hover { background: var(--ac-elev); color: var(--ac-accent); }
.menu-item.danger { color: var(--ac-danger); }
.menu-item.danger:hover { background: var(--ac-danger-wash); color: var(--ac-danger); }
/* Inert requirement rows (e.g. a harvest whose rank gate you don't meet):
   visible so the requirement teaches, but never clickable. */
.menu-item.disabled, .menu-item.disabled:hover { color: var(--ac-dim); background: none; cursor: default; opacity: .65; }
@media (pointer: coarse) { .menu-item { min-height: 44px; } }

/* ----- Icon picker (reuses #hud-menu with a wider grid layout) ----- */
#hud-menu.menu-picker { min-width: 244px; max-width: min(92vw, 328px); padding: 6px; }
.picker-group { font-size: .62rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; color: var(--ac-dim); padding: 8px 2px 3px; }
.picker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(34px, 1fr)); gap: 4px; }
.picker-icon, .picker-auto {
    display: flex; align-items: center; justify-content: center; gap: 6px; cursor: pointer;
    background: var(--ac-elev); color: var(--ac-text);
    border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm);
}
.picker-icon { aspect-ratio: 1 / 1; }
.picker-icon .gi { width: 21px; height: 21px; }
.picker-icon:hover, .picker-auto:hover { border-color: var(--ac-accent); color: var(--ac-accent); }
.picker-icon.on, .picker-auto.on { border-color: var(--ac-accent); box-shadow: 0 0 0 1px var(--ac-accent) inset; color: var(--ac-accent); }
.picker-auto { width: 100%; padding: 8px 10px; margin: 4px 0 2px; font-size: .82rem; font-weight: 600; }
.picker-auto .gi { width: 20px; height: 20px; flex: none; }
@media (pointer: coarse) { .picker-icon { min-height: 44px; } }

/* Ability-browser row icon (mirrors the bar's glyph so pins are recognisable). */
.ab-icon { flex: none; width: 17px; height: 17px; color: var(--ac-dim); margin-right: 2px; }
.ab-row.cat-damage .ab-icon { color: #e6836b; }
.ab-row.cat-heal   .ab-icon { color: #7fc99a; }
.ab-row.cat-misc   .ab-icon { color: #7fb2e6; }

/* ----- Tooltip (.hud-tip) — the HUD's single hover/focus tip -----
   Convention (see components.md): terse. A bold title, an optional right-
   aligned key chip (the hotkey), and at most one status line. Any element opts
   in with data-tip="text"; the action bar supplies richer structured tips.
   Hover/focus only — coarse pointers use the long-press menu instead. */
.hud-tip {
    position: fixed; z-index: 1060; pointer-events: none; max-width: 240px;
    padding: 5px 8px; background: var(--ac-panel); color: var(--ac-text);
    border: 1px solid var(--ac-border-2); border-radius: var(--ac-radius-sm);
    box-shadow: 0 6px 20px rgba(0, 0, 0, .55); font-size: .72rem; line-height: 1.3;
}
.hud-tip[hidden] { display: none; }
.tip-row { display: flex; align-items: baseline; gap: 12px; }
.tip-name { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tip-key {
    margin-left: auto; flex: none; font-size: .62rem; font-weight: 700; color: var(--ac-accent);
    border: 1px solid var(--ac-border-2); border-radius: 4px; padding: 0 4px;
    font-variant-numeric: tabular-nums; white-space: nowrap;
}
.tip-sub { color: var(--ac-dim); font-size: .66rem; margin-top: 1px; }
.tip-warn { color: var(--ac-danger); font-weight: 700; }
@media (prefers-reduced-motion: no-preference) {
    .hud-tip { animation: hud-tip-in .1s ease-out; }
    @keyframes hud-tip-in { from { opacity: 0; } to { opacity: 1; } }
}

/* ----- Shared topbar buttons (aligned with .ac-btn — see components.md) ----- */
.hud-btn[hidden] { display: none; }
.hud-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    padding: 5px 12px; font-size: .8rem; font-weight: 600; cursor: pointer; white-space: nowrap;
    background: var(--ac-elev); color: var(--ac-text);
    border: 1px solid var(--ac-border-2); border-radius: var(--ac-radius-sm);
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}
.hud-btn:hover { border-color: rgba(255, 170, 119, .45); color: var(--ac-accent); }
.hud-btn .bi { flex-shrink: 0; }
.hud-btn--icon { padding: 5px 8px; }
.hud-btn--icon .bi { width: 1rem; height: 1rem; }
.hud-btn-accent[aria-pressed="false"] { border-color: rgba(255, 170, 119, .45); color: var(--ac-accent); }
.hud-btn-accent[aria-pressed="false"]:hover { background: var(--ac-wash); }
.col-toggle[aria-pressed="true"] { color: var(--ac-accent); background: var(--ac-wash); border-color: rgba(255, 170, 119, .45); }

/* ----- Phone dock ----- */
#hud-dock {
    display: none;
    min-height: var(--hud-dock-h);
    gap: 2px;
    padding: .25rem .25rem calc(.25rem + env(safe-area-inset-bottom, 0px));
    background: var(--ac-panel);
    border: 1px solid var(--ac-border);
    border-radius: var(--ac-radius-sm);
    overflow-x: auto;
    scrollbar-width: none;
}
#hud-dock::-webkit-scrollbar { display: none; }
@media (max-width: 767.98px) {
    #connect-app.hud-on #hud-dock { display: flex; }
}
#hud-dock button {
    position: relative;
    flex: 1 1 2.3rem; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
    padding: 4px 2px;
    background: transparent; color: var(--ac-dim);
    border: 0; border-radius: var(--ac-radius-sm);
    font-size: .58rem; font-weight: 700; text-transform: uppercase; letter-spacing: .02em;
    cursor: pointer;
}
/* Shrink to fit all tabs on narrow phones instead of pushing Chat/Who off the
   scroll edge; labels ellipsize rather than overflow. */
#hud-dock button span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
#hud-dock button .bi { width: 1.1rem; height: 1.1rem; }
/* Overlay-app tabs are availability-gated by hud.js (no professions → no tab);
   display:flex above would otherwise defeat the hidden attribute. */
#hud-dock button[hidden] { display: none; }
#hud-dock button[aria-pressed="true"] { color: var(--ac-accent); background: var(--ac-elev); }

#hud-dock button.unread::after {
    content: ""; position: absolute; top: 4px; right: 8px;
    width: .45rem; height: .45rem; border-radius: 50%;
    background: var(--ac-accent);
}
/* Tracked-spell expiry alarm on the phone dock: a spell about to drop raises a
   caution dot on the Tracked button — the ambient warning the panel can't be
   while it's off-screen. Distinct (caution, pulsing) from the amber unread dot. */
#hud-dock button.alarm::after {
    content: ""; position: absolute; top: 4px; right: 8px;
    width: .5rem; height: .5rem; border-radius: 50%;
    background: var(--ac-warn); box-shadow: 0 0 5px 1px rgba(255, 136, 0, .7);
}
@media (prefers-reduced-motion: no-preference) {
    #hud-dock button.alarm::after { animation: dock-alarm 1.2s ease-in-out infinite; }
    @keyframes dock-alarm { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }
}

/* ----- Phone bottom sheet ----- */
#hud-sheet {
    position: fixed; z-index: 1035;
    left: .4rem; right: .4rem;
    bottom: calc(var(--hud-dock-h) + .8rem + env(safe-area-inset-bottom, 0px));
    max-height: 55vh;
    max-height: 55dvh;
    display: flex; flex-direction: column;
    background: var(--ac-panel);
    border: 1px solid var(--ac-border-2);
    border-radius: var(--ac-radius);
    box-shadow: 0 -10px 30px rgba(0, 0, 0, .55);
}
#hud-sheet[hidden] { display: none; }
.sheet-head {
    position: relative; flex: none;
    display: flex; align-items: center; gap: 8px;
    padding: 10px 10px 6px;
    border-bottom: 1px solid var(--ac-border);
}
.sheet-grip {
    position: absolute; top: 4px; left: 50%; transform: translateX(-50%);
    width: 36px; height: 3px; border-radius: 999px; background: var(--ac-border-2);
}
.sheet-title {
    font-size: .72rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .09em; color: var(--ac-dim);
}
.sheet-close {
    margin-left: auto; padding: 4px 6px; cursor: pointer;
    background: none; border: 0; color: var(--ac-dim);
}
.sheet-close:hover { color: var(--ac-text); }
.sheet-close .bi { width: .9rem; height: .9rem; }
#hud-sheet-body { overflow-y: auto; min-height: 0; padding: 2px 0 4px; }
#hud-sheet-body .panel {
    display: none;
    background: transparent; border: 0; border-radius: 0;
    padding: 2px 4px 12px;
}
#hud-sheet-body .panel.sheet-active { display: block; }
/* In the sheet the panel header is always expanded context; keep it readable. */
#hud-sheet-body .panel-h { border-bottom-color: var(--ac-border); }
/* The sheet body is the scroll container (not .ab-scroll), so pin the ability
   search + filter chips to the top instead of letting them scroll out of view. */
#hud-sheet-body .ab-controls,
#hud-sheet-body .ab-chips {
    position: sticky; top: 0; z-index: 1; background: var(--ac-panel);
}

/* ----- Focus (keyboard) ----- */
.hud-btn:focus-visible, .exit:focus-visible, .skill:focus-visible,
#hud-dock button:focus-visible,
.who-act button:focus-visible, .action-btn:focus-visible, .sheet-close:focus-visible,
.panel-h-toggle:focus-visible, .row-more:focus-visible, .menu-item:focus-visible,
.ab-chip:focus-visible, .ab-star:focus-visible, .panel-h-btn:focus-visible,
.aff-rel:focus-visible, .occ-row:focus-visible, .sub-h.collapse:focus-visible,
.item-pin:focus-visible, .bag-h:focus-visible,
.micro-btn:focus-visible, .prof-btn:focus-visible, .prof-head:focus-visible,
.recipe-toggle:focus-visible, .recipe-cat:focus-visible, .recipe-chip:focus-visible {
    outline: 2px solid var(--ac-accent); outline-offset: 2px;
}

/* ----- Touch ergonomics ----- */
@media (pointer: coarse) {
    .hud-btn { padding: 8px 12px; }
    .hud-btn--icon { padding: 8px 10px; }
    .exit { padding: 10px 0; }
    .exit.ud, .exit.named { padding: 9px 12px; }
    .who-act button { padding: 7px 12px; }
    /* Bigger touch target for the icon slots (still square). */
    .skill { width: 52px; height: 52px; }
    .skill .skill-icon { width: 34px; height: 34px; }
    .item-row, .occ-row, .ab-row { min-height: 44px; padding: 8px 6px; }
    .row-more, .item-pin { min-width: 40px; min-height: 40px; padding: 6px 8px; }
    .bag-h { min-height: 44px; }
    /* Taller (full row height) tap zone for the caret without widening the
       lead column and shoving container names out of line with dotted rows. */
    .row-caret { width: 1.6rem; min-height: 40px; }
    .action-btn { padding: 10px; }
    .sheet-close { padding: 8px 10px; }
    .panel-h-toggle { padding: 10px 8px; }
    #command-input { padding: 9px 10px; }
    #send-btn { padding: 10px 12px; }
    #hud-dock button { min-height: 2.9rem; }
    #rose-overlay .exit { min-height: 44px; padding: 0; }
    #rose-overlay .compass.overlay { grid-template-columns: repeat(3, 44px); }
}

/* ----- Quest Log (OVERLAYS app "quests", Ctrl+Q) -----
   Reuses the .ab-search/.ab-chips/.ab-scroll browser chrome; rows carry a
   status-colored left edge and expand in place to catalog detail. */
#hud-overlay[data-app="quests"] { width: min(560px, calc(100vw - 32px)); }
.qst-list { list-style: none; margin: 0; padding: 0; }
.qst-row { border-left: 3px solid transparent; border-radius: 3px; margin-bottom: 2px; }
.qst-row.qst-progress { border-left-color: var(--ac-info); }
.qst-row.qst-ready { border-left-color: var(--ac-ok); }
.qst-row.qst-failed { border-left-color: var(--ac-danger); }
.qst-row.qst-done { border-left-color: var(--ac-border-2); }
.qst-head {
    display: flex; align-items: center; gap: 6px;
    padding: 5px 6px; cursor: pointer; font-size: .82rem;
}
.qst-head:hover { background: var(--ac-elev); }
.qst-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; }
.qst-row.qst-done .qst-name { color: var(--ac-dim); font-weight: 400; }
.qst-right { flex: none; display: flex; align-items: center; gap: 6px; }
.qst-status { font-size: .64rem; color: var(--ac-dim); white-space: nowrap; }
.qst-row.qst-ready .qst-status { color: var(--ac-ok); font-weight: 700; }
.qst-row.qst-failed .qst-status { color: var(--ac-danger); }
.qst-detail { padding: 0 8px 7px 9px; font-size: .76rem; }
.qst-desc { margin: 0 0 5px; color: var(--ac-dim); white-space: pre-line; }
.qst-steps { list-style: none; margin: 0 0 5px; padding: 0; }
.qst-step { display: flex; gap: 8px; align-items: baseline; padding: 1px 0; }
.qst-step.complete .qst-step-label { color: var(--ac-ok); text-decoration: line-through; }
.qst-step-label { flex: 1; }
.qst-step-count { flex: none; font-variant-numeric: tabular-nums; color: var(--ac-dim); }
.qst-step.complete .qst-step-count { color: var(--ac-ok); }
.qst-rewards { margin-bottom: 3px; }
.qst-h { color: var(--ac-dim); font-weight: 700; font-size: .68rem; text-transform: uppercase; letter-spacing: .04em; }
.qst-meta { font-size: .68rem; color: var(--ac-dim); }
.qst-cmd { font-family: var(--bs-font-monospace, monospace); }

/* ----- Tracked-objectives tracker: the one sanctioned persistent surface
   over the terminal (docs/design/decisions.md, tracked-objectives
   amendment). Glanceable, collapsible, never focus-stealing. ----- */
#quest-tracker {
    position: absolute; top: 8px; right: 8px; z-index: 5;
    width: min(260px, 42vw); max-height: 60%; overflow-y: auto;
    background: rgba(20, 20, 26, .82); border: 1px solid var(--ac-border);
    border-radius: var(--ac-radius-sm); padding: 0 0 4px;
    font-size: .74rem; pointer-events: auto;
}
#quest-tracker.collapsed { width: auto; padding: 0; }
.qtr-head {
    display: flex; align-items: center; gap: 6px; width: 100%;
    background: none; border: 0; color: var(--ac-dim); cursor: pointer;
    padding: 4px 8px; font-size: .68rem; font-weight: 700;
    text-transform: uppercase; letter-spacing: .05em; text-align: left;
}
.qtr-head:hover { color: var(--ac-text); }
.qtr-title { flex: 1; }
.qtr-count { font-variant-numeric: tabular-nums; }
.qtr-count.ready { color: var(--ac-ok); }
.qtr-caret { flex: none; }
.qtr-quest { padding: 2px 8px 4px; }
.qtr-name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qtr-name.qst-ready { color: var(--ac-ok); }
.qtr-step { display: flex; gap: 6px; align-items: baseline; color: var(--ac-dim); }
.qtr-step.complete { color: var(--ac-ok); }
.qtr-step-label { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.qtr-step-count { flex: none; font-variant-numeric: tabular-nums; }
@media (max-width: 767.98px) {
    /* Phones: a slim count pill by default (renderQuestTracker starts
       collapsed), raised above the tap-to-move compass (z 15) so the
       whole pill stays tappable where their corners meet; expanded, the
       card drops below the compass so it never covers an exit button. */
    #quest-tracker { width: min(220px, 58vw); font-size: .7rem; z-index: 16; }
    #quest-tracker.collapsed .qtr-title { display: none; }
    #quest-tracker:not(.collapsed) { top: 10.5rem; max-height: calc(100% - 11.5rem); }
    #quest-tracker .qtr-head { min-height: 34px; }
}
.hud-off #quest-tracker { display: none; }

/* ----- Season (OVERLAYS app "season", Ctrl+E) — Char.Season -----
   Season identity + countdown, the engagement track (meter with milestone
   ticks, per-activity bars, milestone list), essence, and active events.
   Colours are the shared --ac-* tokens; the amber track reads as "season". */
#panel-season { padding-bottom: 8px; }
.season-id { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.season-id-name { font-size: 1.02rem; font-weight: 700; color: var(--ac-accent-2); min-width: 0; overflow-wrap: anywhere; }
.season-count { font-size: .74rem; color: var(--ac-dim); white-space: nowrap; }
.season-count b { color: var(--ac-text); font-weight: 600; font-variant-numeric: tabular-nums; }

.season-sec { margin-top: 14px; }
.season-sec-h { font-size: .64rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--ac-dim); margin-bottom: 7px; }

.eng-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 6px; }
.eng-pct { font-size: 1.4rem; font-weight: 700; color: var(--ac-accent); font-variant-numeric: tabular-nums; line-height: 1; }
.eng-sub { font-size: .72rem; color: var(--ac-dim); }
.eng-sub b { color: var(--ac-text); }
.eng-track-wrap { position: relative; padding-top: 8px; }
.eng-track { position: relative; height: 13px; background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: 4px; overflow: hidden; }
.eng-fill { position: absolute; inset: 0 auto 0 0; height: 100%; background: linear-gradient(90deg, #d88a4a, var(--ac-accent)); opacity: .9; transition: width .2s ease; }
.eng-tick { position: absolute; top: 2px; width: 2px; height: 19px; transform: translateX(-1px); background: var(--ac-border-2); }
.eng-tick.done { background: var(--ac-ok); }
.eng-tick::before { content: ""; position: absolute; top: -8px; left: 50%; transform: translateX(-50%); width: 6px; height: 6px; border-radius: 50%; background: var(--ac-elev); border: 1px solid var(--ac-border-2); }
.eng-tick.done::before { background: var(--ac-ok); border-color: var(--ac-ok); }
.eng-tick.cap::before { border-radius: 1px; transform: translateX(-50%) rotate(45deg); }
.eng-next { margin-top: 9px; font-size: .74rem; color: var(--ac-dim); }
.eng-next b { color: var(--ac-accent-2); }
.eng-next.complete { color: var(--ac-ok); }

.season-perks { display: flex; gap: 7px; margin-top: 10px; flex-wrap: wrap; }
.season-pill { font-size: .66rem; font-weight: 600; letter-spacing: .03em; text-transform: uppercase; white-space: nowrap; padding: 2px 9px; border-radius: 999px; border: 1px solid var(--ac-border); color: var(--ac-dim); }
.season-pill.accent { color: var(--ac-accent); border-color: rgba(255, 170, 119, .45); background: var(--ac-wash); }
.season-pill.ok { color: var(--ac-ok); border-color: rgba(76, 187, 23, .4); background: var(--ac-ok-wash); }

.season-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(5.5rem, 1fr)); gap: 8px; }
.season-tile { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 9px 6px; border-radius: var(--ac-radius-sm); background: var(--ac-bg); border: 1px solid var(--ac-border); }
.season-tile-n { font-size: 1.2rem; font-weight: 700; color: var(--hud-gold); font-variant-numeric: tabular-nums; line-height: 1.05; }
.season-tile-l { font-size: .58rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--ac-dim); text-align: center; }

.season-bars { display: flex; flex-direction: column; gap: 8px; }
.season-bar { display: grid; grid-template-columns: minmax(0, 6rem) minmax(0, 1fr) auto; align-items: center; gap: 10px; font-size: .78rem; }
.season-bar-l { color: var(--ac-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.season-bar-track { height: 9px; border-radius: 5px; background: var(--ac-elev); overflow: hidden; }
.season-bar-fill { display: block; height: 100%; border-radius: 5px; background: var(--ac-info); transition: width .2s ease; }
.season-bar-fill.ax-craft { background: var(--ac-accent); }
.season-bar-fill.ax-explore { background: var(--ac-info); }
.season-bar-fill.ax-general { background: var(--ac-ok); }
.season-bar-n { color: var(--ac-dim); font-variant-numeric: tabular-nums; font-size: .72rem; white-space: nowrap; }
.season-bar-n b { color: var(--ac-text); }

.season-ms { display: flex; flex-direction: column; }
.season-ms-row { display: flex; align-items: center; gap: 8px; padding: 6px 4px; border-top: 1px solid var(--ac-border); font-size: .78rem; }
.season-ms-row:first-child { border-top: 0; }
.season-ms-row.locked { color: var(--ac-dim); }
.season-ms-row.next { background: var(--ac-wash); border-radius: var(--ac-radius-sm); }
.season-ms-mk { flex: none; width: 15px; text-align: center; font-weight: 700; color: var(--ac-ok); }
.season-ms-row.locked .season-ms-mk { color: var(--ac-border-2); }
.season-ms-at { flex: none; width: 34px; text-align: right; color: var(--ac-dim); font-variant-numeric: tabular-nums; font-size: .72rem; }
.season-ms-rw { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.season-ms-row.next .season-ms-rw { color: var(--ac-accent-2); }
.season-ms-badge { flex: none; font-size: .56rem; letter-spacing: .05em; text-transform: uppercase; color: var(--ac-accent); border: 1px solid rgba(255, 170, 119, .4); border-radius: 999px; padding: 1px 7px; }

.season-events { display: flex; gap: 7px; flex-wrap: wrap; }
.season-event { display: inline-flex; align-items: center; gap: 4px; font-size: .72rem; color: var(--hud-event); background: rgba(232, 176, 75, .08); border: 1px solid rgba(232, 176, 75, .3); border-radius: 999px; padding: 2px 9px; white-space: nowrap; }
.season-event b { color: var(--ac-text); font-weight: 600; font-variant-numeric: tabular-nums; }

/* ----- Achievements (OVERLAYS app "achievements", Ctrl+H) — Char.Achievements
   Rows arrive in the in-game command's category order; done rows are quiet
   green, in-progress rows carry criteria chips colored by live met state. */
#hud-overlay[data-app="achievements"] { width: min(560px, calc(100vw - 32px)); }
#panel-achievements { padding-bottom: 8px; }
.achv-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.achv-points { font-size: 1.02rem; color: var(--ac-text); }
.achv-points b { font-size: 1.2rem; font-weight: 700; color: var(--hud-gold); font-variant-numeric: tabular-nums; }
.achv-count { font-size: .74rem; color: var(--ac-dim); white-space: nowrap; }

.achv-latest { display: flex; flex-direction: column; }
.achv-latest-row { display: flex; align-items: baseline; gap: 4px 8px; padding: 4px 4px; font-size: .78rem; min-width: 0; flex-wrap: wrap; }
.achv-latest-row .achv-name { flex: 1; }
.achv-when { color: var(--ac-dim); font-size: .7rem; white-space: nowrap; }

.achv-rows { display: flex; flex-direction: column; }
.achv-row { padding: 7px 4px; border-top: 1px solid var(--ac-border); }
.achv-row:first-child { border-top: 0; }
.achv-row-h { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.achv-mk { flex: none; width: 15px; text-align: center; font-weight: 700; color: var(--ac-border-2); }
.achv-row.done .achv-mk, .achv-latest-row .achv-mk { color: var(--ac-ok); }
.achv-name { font-size: .82rem; font-weight: 600; color: var(--ac-text); min-width: 0; overflow-wrap: anywhere; }
.achv-row.done .achv-name { color: var(--ac-ok); }
.achv-pts { margin-left: auto; flex: none; font-size: .68rem; color: var(--hud-gold); font-variant-numeric: tabular-nums; white-space: nowrap; }
.achv-badge { flex: none; font-size: .56rem; letter-spacing: .05em; text-transform: uppercase; color: var(--ac-accent); border: 1px solid rgba(255, 170, 119, .4); border-radius: 999px; padding: 1px 7px; }
.achv-sub { font-size: .72rem; color: var(--ac-dim); margin: 3px 0 0 23px; overflow-wrap: anywhere; }
.achv-row.done .achv-sub { font-style: italic; }

.achv-crits { display: flex; gap: 5px; flex-wrap: wrap; margin: 5px 0 0 23px; }
.achv-crit { font-size: .66rem; white-space: nowrap; padding: 1px 8px; border-radius: 999px; border: 1px solid var(--ac-border); color: var(--ac-dim); }
.achv-crit.met { color: var(--ac-ok); border-color: rgba(76, 187, 23, .4); background: var(--ac-ok-wash); }

.achv-rewards { display: flex; gap: 5px; flex-wrap: wrap; margin: 5px 0 0 23px; }
.achv-reward { font-size: .66rem; white-space: nowrap; padding: 1px 8px; border-radius: 999px; color: var(--ac-accent); border: 1px solid rgba(255, 170, 119, .4); background: var(--ac-wash); }

/* Character overlay → achievements door (renderTrain). */
.char-achv { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; width: 100%; margin-top: 10px; padding: 7px 10px; font: inherit; font-size: .8rem; color: var(--ac-text); text-align: left; background: var(--ac-bg); border: 1px solid var(--ac-border); border-radius: var(--ac-radius-sm); cursor: pointer; }
.char-achv:hover { border-color: var(--ac-accent); }
.char-achv:focus-visible { outline: 2px solid var(--ac-accent); outline-offset: 2px; }
.char-achv-n { color: var(--ac-dim); font-size: .72rem; white-space: nowrap; }
.char-achv-n b { color: var(--hud-gold); font-variant-numeric: tabular-nums; }

/* ----- Reduced motion ----- */
@keyframes hud-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: .35; }
}
@media (prefers-reduced-motion: reduce) {
    .vbar-fill, .hud-btn, #rose-overlay { transition: none; }
    .status-connecting .status-dot { animation: none; }
    .eng-fill, .season-bar-fill { transition: none; }
}
