  /* Palette — cohesive across every page. Brass accent (DayZ brass casings) for
     interactive/active; a distinct DELTA green that means one thing: "captured override";
     a soft INFO blue for the 'all missions' layer chip. The code surface (--pre-bg) stays
     dark in both themes on purpose, like a terminal. */
  :root {
    --bg: #eaeef3; --card: #ffffff; --fg: #1a2028; --muted: #59636f; --faint: #8592a0;
    --border: #d2dae2; --border-soft: #e5eaef; --rail: #f6f8fa; --panel2: #f2f5f8;
    --accent: #a9741a; --accent-fg: #ffffff; --accent-weak: rgba(169,116,26,0.12);
    --pre-bg: #0b1017; --pre-fg: #cfd9e4; --danger: #c33327; --ok: #1a8a44;
    --delta: #1a8a44; --delta-weak: rgba(26,138,68,0.12); --delta-line: rgba(26,138,68,0.16);
    --info: #2f6fd0; --info-weak: rgba(47,111,208,0.12);
    --drift: #c2570b; --tree-guide: #b7c3d0;
    --shadow: 0 1px 2px rgba(16,24,32,.06), 0 6px 20px rgba(16,24,32,.06);
  }
  :root[data-theme="dark"] {
    --bg: #0e1217; --card: #151b23; --fg: #e7edf3; --muted: #8b98a7; --faint: #5c6875;
    --border: #263140; --border-soft: #1c2530; --rail: #10161d; --panel2: #1a222c;
    --accent: #d7a13b; --accent-fg: #1a1205; --accent-weak: rgba(215,161,59,0.14);
    --pre-bg: #0b1017; --pre-fg: #cfd9e4; --danger: #ef5b52; --ok: #46c266;
    --delta: #46c266; --delta-weak: rgba(70,194,102,0.13); --delta-line: rgba(70,194,102,0.14);
    --info: #4c9be8; --info-weak: rgba(76,155,232,0.14);
    --drift: #e8843c; --tree-guide: #33455a;
    --shadow: 0 1px 2px rgba(0,0,0,.35), 0 10px 30px rgba(0,0,0,.35);
  }
  * { box-sizing: border-box; }
  body {
    margin: 0; background: var(--bg); color: var(--fg);
    font: 15px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif; min-height: 100vh;
  }
  .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .hidden { display: none !important; }
  .spacer { flex: 1; }
  .meta { color: var(--muted); font-size: 13px; word-break: break-all; margin: 0; }
  .msg { font-size: 13px; min-height: 1em; }
  .msg.err { color: var(--danger); } .msg.ok { color: var(--ok); }

  /* Text fields only — checkboxes/radios must NOT inherit width:100%/padding/border (that
     styled them like text boxes and was the root of the misaligned, oversized checkboxes). */
  input:not([type=checkbox]):not([type=radio]), select, textarea {
    width: 100%; padding: 9px 11px; border: 1px solid var(--border);
    border-radius: 8px; background: var(--bg); color: var(--fg); font: inherit;
  }
  input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
  button { font: inherit; font-weight: 600; padding: 9px 16px; border: 0; border-radius: 8px; background: var(--accent); color: var(--accent-fg); cursor: pointer; }
  button.ghost { background: transparent; color: var(--muted); border: 1px solid var(--border); padding: 6px 12px; font-size: 13px; }
  button.ghost:hover { color: var(--fg); border-color: var(--faint); }
  button:disabled { opacity: .55; cursor: default; }

  /* ---------- login card (pre-auth) ---------- */
  .card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 22px; max-width: 460px; margin: 10vh auto 0; box-shadow: var(--shadow); }
  .card h2 { margin: 0 0 4px; font-size: 17px; }
  .card p.hint { margin: 0 0 18px; color: var(--muted); font-size: 13px; }
  .card label { display: block; font-size: 13px; font-weight: 600; margin: 14px 0 5px; }
  .card button[type=submit] { margin-top: 18px; }

  /* ---------- app shell ---------- */
  #app { display: grid; grid-template-columns: 250px 1fr; grid-template-rows: 1fr auto; height: 100vh; }

  /* Server stats bar — spans both columns at the very bottom. */
  #statsbar { grid-column: 1 / -1; display: flex; align-items: center; gap: 16px;
    padding: 8px 16px; border-top: 1px solid var(--border); background: var(--rail);
    font-size: 12px; color: var(--muted); min-height: 20px; }
  #sbStats { display: flex; align-items: center; gap: 18px; flex-wrap: wrap; flex: 1 1 auto; min-width: 0; }
  #sbActions { display: inline-flex; align-items: center; gap: 10px; flex: none; }
  #statsbar .sb-arm { display: inline-flex; align-items: center; gap: 5px; cursor: pointer; user-select: none; white-space: nowrap; }
  #statsbar .sb-arm input { cursor: pointer; margin: 0; }
  #statsbar .sb-btn { padding: 4px 12px; font-size: 12px; font-weight: 600; border-radius: 6px; background: var(--danger); color: #fff; border: 0; cursor: pointer; }
  #statsbar .sb-btn:disabled { opacity: 0.45; cursor: not-allowed; }
  /* Neutral (non-danger) footer button — queue/cancel an update, which kicks nobody. */
  #statsbar .sb-btn.ghost { background: var(--panel2); color: var(--fg); border: 1px solid var(--border); }
  /* Update status pill + its detail popover. */
  #sbUpdate { display: inline-flex; align-items: center; gap: 8px; }
  #sbUpdate.hidden { display: none; }
  #statsbar .sb-pill { padding: 3px 10px; font-size: 12px; font-weight: 600; border-radius: 999px; cursor: pointer; background: transparent; border: 1px solid var(--border); color: var(--faint); white-space: nowrap; }
  #statsbar .sb-pill.is-avail, #statsbar .sb-pill.is-pending { color: var(--accent); border-color: var(--accent); background: var(--accent-weak); }
  #statsbar .sb-pill.is-fail { color: var(--danger); border-color: var(--danger); }
  #statsbar .sb-pill.is-ok { color: var(--ok); border-color: var(--border); }
  .upd-panel { position: fixed; right: 12px; bottom: 48px; z-index: 60; width: min(540px, 92vw); max-height: min(60vh, 460px); overflow: auto; background: var(--card); color: var(--fg); border: 1px solid var(--border); border-radius: 10px; box-shadow: 0 12px 34px rgba(0,0,0,0.28); padding: 14px 16px; font-size: 13px; }
  .upd-panel.hidden { display: none; }
  .upd-panel h4 { margin: 0 0 10px; font-size: 13px; display: flex; justify-content: space-between; align-items: center; }
  .upd-panel .upd-close { background: none; border: 0; color: var(--faint); font-size: 18px; line-height: 1; cursor: pointer; padding: 0 2px; }
  .upd-row { display: flex; justify-content: space-between; gap: 14px; padding: 4px 0; border-bottom: 1px solid var(--border-soft); }
  .upd-row:last-of-type { border-bottom: 0; }
  .upd-row .k { color: var(--faint); }
  .upd-row .v { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; text-align: right; word-break: break-word; }
  .upd-row .v.warn { color: var(--accent); } .upd-row .v.bad { color: var(--danger); } .upd-row .v.good { color: var(--ok); }
  .upd-log { margin: 12px 0 0; background: var(--pre-bg); color: var(--pre-fg); border-radius: 7px; padding: 10px 12px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; white-space: pre-wrap; word-break: break-word; max-height: 200px; overflow: auto; }
  .upd-lbl { color: var(--faint); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; margin: 12px 0 4px; }

  /* ===================== Maintenance page ===================== */
  /* No width cap: the grid is auto-fill, so a cap here just parks empty space to the right
     on a wide screen instead of fitting more cards across. */
  .mnt { padding: 20px 22px; }
  .mnt-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 6px; }
  .mnt-head h2 { margin: 0; font-size: 20px; }
  .mnt-sub { color: var(--faint); font-size: 13px; margin-top: 2px; }
  .mnt-head-right { display: flex; align-items: center; gap: 10px; flex: none; }
  .mnt-role { font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 999px; border: 1px solid var(--border); color: var(--faint); white-space: nowrap; }
  .mnt-role.is-op { color: var(--ok); border-color: var(--ok); }
  .mnt-role.is-view { color: var(--accent); border-color: var(--accent); }
  .mnt-viewer-note { margin: 8px 0 4px; padding: 8px 12px; border-radius: 8px; background: var(--accent-weak); color: var(--fg); font-size: 12.5px; border: 1px solid var(--accent); }
  .mnt-viewer-note.hidden { display: none; }
  .mnt-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(290px, 1fr)); gap: 14px; margin-top: 14px; align-items: start; }
  .mnt-card { background: var(--card); border: 1px solid var(--border); border-radius: 11px; padding: 14px 16px; }
  .mnt-card.mnt-ops { grid-column: span 2; }
  /* Charts run the full row whatever the column count: the time axis is the point, and at
     `span 2` of a six-column grid it would be squashed into a third of the page. */
  .mnt-card.span2 { grid-column: 1 / -1; }
  @media (max-width: 720px) { .mnt-card.mnt-ops, .mnt-card.span2 { grid-column: auto; } .mnt { padding: 16px; } }
  .mnt-card h3 { margin: 0 0 10px; font-size: 13px; display: flex; align-items: center; gap: 8px; }
  .mnt-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--muted); flex: none; }
  .mnt-dot.up { background: var(--ok); } .mnt-dot.down { background: var(--danger); }
  .mnt-body { font-size: 13px; }
  .mnt-kv { display: flex; justify-content: space-between; gap: 12px; padding: 4px 0; border-bottom: 1px solid var(--border-soft); }
  .mnt-kv:last-child { border-bottom: 0; }
  .mnt-kv .k { color: var(--faint); } .mnt-kv .v { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; text-align: right; word-break: break-word; }
  .mnt-kv .v.warn { color: var(--accent); } .mnt-kv .v.bad { color: var(--danger); } .mnt-kv .v.good { color: var(--ok); }
  .mnt-bar { height: 6px; background: var(--panel2); border-radius: 3px; overflow: hidden; margin: 5px 0 2px; }
  .mnt-bar > i { display: block; height: 100%; background: var(--accent); border-radius: 3px; }
  .mnt-metric { margin: 8px 0; }
  .mnt-metric .top { display: flex; justify-content: space-between; font-size: 12px; }
  .mnt-metric .top .k { color: var(--faint); } .mnt-metric .top .v { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .mnt-lbl { color: var(--faint); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; margin: 12px 0 5px; }
  .mnt-btns { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 2px; }
  .mnt-btn { padding: 6px 14px; font-size: 12.5px; font-weight: 600; border-radius: 7px; border: 1px solid var(--border); background: var(--panel2); color: var(--fg); cursor: pointer; }
  .mnt-btn.ok { background: var(--ok); color: #fff; border-color: transparent; }
  .mnt-btn.warn { background: var(--accent); color: var(--accent-fg); border-color: transparent; }
  .mnt-btn.danger { background: var(--danger); color: #fff; border-color: transparent; }
  .mnt-btn.ghost { background: transparent; }
  .mnt-btn:disabled { opacity: 0.4; cursor: not-allowed; }

  /* --- Charts: Prometheus history via POST /dayz/timeseries -----------------------------
     js/charts.js emits colours as style="stroke:var(--x)" rather than as presentation
     attributes, because fill="var(--x)" does not resolve. That also means a theme switch
     needs no redraw - the variables below re-resolve under :root[data-theme="dark"] on
     their own. .gap is the band drawn over a span Prometheus never collected; it is
     deliberately --danger, because a missing measurement is not a quiet condition. */
  .spark { display: block; width: 100%; height: 30px; margin-top: 3px; }
  .spark .gap, .chart .gap { fill: var(--danger); }
  .picker { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 4px 14px; margin: 4px 0 2px; }
  .picker label { display: flex; align-items: center; gap: 8px; font-size: 12.5px; padding: 3px 0; cursor: pointer; }
  .picker label.pinned { color: var(--muted); cursor: default; }
  .picker .pin { font-size: 9.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--accent); border: 1px solid var(--accent); border-radius: 999px; padding: 0 6px; margin-left: auto; }
  .picker .sname { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 10.5px; color: var(--faint); margin-left: auto; }
  .chartrow { border-top: 1px solid var(--border-soft); padding-top: 10px; margin-top: 12px; }
  .chartrow .hd { display: flex; align-items: baseline; gap: 10px; font-size: 12.5px; }
  .chartrow .hd .now { margin-left: auto; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; }
  .chart { display: block; width: 100%; height: 132px; }
  .chart .grid { stroke: var(--border-soft); stroke-width: 1; }
  .chart .axis { fill: var(--faint); font-size: 9px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .chart .gaplbl { fill: var(--danger); font-size: 9.5px; font-weight: 600; }
  .rangebtns { display: flex; gap: 6px; margin-left: auto; }
  .rangebtns button { font: inherit; font-size: 11px; padding: 3px 9px; border-radius: 6px; cursor: pointer; border: 1px solid var(--border); background: var(--panel2); color: var(--muted); }
  .rangebtns button[aria-pressed="true"] { background: var(--accent); color: var(--accent-fg); border-color: transparent; }
  /* align-items: flex-start (not center) so a wrapping label keeps the checkbox on the FIRST
     line instead of floating to the vertical middle of the two-line block; gap owns the spacing,
     flex:none keeps the box from shrinking, and the 2px nudge lines it up with the text. */
  .mnt-arm, .mnt-force { display: inline-flex; align-items: flex-start; gap: 6px; cursor: pointer; user-select: none; font-size: 12.5px; line-height: 1.4; }
  .mnt-force { color: var(--faint); margin-top: 6px; }
  .mnt-arm input, .mnt-force input { cursor: pointer; margin: 2px 0 0; flex: none; }
  .mnt-map { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--border-soft); }
  .mnt-map-row { display: flex; gap: 8px; }
  .mnt-map-row select { flex: 1; min-width: 0; padding: 6px 8px; border-radius: 7px; background: var(--panel2); color: var(--fg); border: 1px solid var(--border); font-size: 12.5px; }
  .mnt-msg { width: 95%; box-sizing: border-box; resize: vertical; padding: 8px 10px; border-radius: 8px; background: var(--panel2); color: var(--fg); border: 1px solid var(--border); font-size: 13px; font-family: inherit; }
  .mnt-log { margin: 4px 0 0; background: var(--pre-bg); color: var(--pre-fg); border-radius: 7px; padding: 10px 12px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; white-space: pre-wrap; word-break: break-word; max-height: 160px; overflow: auto; }
  .mnt-players { list-style: none; margin: 0; padding: 0; max-height: 220px; overflow: auto; }
  .mnt-players li { display: flex; justify-content: space-between; gap: 10px; padding: 4px 0; border-bottom: 1px solid var(--border-soft); font-size: 12.5px; }
  .mnt-players li:last-child { border-bottom: 0; }
  .mnt-players .pn { font-weight: 600; } .mnt-players .pp { color: var(--faint); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .mnt-nav { padding: 10px; }
  .mnt-nav-role { font-size: 12px; color: var(--faint); padding: 6px 8px; }
  .mnt-nav-role span { font-weight: 700; }
  #statsbar .sb-stat { display: inline-flex; align-items: baseline; gap: 6px; white-space: nowrap; }
  #statsbar .sb-k { color: var(--muted); }
  #statsbar .sb-v { color: var(--fg); font-weight: 600; font-variant-numeric: tabular-nums; }
  #statsbar .sb-state { display: inline-flex; align-items: center; gap: 7px; font-weight: 600; color: var(--fg); }
  #statsbar .sb-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--faint); flex: none; }
  #statsbar.sb-up .sb-dot { background: var(--ok); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 22%, transparent); }
  #statsbar.sb-down .sb-dot { background: var(--danger); box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 22%, transparent); }
  #statsbar .sb-foot { color: var(--faint); font-size: 11px; }
  #statsbar .sb-err { color: var(--danger); }
  #sidebar { background: var(--rail); border-right: 1px solid var(--border); display: flex; flex-direction: column; min-height: 0; }
  .side-brand { display: flex; align-items: center; gap: 8px; padding: 16px 16px 8px; font-size: 16px; font-weight: 700; letter-spacing: .3px; }
  .theme-toggle { margin-left: auto; flex: none; width: 30px; height: 30px; padding: 0; display: inline-flex; align-items: center; justify-content: center;
    font-size: 15px; line-height: 1; border-radius: 7px; background: transparent; color: var(--muted); border: 1px solid var(--border); cursor: pointer; }
  .theme-toggle:hover { color: var(--fg); border-color: var(--faint); background: var(--panel2); }
  .side-brand b { color: var(--accent); }
  .side-sub { padding: 0 16px 10px; color: var(--faint); font-size: 12px; }
  .side-nav { display: flex; flex-direction: column; gap: 2px; padding: 2px 10px 8px; }
  .snav { text-align: left; padding: 8px 12px; border-radius: 8px; border: 1px solid transparent; background: transparent; color: var(--muted); font-size: 13px; display: flex; align-items: center; gap: 9px; }
  .snav:hover { background: var(--panel2); color: var(--fg); }
  .snav.active { background: var(--accent-weak); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 30%, transparent); }
  .snav .ic { width: 15px; height: 15px; flex: none; }
  .side-hr { height: 1px; background: var(--border); margin: 4px 14px; }
  .side-scroll { flex: 1; overflow-y: auto; min-height: 0; padding: 4px 8px 12px; }
  .side-foot { padding: 10px 12px; border-top: 1px solid var(--border); }
  .side-foot .ghost { width: 100%; }

  /* file tree (sidebar) */
  .side-grp { margin: 1px 0; }
  .side-grp > summary { list-style: none; cursor: pointer; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; color: var(--faint); padding: 7px 8px 5px; display: flex; align-items: center; gap: 7px; }
  .side-grp > summary::-webkit-details-marker { display: none; }
  .side-grp > summary::before { content: "▸"; font-size: 9px; }
  .side-grp[open] > summary::before { content: "▾"; }
  .side-count { margin-left: auto; }
  /* Patrols group add/delete buttons (in the group summary) */
  .side-grp > summary .grp-btns { display: inline-flex; gap: 4px; }
  .side-grp > summary .grp-btns button { width: 18px; height: 18px; line-height: 15px; text-align: center; padding: 0; border-radius: 4px; border: 1px solid var(--border); background: var(--panel2); color: var(--muted); font-size: 13px; font-weight: 700; cursor: pointer; }
  .side-grp > summary .grp-add:hover { color: var(--ok); border-color: var(--ok); }
  .side-grp > summary .grp-del:hover { color: var(--danger); border-color: var(--danger); }
  .side-sub2 { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; color: var(--faint); padding: 6px 8px 2px 22px; }
  /* Tree indent: one depth number (--d, set per element) times one step, so nesting costs no
     rule per level. Scoped to the file tree - .side-sub2 is also the Map/Logs nav caption,
     which has no depth. The 0 fallback keeps every other .side-item at its original inset. */
  #filesNav .side-sub2 { font-size: 11.5px; font-weight: 600; color: var(--muted); padding: 9px 8px 3px calc(10px + var(--d, 0) * 12px); }
  .side-item { display: flex; align-items: center; gap: 8px; padding: 6px 10px 6px calc(10px + var(--d, 0) * 12px); margin: 1px 0 1px 8px; border-radius: 7px; border: 1px solid transparent; cursor: pointer; }
  /* min-width:0 - as a flex item the input will not shrink below its intrinsic field width
     (~20 characters) without it, so a narrow sidebar overflows however the width is set. */
  .files-filter { width: calc(100% - 28px); min-width: 0; margin: 6px 14px; padding: 6px 9px; border-radius: 7px; border: 1px solid var(--border); background: var(--panel2); color: var(--fg); font-size: 12.5px; }
  .files-filter:focus { outline: none; border-color: var(--accent); }
  .side-item .fn { flex: 1; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .side-item:hover { background: var(--panel2); } .side-item:hover .fn { color: var(--fg); }
  .side-item.active { background: var(--accent-weak); border-color: color-mix(in srgb, var(--accent) 30%, transparent); } .side-item.active .fn { color: var(--accent); font-weight: 600; }
  /* badges: green N = captured overrides; rw = box-owned whole-file; ro = locked (not patchable) */
  .own-badge { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; font-weight: 700; color: var(--accent); background: var(--accent-weak); border-radius: 999px; padding: 1px 6px; }
  /* "edited here" - the box captured a frozen baseline for this file, so it has been saved through
     the editor at least once. Beside the NAME, never in the badge slot - a second thing there
     would displace the access badge. Muted, because it is context and not a warning. */
  .side-item .edited-mark { color: var(--accent); font-size: 11px; margin-left: 5px; opacity: .85; cursor: help; }
  .side-item.active .edited-mark { opacity: 1; }
  .ro-badge { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; font-weight: 700; color: var(--faint); background: var(--panel2); border: 1px solid var(--border-soft); border-radius: 999px; padding: 0 6px; }
  .own-ta { display: block; width: 100%; min-height: 55vh; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; line-height: 1.6; background: var(--pre-bg); color: var(--pre-fg); border: none; border-radius: 0; padding: 16px 22px; resize: vertical; }
  .own-ta:focus { outline: 2px solid var(--accent); outline-offset: -2px; }

  /* ---------- workspace (content) ---------- */
  #workspace { overflow-y: auto; min-height: 0; }
  .doc-crumb { position: sticky; top: 0; z-index: 2; padding: 8px 22px; border-bottom: 1px solid var(--border-soft); background: var(--panel2); font-size: 12px; color: var(--muted); }
  .doc-raw pre { margin: 0; padding: 16px 22px 60px; white-space: pre-wrap; word-break: break-word; font: 12.5px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace; }
  .doc-md { max-width: 900px; padding: 18px 26px 64px; line-height: 1.62; font-size: 14.5px; }
  .doc-md h1, .doc-md h2, .doc-md h3, .doc-md h4 { line-height: 1.25; margin: 1.3em 0 .5em; text-wrap: balance; }
  .doc-md h1 { font-size: 1.7em; border-bottom: 1px solid var(--border-soft); padding-bottom: .25em; }
  .doc-md h2 { font-size: 1.35em; border-bottom: 1px solid var(--border-soft); padding-bottom: .2em; }
  .doc-md h3 { font-size: 1.15em; } .doc-md h4 { font-size: 1em; color: var(--muted); }
  .doc-md p { margin: .7em 0; } .doc-md ul, .doc-md ol { margin: .6em 0; padding-left: 1.6em; } .doc-md li { margin: .2em 0; }
  .doc-md a { color: var(--accent); } .doc-md hr { border: none; border-top: 1px solid var(--border); margin: 1.4em 0; }
  .doc-md code { background: var(--panel2); border: 1px solid var(--border-soft); border-radius: 4px; padding: .1em .35em; font: .88em ui-monospace, SFMono-Regular, Menlo, monospace; }
  .doc-md pre.doc-code { background: var(--panel2); border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; overflow-x: auto; font: 12.5px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace; }
  .doc-item .fn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .page-head { display: flex; align-items: center; gap: 12px; padding: 15px 22px 13px; border-bottom: 1px solid var(--border); }
  .ph-title { font-size: 15px; font-weight: 650; }
  .empty { display: flex; align-items: center; justify-content: center; min-height: 55vh; color: var(--faint); font-size: 14px; padding: 40px; text-align: center; }

  pre { background: var(--pre-bg); color: var(--pre-fg); padding: 18px 22px; overflow: auto; font-size: 13px; line-height: 1.6; margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  /* token colours — tuned for the always-dark code surface (--pre-bg) */
  .t-key { color: #79c0ff; } .t-str { color: #a5d6ff; } .t-num { color: #f0883e; }
  .t-kw { color: #ff7b72; } .t-com { color: #8b949e; font-style: italic; } .t-tag { color: #7ee787; }

  /* ---------- file editor (content pane; tree lives in the sidebar) ---------- */
  #editorPage { display: flex; flex-direction: column; min-height: 100%; }
  #edEditor { display: flex; flex-direction: column; flex: 1; min-height: 0; }
  .ovr-empty { flex: 1; }
  .ovr-phead { position: sticky; top: 0; z-index: 6; display: flex; align-items: center; gap: 12px; padding: 12px 22px; border-bottom: 1px solid var(--border); background: color-mix(in srgb, var(--bg) 92%, transparent); backdrop-filter: blur(6px); flex-wrap: wrap; }
  .ovr-ppath { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .ovr-ppath .crumb { font-size: 11px; color: var(--faint); font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
  .ovr-ppath .nm { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 14px; color: var(--fg); font-weight: 600; word-break: break-all; }
  .ovr-pact { display: flex; align-items: center; gap: 10px; margin-left: auto; flex-wrap: wrap; }
  .ovr-unsaved { display: none; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--danger);
    background: color-mix(in srgb, var(--danger) 12%, transparent); border: 1px solid color-mix(in srgb, var(--danger) 35%, transparent);
    border-radius: 999px; padding: 3px 10px; }
  .ovr-unsaved.on { display: inline-flex; }
  .ovr-unsaved .ud-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--danger); flex: none; }
  .seg { display: inline-flex; background: var(--panel2); border: 1px solid var(--border); border-radius: 7px; padding: 2px; }
  .seg button { padding: 5px 13px; border: none; border-radius: 5px; background: transparent; color: var(--muted); font-size: 12px; }
  .seg button.on { background: var(--card); color: var(--fg); box-shadow: var(--shadow); }
  .btn-sm { font-size: 13px; padding: 7px 15px; border-radius: 7px; border: 1px solid var(--border); background: var(--panel2); color: var(--fg); display: inline-flex; align-items: center; gap: 6px; }
  .btn-sm:hover { border-color: var(--faint); }
  .btn-sm.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); }
  .btn-sm.primary:hover { filter: brightness(1.06); }
  .ovr-sum { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; padding: 9px 22px; border-bottom: 1px solid var(--border-soft); background: var(--panel2); font-size: 12.5px; color: var(--muted); }
  .stat { display: inline-flex; align-items: center; gap: 7px; } .stat b { color: var(--fg); font-variant-numeric: tabular-nums; } .stat.d b { color: var(--delta); }
  .dot { width: 8px; height: 8px; border-radius: 50%; } .dot.d { background: var(--delta); } .dot.b { background: var(--faint); }
  /* w = the state is wrong and needs a decision (override rows against a file the box does not have) */
  .stat.w { color: var(--drift); } .dot.w { background: var(--drift); }
  /* "About this file" - registry about/aboutUrl, rendered under the filename in every chrome */
  .ovr-about { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; padding: 8px 22px; border-bottom: 1px solid var(--border-soft); font-size: 12.5px; color: var(--muted); line-height: 1.45; }
  .ovr-about .about-lbl { flex: none; font-size: 10.5px; letter-spacing: .06em; text-transform: uppercase; color: var(--faint); }
  .ovr-about .about-txt { min-width: 0; }
  .ovr-about .about-src { flex: none; color: var(--accent); text-decoration: none; border-bottom: 1px dotted currentColor; }
  .ovr-about .about-src:hover { text-decoration: none; opacity: .8; }
  .ovr-body { flex: 1; }
  .ovr-note { padding: 11px 22px; font-size: 12.5px; color: var(--muted); border-bottom: 1px solid var(--border-soft); } .ovr-note b { color: var(--fg); }

  /* fields */
  .fld { display: grid; grid-template-columns: minmax(160px,280px) 1fr auto 30px; align-items: center; gap: 14px; padding: 8px 22px 8px 19px; border-left: 3px solid transparent; border-bottom: 1px solid var(--border-soft); }
  .fld .k { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; color: var(--fg); word-break: break-word; }
  .fld .v { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; color: var(--faint); word-break: break-all; cursor: pointer; }
  .fld input, .fld textarea { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; padding: 6px 9px; border-radius: 6px; background: var(--pre-bg); color: var(--pre-fg); border: 1px solid var(--border); }
  .fld textarea { resize: vertical; min-height: 34px; }
  .fld input:focus, .fld textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
  .base { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; color: var(--faint); white-space: nowrap; }
  .tag { font-size: 10px; font-weight: 700; letter-spacing: .4px; text-transform: uppercase; padding: 2px 7px; border-radius: 999px; color: var(--delta); background: var(--delta-weak); }
  .tag.warn { color: var(--danger); background: color-mix(in srgb, var(--danger) 15%, transparent); }
  .tag.cx { color: var(--accent); background: var(--accent-weak); }
  .tag.all { color: var(--info); background: var(--info-weak); }
  .x { cursor: pointer; color: var(--faint); background: transparent; border: none; border-radius: 6px; width: 26px; height: 26px; padding: 0; opacity: 0; }
  .fld:hover .x { opacity: 1; } .x:hover { color: var(--danger); background: var(--panel2); }
  .fld.over { border-left-color: var(--delta); background: linear-gradient(90deg, var(--delta-weak), transparent 55%); }
  .fld.ctx .k { color: var(--muted); }
  .fld.ctx .addb { font-size: 11px; cursor: pointer; color: var(--faint); background: transparent; border: 1px solid var(--border); border-radius: 999px; padding: 2px 10px; opacity: 0; }
  .fld.ctx:hover .addb { opacity: 1; } .fld.ctx:hover { background: var(--panel2); }
  .fld.ctx .addb:hover { color: var(--delta); border-color: var(--delta); }
  /* Fields-view filter + capped-list expander */
  .fld-more { padding: 10px 22px 4px; }

  /* file view */
  .fileview pre { border-radius: 0; }
  .xeval { display: flex; flex-direction: column; gap: 4px; padding: 10px 22px; border-bottom: 1px solid var(--border-soft); background: var(--panel2); font-size: 12px; }
  .xeval .sel { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--fg); word-break: break-all; }


  /* API page */
  #swagger { margin: 0; background: #fff; }
  #apiNav .meta { padding: 12px 10px; }

  /* toast */
  .toast { position: fixed; bottom: 22px; left: 50%; transform: translateX(-50%) translateY(20px); background: var(--fg); color: var(--bg); font-weight: 600; font-size: 13px; padding: 10px 18px; border-radius: 999px; box-shadow: var(--shadow); opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s; z-index: 50; max-width: 80vw; }
  .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
  .toast.ok { background: var(--delta); color: #04210f; } .toast.err { background: var(--danger); color: #fff; }

  /* ---------- Map tab (AI coordinates from VPP bookmarks) ---------- */
  /* Delta status colors — contrast + CVD validated against both surfaces. The amber↔red
     pair sits in the CVD floor band, so serious (>2 m) points ALSO change shape to a
     square and every delta is printed as a number in the list: color is never alone. */
  :root { --map-ok: #1a8a44; --map-warn: #b06008; --map-bad: #c33327; }
  :root[data-theme="dark"] { --map-ok: #3aa957; --map-warn: #c07f24; --map-bad: #ef5b52; }
  .map-head-sel { width: auto; font-size: 13px; padding: 6px 10px; border-radius: 7px; background: var(--panel2); color: var(--fg); border: 1px solid var(--border); }
  /* Map body: the stage flexes to fill; toggles + filters live in a fixed rail on the right. */
  .map-body { display: flex; gap: 12px; align-items: flex-start; margin: 12px 22px 0; }
  .map-body .map-stage { margin: 0; flex: 1 1 auto; min-width: 0; }
  .map-rail { flex: 0 0 226px; height: min(85vh, 1000px); overflow-y: auto; display: flex; flex-direction: column; gap: 12px; }
  .mr-tools { display: flex; flex-wrap: wrap; gap: 8px; }
  .map-rail .map-filter { padding: 0; border-bottom: none; background: none; align-content: flex-start; gap: 5px; }
  .map-rail .map-filter .mf-label { flex-basis: 100%; margin: 0 0 1px; }
  .mr-help { margin-top: auto; padding-top: 4px; font-size: 11px; line-height: 1.45; color: var(--faint); }
  @media (max-width: 760px) { .map-body { flex-direction: column; } .map-body .map-stage { width: 100%; height: 56vh; } .map-rail { flex-basis: auto; width: 100%; height: auto; max-height: 320px; } }

  /* Resizable panels: sidebar (grid column), detail + rail (flex order + basis). Widths persist via JS.
     The map stage is flex:1 so it absorbs slack and collapses; a ResizeObserver re-fits the canvas. */
  #sidebar { position: relative; }
  .rz { flex: none; align-self: stretch; width: 10px; cursor: col-resize; position: relative; touch-action: none; }
  .rz::after { content: ""; position: absolute; top: 0; bottom: 0; left: 4px; width: 2px; border-radius: 2px; background: var(--border); opacity: .5; transition: opacity .12s, background .12s, width .12s; }
  .rz:hover::after, .rz.drag::after { opacity: 1; background: var(--accent); width: 3px; left: 3.5px; }
  .rz-side { position: absolute; top: 0; right: -2px; bottom: 0; width: 9px; align-self: auto; z-index: 6; }
  .rz-side::after { left: 3px; }
  .map-body .map-detail { order: 1; }
  .map-body .rz-detail { order: 2; }
  .map-body .map-stage { order: 3; }
  .map-body .rz-rail { order: 4; }
  .map-body .map-rail { order: 5; }
  .map-body:has(#mapDetail.hidden) .rz-detail { display: none; }
  body.resizing { cursor: col-resize; user-select: none; }
  @media (max-width: 760px) { .rz { display: none; } }
  /* The stage is a pan/zoom canvas viewport (terrain tiles + grid + bookmarks). */
  .map-stage { position: relative; margin: 12px 22px 0; height: min(85vh, 1000px); border: 1px solid var(--border); border-radius: 10px; overflow: hidden; background: var(--panel2); }
  #mapCanvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block; cursor: crosshair; touch-action: none; }
  .map-stage .empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; z-index: 2; background: color-mix(in srgb, var(--panel2) 82%, transparent); }
  .map-bar { display: flex; align-items: baseline; gap: 16px; flex-wrap: wrap; margin: 0 22px; padding: 8px 4px 2px; font: 12px ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--muted); }
  .map-bar b { color: var(--fg); font-weight: 600; }
  .map-bar .mp-live { display: inline-flex; align-items: center; gap: 6px; color: var(--info); font-weight: 600; }
  .map-bar .mp-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--info); box-shadow: 0 0 0 2px color-mix(in srgb, var(--info) 25%, transparent); }
  .map-bar .mp-bandit { display: inline-flex; align-items: center; gap: 6px; color: var(--map-bad); font-weight: 600; cursor: help; }
  .map-bar .mb-dot { width: 8px; height: 8px; background: var(--map-bad); transform: rotate(45deg); box-shadow: 0 0 0 2px color-mix(in srgb, var(--map-bad) 22%, transparent); }
  .map-bar .mp-stale { color: var(--muted); font-weight: 600; font-style: italic; cursor: help; }
  .map-seg { display: inline-flex; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
  .map-seg button { font-size: 12px; padding: 5px 11px; background: var(--panel2); color: var(--muted); border: none; cursor: pointer; }
  .map-seg button + button { border-left: 1px solid var(--border); }
  .map-seg button.active { background: var(--accent); color: #fff; }
  /* layer switcher can hold many layers — let it wrap into pills instead of clipping */
  #mapLayerSeg { flex-wrap: wrap; overflow: visible; border: none; gap: 4px; background: none; }
  #mapLayerSeg button { border: 1px solid var(--border); border-radius: 6px; }
  #mapLayerSeg button + button { border-left: 1px solid var(--border); }
  .map-filter { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 8px 22px; border-bottom: 1px solid var(--border-soft); background: var(--panel2); }
  .map-filter .mf-label { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--faint); margin-right: 2px; }
  .mf-chip { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; padding: 4px 10px; border: 1px solid var(--border); border-radius: 999px; background: var(--panel); color: var(--muted); cursor: pointer; }
  .mf-chip b { font-variant-numeric: tabular-nums; opacity: .7; font-weight: 600; }
  .mf-ico { flex: 0 0 auto; vertical-align: middle; }
  .map-tip .mf-ico { vertical-align: -2px; margin-right: 4px; }
  .mf-chip.active { background: var(--accent); border-color: var(--accent); color: #fff; }
  .mf-chip.active b { opacity: .85; }
  .mf-chip.mf-all { font-weight: 600; }
  /* Colour-coded overlay chips: a swatch keys the on-map colour; the active chip fills with it. */
  .map-ovf .mf-label { min-width: 42px; }
  .mf-chip.mf-dot { display: inline-flex; align-items: center; gap: 6px; }
  .mf-swatch { width: 9px; height: 9px; border-radius: 2px; background: var(--dot, var(--faint)); box-shadow: inset 0 0 0 1px rgba(0,0,0,.3); flex: none; }
  .mf-chip.mf-dot.active { background: var(--dot); border-color: var(--dot); color: var(--dot-fg, #fff); }
  .mf-chip.mf-dot.active .mf-swatch { display: none; }
  .map-tip { position: fixed; z-index: 40; pointer-events: none; background: var(--card); color: var(--fg); border: 1px solid var(--border); border-radius: 8px; padding: 8px 11px; font-size: 12px; line-height: 1.45; box-shadow: var(--shadow); max-width: 300px; display: none; }
  /* Point detail = a right sidebar inside .map-body; the map (.map-stage flex:1) shrinks when it opens. */
  .map-detail { order: -1; flex: 0 0 320px; align-self: stretch; max-height: min(85vh, 1000px); overflow-y: auto; margin: 0; border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; display: flex; flex-direction: column; gap: 11px; align-items: stretch; font-size: 13px; }
  .map-detail.hidden { display: none; }
  .map-detail .k2 { color: var(--faint); font-size: 10px; text-transform: uppercase; letter-spacing: .5px; }
  .map-detail:not(.editing) > span { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
  /* Waypoint list + buttons in the patrol editor (drag dots on the map to move). */
  .map-detail .me-btns { display: flex; gap: 8px; border-top: 1px solid var(--border-soft); padding-top: 9px; margin-top: 3px; }
  .map-detail .me-wps { display: flex; flex-direction: column; gap: 5px; margin-top: 2px; border-top: 1px solid var(--border); padding-top: 10px; }
  .map-detail .me-wp { display: flex; justify-content: space-between; align-items: center; gap: 8px; font-size: 12px; }
  .map-detail .me-wp .me-wp-n { flex: none; width: 15px; color: var(--faint); font-size: 11px; text-align: right; }
  .map-detail .me-wp .me-wpin { flex: 1; min-width: 0; box-sizing: border-box; background: var(--panel2); border: 1px solid var(--border); border-radius: 5px; color: var(--fg); font-size: 12px; padding: 3px 6px; }
  .map-detail .me-wp .me-wpin:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
  .map-detail .me-wp-del { background: none; border: none; color: var(--danger); cursor: pointer; font-size: 12px; line-height: 1; padding: 0 4px; }
  .map-detail .me-wp-hint { color: var(--faint); font-size: 10px; }
  .dot.mok { background: var(--map-ok); } .dot.mwarn { background: var(--map-warn); }
  .dot.mbad { background: var(--map-bad); border-radius: 2px; } .dot.mnull { background: var(--faint); }
  .mp-badge { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; font-weight: 700; border-radius: 999px; padding: 1px 7px; white-space: nowrap; }
  .mp-badge.mok { color: var(--map-ok); background: color-mix(in srgb, var(--map-ok) 13%, transparent); }
  .mp-badge.mwarn { color: var(--map-warn); background: color-mix(in srgb, var(--map-warn) 14%, transparent); }
  .mp-badge.mbad { color: var(--map-bad); background: color-mix(in srgb, var(--map-bad) 14%, transparent); }
  .mp-badge.mnull { color: var(--faint); background: var(--panel2); }
  /* Nav quick-filter: sticky at the top of the scrolling list so it stays put while the list scrolls. */
  .mp-filterbar { position: sticky; top: 0; z-index: 3; background: var(--rail); padding: 6px 10px 6px 12px; display: flex; flex-direction: column; gap: 6px; }
  .mp-filter { width: 100%; box-sizing: border-box; background: var(--panel2); border: 1px solid var(--border); border-radius: 7px; color: var(--fg); font: inherit; font-size: 12px; padding: 5px 9px; }
  .mp-filter:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
  .mp-grpseg { display: inline-flex; align-self: flex-start; border: 1px solid var(--border); border-radius: 7px; overflow: hidden; }
  .mp-grpseg button { background: var(--panel2); color: var(--muted); border: 0; border-left: 1px solid var(--border); font: inherit; font-size: 11px; font-weight: 600; padding: 3px 10px; cursor: pointer; }
  .mp-grpseg button:first-child { border-left: 0; }
  .mp-grpseg button.on { background: var(--accent); color: var(--accent-fg); }
  .mp-empty { padding: 10px 12px; color: var(--faint); font-size: 12px; }

  @media (max-width: 780px) {
    #app { grid-template-columns: 1fr; height: auto; }
    #sidebar { border-right: none; border-bottom: 1px solid var(--border); }
    .side-scroll { max-height: 40vh; }
    .fld { grid-template-columns: 1fr; gap: 6px; }
  }

  /* ===== Swagger UI dark theme (scoped to #swagger; wins over the vendored light css) =====
     Nested under :root[data-theme="dark"] so it follows the manual toggle, not just the OS. */
  :root[data-theme="dark"] {
    #swagger, #swagger .swagger-ui { background: var(--card); }
    #swagger .swagger-ui .info .title,
    #swagger .swagger-ui .info li, #swagger .swagger-ui .info p, #swagger .swagger-ui .info table,
    #swagger .swagger-ui .info h1, #swagger .swagger-ui .info h2, #swagger .swagger-ui .info h3,
    #swagger .swagger-ui .info h4, #swagger .swagger-ui .info h5,
    #swagger .swagger-ui .opblock-tag,
    #swagger .swagger-ui .opblock .opblock-summary-operation-id,
    #swagger .swagger-ui .opblock .opblock-summary-path,
    #swagger .swagger-ui .opblock .opblock-summary-path__deprecated,
    #swagger .swagger-ui .opblock .opblock-summary-description,
    #swagger .swagger-ui .opblock-description-wrapper p,
    #swagger .swagger-ui .opblock-external-docs-wrapper p,
    #swagger .swagger-ui .opblock-title_normal p,
    #swagger .swagger-ui .opblock .opblock-section-header h4,
    #swagger .swagger-ui .opblock .opblock-section-header > label,
    #swagger .swagger-ui .tab li,
    #swagger .swagger-ui .parameter__name,
    #swagger .swagger-ui .parameter__type,
    #swagger .swagger-ui .parameters-col_description p,
    #swagger .swagger-ui table thead tr td, #swagger .swagger-ui table thead tr th,
    #swagger .swagger-ui .response-col_status,
    #swagger .swagger-ui .response-col_links,
    #swagger .swagger-ui .responses-inner h4, #swagger .swagger-ui .responses-inner h5,
    #swagger .swagger-ui .model-title, #swagger .swagger-ui .model,
    #swagger .swagger-ui section.models h4, #swagger .swagger-ui section.models h5,
    #swagger .swagger-ui .prop-type,
    #swagger .swagger-ui .servers > label,
    #swagger .swagger-ui label { color: var(--fg); }
    #swagger .swagger-ui .opblock-tag small,
    #swagger .swagger-ui .parameter__in,
    #swagger .swagger-ui .parameter__extension,
    #swagger .swagger-ui .response-col_description,
    #swagger .swagger-ui table.model tr.property-row td:first-child { color: var(--muted); }
    #swagger .swagger-ui a, #swagger .swagger-ui .info a, #swagger .swagger-ui .info a.link { color: var(--accent); }
    #swagger .swagger-ui .expand-methods svg, #swagger .swagger-ui .expand-operation svg,
    #swagger .swagger-ui .model-toggle:after, #swagger .swagger-ui svg.arrow { fill: var(--fg); }
    #swagger .swagger-ui .scheme-container, #swagger .swagger-ui section.models,
    #swagger .swagger-ui section.models .model-container, #swagger .swagger-ui .model-box,
    #swagger .swagger-ui .opblock .opblock-section-header, #swagger .swagger-ui .responses-inner { background: var(--card); }
    #swagger .swagger-ui .opblock-tag, #swagger .swagger-ui section.models,
    #swagger .swagger-ui section.models .model-container,
    #swagger .swagger-ui .opblock .opblock-section-header,
    #swagger .swagger-ui table tbody tr td { border-color: var(--border); }
    #swagger .swagger-ui input[type=text], #swagger .swagger-ui input[type=password],
    #swagger .swagger-ui input[type=search], #swagger .swagger-ui input[type=email],
    #swagger .swagger-ui input[type=file], #swagger .swagger-ui textarea, #swagger .swagger-ui select {
      background: var(--pre-bg); color: var(--fg); border-color: var(--border); }
    #swagger .swagger-ui .highlight-code > .microlight, #swagger .swagger-ui .microlight code { color: var(--pre-fg); }
    #swagger .swagger-ui .opblock .opblock-section-header { box-shadow: none; }
  }
  @media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
  
  .logo a, a:visited{
    text-decoration: none;
    color: inherit;
  }

  /* --- Logs tab: mono scrollback pane with line numbers + filter highlights --- */
  .log-pane { position: relative; height: min(72vh, 920px); overflow: auto; background: var(--card);
    border: 1px solid var(--border); border-radius: 10px;
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; line-height: 1.5; }
  .log-lines { padding: 6px 0 8px; width: max-content; min-width: 100%; }
  .ll { display: flex; gap: 12px; padding: 0 14px 0 8px; white-space: pre; }
  .ll:hover { background: var(--panel2); }
  .ll .ln { color: var(--faint); min-width: 64px; text-align: right; flex: none; user-select: none; cursor: pointer; }
  .ll .ln:hover { color: var(--accent); }
  .ll .lt .ts { color: var(--faint); }
  .ll.lwarn .lt { color: var(--map-warn); }
  .ll.lerr .lt { color: var(--map-bad); }
  .ll .lt mark { background: var(--accent-weak); color: var(--accent); border-radius: 3px; padding: 0 1px; }
  /* Chat view (logs.js chat source): day divider heads the file, then [time] [channel] <name> message */
  .ll.chat-line .lt { white-space: pre-wrap; }
  .chat-ts { color: var(--faint); }
  .chat-sep { color: var(--border); }
  .chat-ch { color: var(--info); }
  .chat-name { color: var(--accent); font-weight: 700; }
  .chat-msg { color: var(--fg); }
  .ll.chat-day { padding: 6px 0 4px; }
  .ll.chat-day .lt { display: flex; align-items: center; justify-content: center; gap: 8px;
    color: var(--faint); white-space: nowrap; overflow: hidden; }
  .chat-day-rule { color: var(--border); overflow: hidden; }
  .chat-day-date { color: var(--muted); font-weight: 700; letter-spacing: 0.04em; }
  .log-sentinel { text-align: center; color: var(--faint); font-size: 11px; padding: 4px 0; }
  .log-filter { width: 300px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px;
    padding: 6px 10px; border-radius: 7px; background: var(--panel2); color: var(--fg); border: 1px solid var(--border); }
  .log-filter.badre { outline: 2px solid var(--map-bad); }
  .log-goto { width: 92px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px;
    padding: 6px 10px; border-radius: 7px; background: var(--panel2); color: var(--fg); border: 1px solid var(--border); }
  .log-aa { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; padding: 6px 9px; }
  .log-aa.on { color: var(--accent); border-color: var(--accent); }
  .log-follow { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--muted); white-space: nowrap; cursor: pointer; }
  /* Logs left column: a date picker (defaults to today) narrows the file list to
     one day; the dropdown then picks the session within it. RPT/ADM split into
     optgroups, newest session first. */
  .log-picker { padding: 8px 8px 2px; display: flex; flex-direction: column; gap: 8px; }
  .lp-row { display: flex; align-items: center; gap: 8px; }
  .lp-lbl { font-size: 12px; color: var(--faint); width: 34px; flex: none; }
  .lp-date { flex: 1; min-width: 0; font-size: 13px; padding: 6px 8px; border-radius: 7px;
    background: var(--panel2); color: var(--fg); border: 1px solid var(--border); color-scheme: light; }
  :root[data-theme="dark"] .lp-date { color-scheme: dark; }
  .lp-sel { width: 100%; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px;
    padding: 6px 8px; border-radius: 7px; background: var(--panel2); color: var(--fg); border: 1px solid var(--border); }
  .lp-sel:disabled { color: var(--faint); }

  /* Whole-file Edit mode + saving spinner (js/editor.js) */
  /* structured-editor host (the json-editor mounts inside): its own scroll box so the sticky path
     bar pins to the top and a deep/large file scrolls within the frame instead of the whole page. */
  /* Third edit surface, same treatment as .own-cm: left thread rule, no box. */
  .wf-json { border: none; border-left: 2px solid var(--border); border-radius: 0; background: var(--card);
    padding: 8px 10px 8px 12px; min-height: 200px; max-height: 64vh; overflow: auto; }
  .wf-json:focus-within { border-left-color: var(--accent); }
  .meta.warn { color: var(--danger); }

  /* --- serverDZ.cfg day/night cycle (Server settings row) ---------------------------------
     The two acceleration multipliers are meaningless as bare numbers, so the panel converts
     them to the real-world clock the players actually feel. Math: docs/SETUP.md. */
  .cyc { margin: 0 0 14px; padding: 14px 16px; border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent); border-radius: 10px; background: var(--accent-weak); }
  .cyc h4 { margin: 0 0 2px; font-size: 13.5px; }
  .cyc .cyc-sub { margin: 0 0 12px; font-size: 12px; opacity: .75; }
  .cyc-grid { display: grid; grid-template-columns: minmax(210px, 1fr) minmax(210px, 1fr); gap: 12px 20px; }
  @media (max-width: 720px) { .cyc-grid { grid-template-columns: 1fr; } }
  .cyc-ctl label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 5px; }
  .cyc-ctl .cyc-row { display: flex; align-items: center; gap: 10px; }
  .cyc-ctl input[type=range] { flex: 1; min-width: 0; accent-color: var(--accent); }
  .cyc-ctl input[type=number] { width: 74px; padding: 5px 7px; font-variant-numeric: tabular-nums; }
  .cyc-ctl .cyc-hint { display: block; font-size: 11.5px; opacity: .7; margin-top: 4px; }
  .cyc-out { margin-top: 14px; }
  .cyc-bar { display: flex; height: 26px; border-radius: 6px; overflow: hidden; border: 1px solid color-mix(in srgb, var(--fg) 20%, transparent); }
  .cyc-bar > i { display: flex; align-items: center; justify-content: center; font-style: normal; font-size: 11.5px; font-weight: 700; white-space: nowrap; overflow: hidden; }
  .cyc-bar > i.day { background: var(--accent); color: var(--accent-fg); }
  .cyc-bar > i.night { background: #16202e; color: #cfd9e4; }
  .cyc-nums { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-top: 10px; font-size: 12.5px; }
  .cyc-nums b { font-variant-numeric: tabular-nums; }
  .cyc-warn { margin-top: 10px; font-size: 12px; color: var(--danger); font-weight: 600; }
  .cyc-note { margin-top: 10px; font-size: 11.5px; opacity: .7; }

  /* Comment column: shown only for field lists whose file carries a "_help" map. Adds a fifth
     grid column; lists without help keep the original four. */
  .fields.with-help .fld { grid-template-columns: minmax(140px,220px) minmax(110px,1fr) minmax(170px,1.5fr) auto 30px; }
  @media (max-width: 900px) { .fields.with-help .fld { grid-template-columns: minmax(140px,220px) minmax(110px,1fr) auto 30px; } }
  .cyc-foot { display: flex; align-items: center; gap: 12px; margin-top: 12px; }
  .cyc-foot .cyc-note { margin-top: 0; flex: 1; font-size: 11.5px; opacity: .7; }
  /* A field shown under a friendlier name than the game's own key. Dotted underline + help
     cursor so it reads as an alias; the tooltip carries the real cfg key. */
  .fld .k.renamed { text-decoration: underline dotted color-mix(in srgb, var(--fg) 40%, transparent); text-underline-offset: 3px; cursor: help; }

  /* "Other links" in the Mod Docs sidebar: real anchors, so they need the side-item look
     without the default link styling, plus an arrow marking that they leave the app. */
  .side-item.doc-link { text-decoration: none; color: inherit; }
  .side-item.doc-link .ext { font-size: 11px; color: var(--faint); flex: none; }
  .side-item.doc-link:hover .ext { color: var(--accent); }

  /* ===== CE types-table editor (types-editor.js — registry web:'types' surfaces) ===== */
  .ty-bar { display: flex; align-items: center; gap: 12px; padding: 12px 22px; border-bottom: 1px solid var(--border-soft); flex-wrap: wrap; }
  .ty-bar #tyFilter { flex: 1 1 260px; max-width: 420px; padding: 7px 10px; font-size: 13px; }
  .ty-only { display: flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--muted); white-space: nowrap; cursor: pointer; }
  .ty-addbar { display: flex; align-items: center; gap: 10px; padding: 10px 22px; border-bottom: 1px solid var(--border-soft); background: var(--panel2); flex-wrap: wrap; }
  .ty-addbar #tyAddInput { flex: 1 1 280px; max-width: 420px; padding: 7px 10px; font-size: 13px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  /* Master-detail: XML preview of the selected type on the LEFT (sticky), table on the RIGHT. */
  .ty-split { display: flex; align-items: flex-start; gap: 16px; padding: 12px 22px 16px; }
  .ty-main { flex: 1 1 auto; min-width: 0; overflow-x: auto; }   /* min-width:0 lets the grid shrink; scroll as a safety valve */
  .ty-preview { flex: 0 0 340px; position: sticky; top: 8px; max-height: calc(100vh - 200px); overflow: auto;
    background: var(--pre-bg); border: 1px solid var(--border); border-radius: 8px; }
  .ty-pv-head { display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-bottom: 1px solid rgba(255,255,255,0.08);
    position: sticky; top: 0; background: var(--pre-bg); }
  .ty-pv-head .mono { color: var(--pre-fg); font-size: 12.5px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ty-pv-xml { margin: 0; padding: 12px; font-size: 12px; line-height: 1.5; color: var(--pre-fg); white-space: pre; overflow-x: auto;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .ty-pv-foot { padding: 8px 12px; border-top: 1px solid rgba(255,255,255,0.08); color: var(--faint); font-size: 11.5px; }
  .ty-pv-empty { padding: 18px 14px; color: var(--faint); font-size: 13px; line-height: 1.5; }
  .ty-head, .ty-row { display: grid; grid-template-columns: minmax(160px, 1fr) 82px 82px 82px 82px 88px minmax(124px, auto); gap: 10px; align-items: center; padding: 5px 4px; }
  .ty-head { position: sticky; top: 0; z-index: 2; background: var(--card); border-bottom: 1px solid var(--border); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--faint); padding-top: 9px; padding-bottom: 7px; }
  .ty-row { border-bottom: 1px solid var(--border-soft); cursor: pointer; }
  .ty-row.over { background: var(--delta-weak); }
  .ty-row.selected { box-shadow: inset 3px 0 0 var(--accent); background: var(--accent-weak); }
  .ty-row.cap-hide { display: none; }
  .ty-name { font-size: 12.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .ty-in { width: 100%; padding: 5px 8px; font-size: 12.5px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .ty-in.bad, .ty-nl.bad { outline: 2px solid var(--danger); }
  .ty-badge { display: flex; justify-content: center; }
  .ty-act { display: flex; gap: 6px; justify-content: flex-end; }
  .ty-act .ghost { padding: 4px 9px; font-size: 11.5px; }
  /* Expanded all-fields panel for one type */
  .ty-exp { padding: 12px 14px 14px; background: var(--panel2); border-bottom: 1px solid var(--border-soft); }
  .ty-exp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px 14px; }
  .ty-fld { display: flex; flex-direction: column; gap: 4px; font-size: 11px; color: var(--faint); text-transform: uppercase; letter-spacing: .03em; }
  .ty-fld.wide { grid-column: 1 / -1; }
  .ty-fld .ty-in, .ty-fld .ty-nl { text-transform: none; letter-spacing: normal; }
  .ty-nl { padding: 5px 8px; font-size: 12.5px; }
  .ty-flags { display: flex; flex-wrap: wrap; gap: 6px 16px; }
  .ty-flags label { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--fg); text-transform: none; letter-spacing: normal; cursor: pointer; }
  /* Fixed-height layout while the types TABLE shows (class set by editor.js on #editorPage):
     the top bars + the XML preview stay put and the LIST is the ONLY thing that scrolls. The
     overrides editor never gets this class, so its workspace-scroll is untouched. */
  #editorPage.types-mode { height: 100%; min-height: 0; }
  .types-mode .ovr-body { display: flex; flex-direction: column; min-height: 0; }
  .types-mode .ty-bar, .types-mode .ty-addbar, .types-mode .ty-note { flex: none; }
  .types-mode .ty-split { flex: 1 1 auto; min-height: 0; align-items: stretch; }
  .types-mode .ty-preview { position: static; top: auto; max-height: none; align-self: stretch; }
  .types-mode .ty-main { min-height: 0; overflow-y: auto; }   /* the sole scroll region; .ty-head sticks to its top */
  /* Narrow: stack the preview above the table (no room to sit left). */
  @media (max-width: 1100px) {
    .ty-split { flex-direction: column; }
    .ty-preview { position: static; flex-basis: auto; width: 100%; max-height: 320px; }
    .types-mode .ty-split { flex-direction: column; align-items: stretch; }
    .types-mode .ty-preview { flex: 0 0 auto; width: auto; max-height: 240px; }
    .types-mode .ty-main { flex: 1 1 auto; }
  }
  @media (max-width: 760px) { .ty-head, .ty-row { grid-template-columns: minmax(120px, 1fr) 66px 66px 88px minmax(104px, auto); } .ty-head div:nth-child(4), .ty-row > div:nth-child(4), .ty-head div:nth-child(5), .ty-row > div:nth-child(5) { display: none; } }

  /* Map calibrate mode (per-layer alignment) */
  #mapCalBtn.active { background: var(--accent); color: var(--accent-fg); border-color: transparent; }
  .cal-head { font-weight: 600; font-size: 12.5px; padding: 8px 10px 4px; }
  .cal-hint { font-size: 11.5px; color: var(--muted); padding: 0 10px 8px; line-height: 1.45; }
  .cal-row { display: grid; grid-template-columns: 18px auto 12px 1fr 1fr auto 20px; align-items: center; gap: 5px; padding: 3px 8px; font-size: 11.5px; }
  .cal-row .cal-n { color: var(--faint); }
  .cal-row .cal-as { color: var(--muted); font-size: 11px; }
  .cal-row .cal-arrow { color: var(--faint); }
  .cal-row .cal-w { width: 100%; min-width: 44px; padding: 3px 5px; font-size: 11.5px; border-radius: 5px; background: var(--pre-bg); color: var(--pre-fg); border: 1px solid var(--border); }
  .cal-row .cal-res.ok { color: var(--ok); } .cal-row .cal-res.bad { color: var(--danger); font-weight: 600; }
  .cal-row .cal-x { opacity: .55; background: transparent; border: 0; color: var(--faint); cursor: pointer; padding: 0; }
  .cal-row .cal-x:hover { opacity: 1; color: var(--danger); }
  .cal-btns { display: flex; flex-wrap: wrap; gap: 6px; padding: 10px; border-top: 1px solid var(--border-soft); margin-top: 6px; }
  .cal-btns .ghost.active { background: var(--accent); color: var(--accent-fg); border-color: transparent; }

  /* Per-patrol field editor (map left nav): patrol / object / global editor, rendered IN
     .map-detail, in place. */
  .map-detail.editing { gap: 8px; }
  /* opt-in structured (json-editor) mode for a patrol: scroll within the narrow detail panel */
  .map-detail .pe-jsonhost { max-height: 62vh; overflow: auto; margin-top: 6px; }
  /* listed waypoints (reuses .me-wps / .me-wp / .me-wp-del / .me-wp-hint), with editable X / Z */
  /* LoadBalancingCategories: a collapsible tier table per category (global editor) */
  .map-detail .lbc-wrap { margin-top: 8px; border-top: 1px solid var(--border); padding-top: 10px; display: flex; flex-direction: column; }
  .map-detail .lbc-list { display: flex; flex-direction: column; gap: 5px; }
  .map-detail .lbc-cat { border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: var(--panel2); }
  .map-detail .lbc-cat > summary { list-style: none; cursor: pointer; display: flex; align-items: center; gap: 8px; padding: 6px 9px; font-size: 12px; }
  .map-detail .lbc-cat > summary::-webkit-details-marker { display: none; }
  .map-detail .lbc-cat > summary::before { content: "▸"; color: var(--faint); font-size: 10px; }
  .map-detail .lbc-cat[open] > summary::before { content: "▾"; }
  .map-detail .lbc-cn { font-weight: 600; }
  .map-detail .lbc-used { color: var(--faint); font-size: 9.5px; border: 1px solid var(--border); border-radius: 999px; padding: 0 6px; }
  .map-detail .lbc-cs { margin-left: auto; color: var(--muted); font-size: 11px; }
  .map-detail .lbc-body { padding: 8px 9px 9px; border-top: 1px solid var(--border); }
  .map-detail .lbc-crow { display: flex; gap: 6px; align-items: center; margin-bottom: 7px; }
  .map-detail .lbc-name { flex: 1; min-width: 0; box-sizing: border-box; background: var(--card); border: 1px solid var(--border); border-radius: 5px; color: var(--fg); font-size: 12px; padding: 3px 7px; }
  .map-detail .lbc-cdel { flex: none; background: none; border: 1px solid color-mix(in srgb, var(--danger) 45%, var(--border)); color: var(--danger); border-radius: 6px; font-size: 11px; font-weight: 600; padding: 3px 8px; cursor: pointer; }
  .map-detail .lbc-th, .map-detail .lbc-tr { display: grid; grid-template-columns: 20px 1fr 1fr 1fr 20px; gap: 5px; align-items: center; }
  .map-detail .lbc-th { font-size: 9px; text-transform: uppercase; letter-spacing: .3px; color: var(--faint); padding: 2px 0 4px; }
  .map-detail .lbc-th > span:first-child, .map-detail .lbc-ix { text-align: center; }
  .map-detail .lbc-tr { padding: 2px 0; }
  .map-detail .lbc-ix { color: var(--faint); font-size: 11px; }
  .map-detail .lbc-in { width: 100%; box-sizing: border-box; background: var(--card); border: 1px solid var(--border); border-radius: 5px; color: var(--fg); font-size: 12px; padding: 3px 5px; text-align: right; font-variant-numeric: tabular-nums; }
  .map-detail .lbc-in:focus, .map-detail .lbc-name:focus, .map-detail .lbc-newname:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
  .map-detail .lbc-tdel { background: none; border: none; color: var(--danger); cursor: pointer; font-size: 12px; padding: 0; }
  .map-detail .lbc-tadd { margin-top: 6px; background: var(--panel2); border: 1px solid var(--border); border-radius: 6px; color: var(--muted); font-size: 11px; font-weight: 600; padding: 3px 9px; cursor: pointer; }
  .map-detail .lbc-add { display: flex; gap: 6px; margin-top: 8px; }
  .map-detail .lbc-newname { flex: 1; min-width: 0; box-sizing: border-box; background: var(--panel2); border: 1px solid var(--border); border-radius: 6px; color: var(--fg); font-size: 12px; padding: 4px 8px; }
  .map-detail .lbc-newadd { flex: none; background: var(--accent); color: var(--accent-fg); border: 0; border-radius: 6px; font-size: 12px; font-weight: 600; padding: 4px 11px; cursor: pointer; }
  /* list row kind glyph (matches the map: location ring / patrol hexagon / object diamond) */
  .mp-item .mf-ico { flex: none; }

  /* Owned-file whole editor (own-editor.js — the two-copy model: frozen default + live).
     CM6 ships a LIGHT default theme; every rule below re-homes it onto the app's always-dark
     code surface (--pre-bg/--pre-fg, same in both themes - matches the File view and log
     panes), with token colors inherited from the app's own t-* palette via class-mapped
     highlighting in own-editor.js. style.css stays the single owner of all colors. */
  .own-bar { display: flex; align-items: center; gap: 10px; padding: 10px 22px 6px; flex-wrap: wrap; }
  .own-bar .spacer { flex: 1; }
  /* Edit surfaces carry a single left "thread" rule, never a full box - a boxed editor reads as
     a widget on the page instead of the page's content, and the four borders fight the gutter.
     Same treatment on both edit paths so they look identical. */
  .own-cm { margin: 8px 22px 16px; border: none; border-left: 2px solid var(--border); border-radius: 0; overflow: hidden; background: var(--pre-bg); }
  .own-cm:focus-within { border-left-color: var(--accent); }
  .own-cm .cm-editor { height: min(68vh, 860px); font-size: 12.5px; background: var(--pre-bg); color: var(--pre-fg); }
  .own-cm .cm-editor .cm-scroller { overflow: auto; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
  .own-cm .cm-gutters { background: var(--pre-bg); color: var(--faint); border-right: 1px solid rgba(255,255,255,0.08); }
  .own-cm .cm-activeLine { background: rgba(255,255,255,0.045); }
  .own-cm .cm-activeLineGutter { background: rgba(255,255,255,0.06); color: var(--pre-fg); }
  .own-cm .cm-cursor, .own-cm .cm-dropCursor { border-left-color: var(--pre-fg); }
  .own-cm .cm-selectionBackground, .own-cm .cm-content ::selection { background: rgba(121,192,255,0.22) !important; }
  .own-cm .cm-selectionMatch { background: rgba(121,192,255,0.14); }
  .own-cm .cm-matchingBracket { background: rgba(126,231,135,0.18); outline: none; }
  .own-cm .cm-tooltip, .own-cm .cm-panels { background: var(--card); color: var(--fg); border: 1px solid var(--border); }
  .own-cm .cm-foldPlaceholder { background: rgba(255,255,255,0.08); color: var(--faint); border: none; }
  /* unified merge view: live-vs-default chunks, colored from the app's ok/danger hues */
  .own-cm .cm-changedLine { background: rgba(70,194,102,0.10); }
  .own-cm .cm-changedText { background: rgba(70,194,102,0.22); }
  .own-cm .cm-deletedChunk { background: rgba(239,91,82,0.12); }
  .own-cm .cm-deletedChunk del, .own-cm .cm-deletedText { background: rgba(239,91,82,0.22); text-decoration: none; }
  .own-cm .cm-changeGutter { width: 4px; }

  /* ---------- two panes over ONE document (own-editor.js) ----------
     Structured on the left, raw text on the right, and the side that HOLDS the document wears the
     gold box - the app's own brass accent, so "this is the live thing" reads the same here as
     everywhere else. The other side is a projection: dimmed, inert, and a click on it is the
     request for the document. Two editors side by side need width, so they stack rather than
     squeeze into two unreadable columns. */
  .tp-split { display: flex; gap: 12px; align-items: stretch; margin: 8px 22px 16px; flex-wrap: wrap; }
  .tp-pane { flex: 1 1 460px; min-width: 0; display: flex; flex-direction: column; gap: 6px;
    border: 2px solid transparent; border-radius: 10px; padding: 6px 8px 8px; background: var(--card); }
  .tp-pane.tp-own { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-weak); }
  .tp-pane.tp-proj { cursor: pointer; opacity: .88; }
  .tp-pane.tp-proj:hover { opacity: 1; border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
  /* Belt to the `inert` property set in JS: a browser that ignores inert must still not let the
     projection be typed into. The click passes through to the pane, which is what asks for the
     document. CodeMirror keeps its pointer events so the projected text stays selectable. */
  .tp-proj .wf-json { pointer-events: none; }
  .tp-head { display: flex; align-items: center; gap: 8px; font-size: 11.5px; }
  .tp-head .tp-name { font-weight: 700; color: var(--fg); }
  .tp-head .tp-role { text-transform: uppercase; letter-spacing: .06em; font-size: 9.5px; font-weight: 700;
    border-radius: 999px; padding: 1px 7px; color: var(--muted); border: 1px solid var(--border); }
  .tp-own .tp-head .tp-role { color: var(--accent); border-color: var(--accent); background: var(--accent-weak); }
  .tp-head .tp-hint { color: var(--faint); font-size: 11px; }
  /* "out of date" is a normal state here, not an error - the projection is committed, not followed.
     It reads as a live warning colour only while it is behind, and the button next to it is the fix. */
  .tp-head .tp-role.tp-stale { color: var(--drift); border-color: var(--drift); background: transparent; }
  .tp-head .tp-commit { padding: 3px 9px; font-size: 11px; }
  .tp-head .tp-commit:disabled { opacity: .45; }
  /* both editors drop their page margins in here - the pane owns the spacing now */
  .tp-pane .own-cm { margin: 0; flex: 1; }
  .tp-pane .own-cm .cm-editor { height: min(62vh, 780px); }
  .tp-pane .wf-json { flex: 1; max-height: min(62vh, 780px); }
  .tp-pane .jn-wrap { --jn-pane-h: 44vh; }
  /* Parse failure: what broke, WHERE, and the promise that the text is untouched. Never a stale
     tree beside text that no longer produces it. */
  .tp-fail { padding: 12px 14px; }
  .tp-fail > b { color: var(--danger); font-size: 13px; }
  .tp-fail .tp-where { margin: 8px 0; font-size: 12.5px; color: var(--fg); display: flex; align-items: center; gap: 10px; }
  .tp-fail .tp-src { margin: 8px 0; padding: 8px 10px; background: var(--pre-bg); color: var(--pre-fg);
    border-radius: 8px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px; white-space: pre; overflow: auto; tab-size: 8; }
  .tp-fail .tp-msg { font-size: 11.5px; color: var(--muted);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; word-break: break-word; }
  .tp-note { padding: 14px; color: var(--muted); font-size: 12.5px; line-height: 1.6; }
  @media (max-width: 1100px) { .tp-split { flex-direction: column; } }

/* The Compare view: live file beside its frozen default, per file, reached from the segment
   switcher (own-editor.js renderOwnCompare). CodeMirror MergeView owns the panes and the
   alignment; this only frames it and gives it a height to scroll in. */
.cmp-head { display: flex; align-items: center; gap: 10px; padding: 10px 22px 6px; flex-wrap: wrap; }
.cmp-split { margin: 8px 22px 16px; border-left: 2px solid var(--border); background: var(--pre-bg); overflow: hidden; }
.cmp-split .cm-mergeView, .cmp-split .cm-mergeViewEditors { height: min(70vh, 900px); }
.cmp-split .cm-editor { height: 100%; font-size: 12.5px; background: var(--pre-bg); color: var(--pre-fg); }
.cmp-split .cm-scroller { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.cmp-split .cm-gutters { background: var(--pre-bg); color: var(--faint); border-right: 1px solid rgba(255,255,255,0.08); }
/* the two copies differ: green = only in the live file, red = only in the frozen default */
.cmp-split .cm-changedLine { background: rgba(70,194,102,0.10); }
.cmp-split .cm-changedText { background: rgba(70,194,102,0.24); }
.cmp-split .cm-deletedChunk { background: rgba(239,91,82,0.12); }
.cmp-split .cm-deletedChunk del, .cmp-split .cm-deletedText { background: rgba(239,91,82,0.24); text-decoration: none; }
/* collapsed identical stretches - the thing that makes a badly diverged file readable at all */
.cmp-split .cm-collapsedLines { background: var(--panel2); color: var(--muted); font-size: 11.5px; padding: 3px 10px; cursor: pointer; }
.cmp-split .cm-collapsedLines:hover { color: var(--fg); }


/* ===== Quests tab ===== */
/* Three stages in one pane: a table of quest types, one type's quests, then one file in the
   shared Server Files editor. No left-column navigator - the table IS the navigator. */
#queststab { display: flex; flex-direction: column; gap: 16px; padding: 18px 20px 24px; min-height: 0; overflow: auto; }
#queststab .page-head { margin: 0; }

/* --- the numbers that matter, before the detail --- */
/* The server not running what you are looking at is the most important thing on the page. */
.qrestart { border: 1px solid var(--drift); border-left: 4px solid var(--drift); border-radius: 9px;
  background: var(--drift-weak, rgba(194,87,11,.10)); color: var(--fg);
  padding: 11px 15px; font-size: 13.5px; }
.qrestart b { color: var(--drift); }
.qrestart.unknown { border-color: var(--border); border-left-color: var(--faint); background: var(--panel2); color: var(--muted); }
.qstrip { display: flex; gap: 10px; flex-wrap: wrap; }
.qstat {
  background: var(--card); border: 1px solid var(--border); border-radius: 10px;
  padding: 9px 15px; min-width: 96px; display: flex; flex-direction: column; gap: 2px;
}
.qstat .k { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); font-weight: 700; }
.qstat .v { font-size: 19px; font-weight: 650; line-height: 1.1;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-variant-numeric: tabular-nums; }
.qstat.good .v { color: #3fb950; }
.qstat.warn .v { color: #d29922; }
.qstat.bad .v { color: #f85149; }

/* --- map picker + filter --- */
.qcontrols { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.qctl { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; color: var(--muted); }
.qsel { width: auto; padding: 7px 10px; font-size: 12.5px; border: 1px solid var(--border);
  border-radius: 8px; background: var(--card); color: var(--fg); }
.qsearch { width: 300px; max-width: 100%; padding: 7px 12px; font-size: 12.5px;
  border: 1px solid var(--border); border-radius: 8px; background: var(--card); color: var(--fg); }
.qsearch::placeholder { color: var(--faint); }
.qnote { font-size: 12.5px; color: var(--muted); }
.qcontrols .spacer { flex: 1; }
.qnew select { border-color: var(--accent); color: var(--accent); font-weight: 600; }
.qprogress { display: flex; flex-direction: column; gap: 10px; border: 1px solid var(--border);
  border-radius: 10px; padding: 14px; background: var(--card); }
.qprogress .qtable-wrap { box-shadow: none; }
.qlink { background: none; border: 0; padding: 0; font: inherit; font-weight: 600; color: var(--accent); cursor: pointer; }
.qlink:hover { text-decoration: underline; }

/* --- the table --- */
.qtable-wrap { position: relative; border: 1px solid var(--border); border-radius: 10px;
  background: var(--card); overflow: auto; max-height: calc(100vh - 330px); box-shadow: var(--shadow); }
.qtable-empty { min-height: 220px; overflow: hidden; }
.qtable { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13.5px; }
.qtable thead th {
  position: sticky; top: 0; z-index: 2; background: var(--panel2); text-align: left;
  padding: 10px 14px; font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--faint); font-weight: 700; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.qtable thead th.n, .qtable td.n { text-align: right; }
.qtable td { padding: 10px 14px; border-bottom: 1px solid var(--border-soft); vertical-align: middle; }
.qtable tbody tr:last-child td { border-bottom: 0; }
.qtable td.n { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.qtable td.n.ok { color: #3fb950; }
.qtable td.n.warnnum { color: #d29922; }
.qtable td.n.meta { color: var(--faint); }
.qtable .qt-name { font-weight: 600; }
.qtable .qt-id { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: var(--faint); font-size: 12px; text-align: right; }
.qtable .qt-chev { color: var(--faint); text-align: right; width: 26px; font-size: 15px; }
.qtable .qt-sw { width: 1%; white-space: nowrap; padding-right: 4px; }
.qtable .qt-steps { color: var(--muted); font-size: 12.5px; max-width: 240px; }
.qtable .qt-chain { white-space: nowrap; }
.qtr { cursor: pointer; }
.qtr:hover { background: var(--bg); }
.qtr:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
/* A chain's second and later quests are the SAME toggle unit: no switch of their own, indented
   under the row that has one. */
.qtr-cont .qt-name { padding-left: 22px; font-weight: 500; }
.qtr-cont td { border-bottom-color: var(--border-soft); }
.qsw-sp { display: inline-block; width: 38px; }

/* --- crumbs + heading --- */
.qcrumbs { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--faint); flex-wrap: wrap; }
.qcrumbs button { background: none; border: 0; color: var(--accent); font: inherit; font-weight: 600; padding: 0; cursor: pointer; }
.qcrumbs button:hover { text-decoration: underline; }
.qcrumbs .now { color: var(--fg); font-weight: 600; }
.qhead { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.qhead h2 { margin: 0; font-size: 19px; letter-spacing: -0.01em; }

/* --- a state you SET, so a slider, not a word you click --- */
.qsw { position: relative; width: 38px; height: 21px; border-radius: 999px; background: var(--border);
  border: 0; padding: 0; cursor: pointer; transition: background .13s; flex: none; display: block; }
.qsw .qsw-knob { position: absolute; top: 2px; left: 2px; width: 17px; height: 17px; border-radius: 50%;
  background: var(--card); transition: transform .13s; box-shadow: 0 1px 2px rgba(0,0,0,.3); }
.qsw.on { background: #3fb950; }
.qsw.on .qsw-knob { transform: translateX(17px); }
.qsw:disabled { opacity: .5; cursor: default; }
.qsw:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* --- pills: state, and the chain edges that make a quest un-switchable alone --- */
.qpill { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; font-weight: 650;
  padding: 3px 9px; border-radius: 999px; border: 1px solid var(--border); color: var(--faint);
  background: var(--card); white-space: nowrap; }
.qpill.ok { color: #3fb950; border-color: #3fb950; }
.qpill.warn { color: #d29922; border-color: #d29922; }
.qpill.bad { color: #f85149; border-color: #f85149; }
.qpill.link { color: var(--info); border-color: var(--info); background: var(--info-weak); }
.qpill.link b { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-weight: 700; }
.qpill.soft { color: var(--muted); }

/* --- the state dot: a chain can be half-on, which must never read as on or off --- */
.qdot { font-size: 11px; margin-right: 2px; }
.qdot-on { color: #3fb950; }
.qdot-off { color: var(--faint); }
.qdot-partial { color: #d29922; }
.qdot-unknown { color: var(--faint); }

/* --- findings, printed in the row: a count behind a tooltip tells the reader nothing --- */
.qtable .qprob { margin: 0; padding: 0; list-style: none; max-width: 380px; }
.qtable .qprob li { font-size: 12px; line-height: 1.4; margin: 1px 0; }
.qtable .qprob li.error { color: #f85149; }
.qtable .qprob li.warn { color: #d29922; }

/* --- only the units that reach outside the type being listed --- */
.qimpacts { display: flex; flex-direction: column; gap: 8px; }
.qimpacts-h { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); font-weight: 700; }
.qimpact { border: 1px solid var(--border); border-left: 3px solid #d29922; border-radius: 8px;
  padding: 11px 15px; background: var(--card); }
.qimpact .k { color: var(--fg); font-size: 12.5px; font-weight: 650; }
.qimpact ul { margin: 6px 0 0; padding-left: 18px; }
.qimpact li { margin: 3px 0; font-size: 12.5px; color: var(--muted); }

.qfind { margin: 0; padding-left: 18px; }
.qfind li { margin: 3px 0; font-size: 13px; }
.qfind li.error { color: #f85149; }
.qfind li.warn { color: #d29922; }

/* --- a quest is not one file: its objectives and NPCs open from here --- */
.qrelated { border: 1px solid var(--border); border-radius: 10px; background: var(--card); padding: 12px 16px; }
.qrelated-h { font-size: 10.5px; text-transform: uppercase; letter-spacing: .06em; color: var(--faint); font-weight: 700; margin-bottom: 8px; }
.qrelated ul { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 5px; }
.qrelated li { font-size: 13px; display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.qrelated li.bad { color: #f85149; }
.qtable .qt-npc { font-size: 12.5px; max-width: 170px; }
.qtable .qt-npc .qlink { font-size: 12.5px; }

/* Stage 3 is the SAME editor the Server Files tab mounts; it brings its own chrome. */
.own-host { min-height: 340px; }
/* Removing a file is offered plainly, not hidden - but it sits below the editor, apart from the
   controls that only change what is in the document. */
.qdanger { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; padding-top: 4px; }
.qdel { border: 1px solid var(--danger); color: var(--danger); background: transparent;
  border-radius: 7px; padding: 6px 14px; font-size: 12.5px; font-weight: 650; cursor: pointer; }
.qdel:hover:not(:disabled) { background: var(--danger); color: #fff; }
.qdel:disabled { opacity: .5; cursor: default; }

.econ-card { display: flex; flex-direction: column; gap: 10px; border: 1px solid var(--border);
  border-radius: 10px; padding: 14px; background: var(--card); margin-bottom: 14px; }
.econ-card .qtable-wrap { box-shadow: none; }
.econ-card input[type="file"] { font: inherit; color: var(--muted); }

/* A questline someone is part-way through. The tint is the only thing separating "they are stuck
   here" from rows that are merely history, and it must survive both themes. */
.qtable tr.qrow-live > td { background: color-mix(in srgb, var(--accent) 9%, transparent); }
.qtable tr.qrow-live > td:first-child { box-shadow: inset 3px 0 0 var(--accent); }
