/* ============================================================================
   CLOUD RADAR - the overlay menu's look, in CSS
   ============================================================================
   Every size and grey below is copied from the overlay (theme.h, widgets.h,
   menulayout.h) at 100 % display scaling: flat, square, no shadows, no
   gradients, a 14 px padding grid with 8 px between rows. Dark is the
   default theme (like CS2 and the reference web radar); Light is every grey
   turned around (g -> 255 - g), exactly like the overlay's.
   The map (canvas) is NOT styled here: view.js / cs2view.js draw it, dark
   like the game's radar in both themes.
   ============================================================================ */

/* ascent/descent-override: where the letters sit in their 14 px line.
   Chrome on Windows takes Roboto's "win" metrics (1946 / 512 units), which
   round to a baseline 11 px under the top of the line; ImGui puts it at
   12 px. Measured against the menu renders, every web letter sat 1 px too
   high. 12 px + 2 px (of an 11.95 px em) puts the baseline at 12 in every
   browser, and the line stays 14 px. */
@font-face {
  font-family: "Roboto";
  src: url("/_/fonts/Roboto-Regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: block;
  ascent-override: 100.4464%;
  descent-override: 16.7411%;
  line-gap-override: 0%;
}

:root {
  /* FONT: Roboto Regular "14" like the overlay. ImGui sizes a font by its
     full height (ascender to descender = 2400 units of Roboto's 2048 em),
     CSS by its em: 14 x 2048 / 2400 = 11.95 px gives the same letters
     (capitals 8.5 px tall) on the same 14 px line. */
  --font-size: 11.9467px;
  --lh: 14px;           /* a text line = a row */
  --pad: 14px;          /* WindowPadding: around panels and dividers */
  --gap: 8px;           /* ItemSpacing: between rows */
  --inner: 6px;         /* ItemInnerSpacing: box -> label, square -> square */
  --fpx: 6px;           /* FramePadding */
  --fpy: 4px;
  --frame: 22px;        /* buttons, number boxes: a line + 2 x FramePadding.y */
  --box: 12px;          /* checkbox and color squares: a line - 2 px */
  --col: 276px;         /* the menu's left column: 2 color editors + 28 px */
  --gutter-t: max(16px, env(safe-area-inset-top));
  --gutter-r: max(16px, env(safe-area-inset-right));
  --gutter-b: max(16px, env(safe-area-inset-bottom));
  --gutter-l: max(16px, env(safe-area-inset-left));

  /* LIGHT (widgets.h SetPalette, light = 255 - dark) */
  --bg: rgb(255, 255, 255);
  --text: rgb(0, 0, 0);
  --dim: rgb(128, 128, 128);        /* TextDisabled: unselected tabs, units, secondary text */
  --line: rgb(204, 204, 204);       /* Border: dividers, outlines */
  --box-off: rgb(217, 217, 217);
  --box-off-h: rgb(197, 197, 197);
  --box-on: rgb(0, 0, 0);
  --box-on-h: rgb(40, 40, 40);
  --box-on-dim: rgb(127, 127, 127);
  --btn: rgb(235, 235, 235);        /* kButtonIdle 0.92 */
  --btn-h: rgb(232, 232, 232);      /* kButtonHovered 0.91 */
  --btn-armed-h: rgb(227, 227, 227);/* kButtonArmedHovered 0.89: list rows under the mouse */
  --btn-p: rgb(241, 241, 241);      /* kButtonPressed 0.945: lighter = "pushed in" */
  --sel: rgba(0, 0, 0, 0.25);       /* selected text */
  color-scheme: light;
}

:root[data-theme="dark"] {
  --bg: rgb(0, 0, 0);
  --text: rgb(255, 255, 255);
  --dim: rgb(128, 128, 128);
  --line: rgb(51, 51, 51);
  --box-off: rgb(38, 38, 38);
  --box-off-h: rgb(58, 58, 58);
  --box-on: rgb(255, 255, 255);
  --box-on-h: rgb(215, 215, 215);
  --box-on-dim: rgb(128, 128, 128);
  --btn: rgb(20, 20, 20);
  --btn-h: rgb(23, 23, 23);
  --btn-armed-h: rgb(28, 28, 28);
  --btn-p: rgb(14, 14, 14);
  --sel: rgba(255, 255, 255, 0.25);
  color-scheme: dark;
}

/* ---- Base ------------------------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; height: 100%; }
body {
  margin: 0;
  height: 100%;
  font: var(--font-size) / var(--lh) "Roboto", sans-serif;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;   /* grey smoothing like ImGui's, not colored */
  -moz-osx-font-smoothing: grayscale;
}
button, input { font: inherit; color: inherit; letter-spacing: inherit; }
button {
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  text-align: inherit;
  cursor: default;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
}
h1, p { margin: 0; font: inherit; }
[hidden] { display: none !important; }
::selection { background: var(--sel); }
:focus { outline: none; }
/* Keyboard focus: a 1 px line in the text color (the overlay has none, the
   web needs one). */
:focus-visible { outline: 1px solid var(--text); outline-offset: 1px; }

.pdim { color: var(--dim); }
/* Text boxes cut long text with "..." but only SIDEWAYS: a "g" or "y"
   hangs 1 px below its 14 px line (ImGui draws that pixel row too, nothing
   clips it there). "clip visible" = cut left/right, not below; browsers
   that don't know it keep the plain "hidden" before it. */
.line { display: block; height: var(--lh); white-space: nowrap; overflow: hidden; overflow: clip visible; text-overflow: ellipsis; }

/* ---- Panels ---------------------------------------------------------------------- */
/* A floating panel: the window's color, 14 px padding, and the popups' 1 px
   outline (widgets.h OutlineCurrentWindow), drawn INSIDE its edge. (An
   outline, not a border: it doesn't move the content and stays put when
   the panel scrolls.) */
.panel {
  position: relative;
  background: var(--bg);
  color: var(--text);
  padding: var(--pad);
  outline: 1px solid var(--line);
  outline-offset: -1px;
  scrollbar-width: thin;
  scrollbar-color: var(--dim) transparent;
  /* Grey-smoothed letters like ImGui's. Chrome on Windows draws text in
     an opaque layer with ClearType (colored fringes, heavier letters): the
     docks came out that way while the settings panel didn't. A filter
     gives the panel its own see-through layer, where Chrome always uses
     grey smoothing. opacity(1) changes nothing else. */
  filter: opacity(1);
}

/* ---- Rows (menulayout.h) ---------------------------------------------------------- */
.rows > * + * { margin-top: var(--gap); }
.divider { height: 1px; background: var(--line); margin: var(--pad) 0; }
.rows > .divider { margin: var(--pad) 0; }
.rows > .divider + * { margin-top: 0; }

.row { display: flex; align-items: flex-start; min-height: var(--lh); }
.row > .label { flex: 1 1 auto; min-width: 0; height: var(--lh); white-space: nowrap; overflow: hidden; overflow: clip visible; text-overflow: ellipsis; }
.row > .cb { flex: 0 1 auto; min-width: 0; }
.row > .ctl { flex: none; margin-left: auto; padding-left: var(--gap); display: flex; align-items: flex-start; gap: var(--inner); }
/* A number box row is as tall as the box; its label moves down to the
   number's line (menulayout.h NumberRow). */
.row.tall { min-height: var(--frame); }
.row.tall > .label { height: var(--frame); padding-top: var(--fpy); }

/* ---- Checkbox (widgets.h Checkbox) --------------------------------------------------- */
.cb { display: inline-flex; align-items: flex-start; height: var(--lh); max-width: 100%; white-space: nowrap; }
.cb > .sq { flex: none; width: var(--box); height: var(--box); margin-top: 1px; background: var(--box-off); }
.cb > .lbl { margin-left: var(--inner); overflow: hidden; overflow: clip visible; text-overflow: ellipsis; }
.cb[aria-checked="true"] > .sq { background: var(--box-on); }

/* ---- Color square (widgets.h ColorSwatch) ------------------------------------------- */
.swatch { flex: none; display: block; width: var(--box); height: var(--box); margin-top: 1px; }
.swatch.near-bg { box-shadow: inset 0 0 0 1px var(--box-off); }

/* ---- Buttons and dropdowns (widgets.h Button / Combo) ----------------------------------- */
/* Flat grey, 1 px outline; a touch darker on hover, LIGHTER while pressed
   (light theme). Pressing is instant, the rest eases over 0.1 s. */
.btn, .combo {
  display: block;
  border: 1px solid var(--line);
  background: var(--btn);
  color: var(--text);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background-color 100ms linear;
}
.btn { width: 100%; height: var(--frame); padding: 0 var(--fpx); line-height: calc(var(--frame) - 2px); }
/* The dropdown sits on a text line like a checkbox, its frame reaching 2 px
   above and 3 px below the line (widgets.h: the "y" in "Dynamic" must fit). */
.combo { flex: none; height: 19px; margin: -2px 0 -3px; padding: 1px var(--fpx) 2px; line-height: var(--lh); }
.btn:active, .combo:active { background: var(--btn-p); transition: none; }

/* The dropdown's list: rows in the button's grey, the chosen one in the
   text color, the others grey. */
.list {
  position: fixed;
  z-index: 45;
  background: var(--btn);
  outline: 1px solid var(--line);
  outline-offset: -1px;
  filter: opacity(1);   /* grey-smoothed text, see .panel */
}
.opt {
  display: block;
  width: 100%;
  height: var(--frame);
  padding: var(--fpy) var(--fpx);
  line-height: var(--lh);
  color: var(--dim);
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.opt[aria-selected="true"] { color: var(--text); }
.opt:focus-visible { outline-offset: -2px; }

/* ---- Number box / text field (widgets.h NumberBox, TextField) -------------------------- */
.numbox {
  position: relative;
  display: block;
  flex: none;
  height: var(--frame);
  background: var(--btn);
  outline: 1px solid var(--line);
  outline-offset: -1px;
}
.numbox > input {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  border: 0;
  border-radius: 0;
  /* A field shows its text in ONE line box and cuts everything outside
     it, so "g j p q y" (1-2 px under the 14 px line) would lose their
     tails. A 16 px line starting 1 px higher keeps the letters exactly
     where FramePadding puts them (baseline 4 + 12 px from the top, like
     ImGui's field) with room underneath. */
  padding: calc(var(--fpy) - 1px) var(--fpx);
  line-height: calc(var(--lh) + 2px);
  background: transparent;
  color: var(--text);
  caret-color: var(--text);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
  /* A field's text gets its own layer in Chrome, an opaque one (ClearType)
     even inside a filtered panel; this one is see-through: grey smoothing
     like the labels around it. */
  will-change: transform;
}
.numbox > input::placeholder { color: var(--dim); opacity: 1; }
.numbox > input::selection { background: var(--sel); color: var(--text); }
.numbox > .unit { position: absolute; top: var(--fpy); right: var(--fpx); line-height: var(--lh); color: var(--dim); pointer-events: none; }
.numbox:focus-within { background: var(--btn-h); }
.textbox { width: 160px; }
/* The room code box fills its row: the label keeps its width, one row gap, then the box takes the
   rest (a code is 56 characters; the 160 px box left most of the row empty). */
.roomform .row > .label { flex: none; }
.roomform .row > .ctl { flex: 1 1 auto; min-width: 0; margin-left: 0; }
.roomform .textbox { flex: 1 1 auto; width: auto; min-width: 0; }
/* The room code box's error line keeps its place when empty (no jump when
   it appears): two lines, as long as the longest message. */
/* No room reserved: the box ends right under Open; an error adds its one line when it shows. */
.form-error { height: 0; margin-top: 0; overflow: hidden; visibility: hidden; } /* (no row gap either: the box ends 14 px under Open, as it starts 14 px above the title) */
.form-error.shown { height: var(--lh); margin-top: var(--gap); visibility: visible; }
/* A message that may need two lines (no cut). */
.wrap { white-space: normal; overflow-wrap: anywhere; }

/* ---- Tabs (widgets.h Tabs) ------------------------------------------------------------ */
.tabs { display: flex; height: var(--lh); margin-bottom: var(--pad); }
.tab { flex: 1 1 0; min-width: 0; height: var(--lh); color: var(--dim); text-align: center; white-space: nowrap; overflow: hidden; overflow: clip visible; }
.tab[aria-selected="true"] { color: var(--text); }

/* ---- Tooltip (widgets.h SmallTooltip) --------------------------------------------------- */
.tip {
  position: fixed;
  z-index: 60;
  padding: 3px 6px;
  background: var(--bg);
  outline: 1px solid var(--line);
  outline-offset: -1px;
  white-space: nowrap;
  pointer-events: none;
  filter: opacity(1);   /* grey-smoothed text, see .panel */
}

/* Hover looks only where there IS hover (a mouse): on a phone a tapped
   button would otherwise stay "hovered". */
@media (hover: hover) {
  .cb:hover > .sq { background: var(--box-off-h); }
  .cb[aria-checked="true"]:hover > .sq { background: var(--box-on-h); }
  .swatch:hover { outline: 1px solid var(--dim); outline-offset: 0; }
  .btn:hover, .combo:hover { background: var(--btn-h); }
  .btn:active, .combo:active { background: var(--btn-p); }
  .opt:hover { color: var(--text); background: var(--btn-armed-h); }
  .numbox:hover { background: var(--btn-h); }
  .tab:hover { color: var(--text); }
  .prow:hover { background: var(--btn-h); }
  .dock-arrow:hover > .tri { opacity: 1; }
  .copybtn:hover > span { border-color: var(--text); }
}

/* ---- A row's gear and its popup (ui.js gear: widgets.h GearButton / BeginSettingsPopup) -- */
/* The gear: 14 px (2 px more than the box under it, which pokes out 1 px
   all round), at the right end of its row like a color square. */
.rowgear { flex: none; display: block; width: 14px; height: var(--lh); }
.rowgear > canvas { display: block; width: 14px; height: 14px; }
/* Its popup: 280 px wide, padding 10 px at the sides and 9 px top and
   bottom, the rows spaced like the panel's, the Close button (80 x 20)
   12 px under the last row. Scrolls when the window is too short. */
.gearpop { width: 280px; padding: 9px 10px; overflow-y: auto; overscroll-behavior: contain; }
.gearpop > .closebtn { width: 80px; height: 20px; margin-top: 12px; line-height: 18px; }

/* ---- Color editor (widgets.h ColorEditor): label, wheel + opacity bar, hex + copy ----- */
.popup { position: fixed; z-index: 40; }
.coloredit { width: calc(124px + 2 * var(--pad)); }
.ce-title { height: var(--lh); white-space: nowrap; overflow: hidden; overflow: clip visible; text-overflow: ellipsis; }
.ce-pick { display: flex; align-items: flex-start; height: 108px; margin-top: var(--gap); }
.ce-wheel { display: block; flex: none; width: 108px; height: 108px; touch-action: none; }
/* The bar's canvas is 2 px wider on each side and 1 px taller at each end
   than the bar (room for its marker): the bar itself starts 6 px right of
   the wheel. */
.ce-alpha { display: block; flex: none; width: 14px; height: 110px; margin: -1px 0 0 4px; touch-action: none; }
.ce-hexrow { display: flex; gap: var(--inner); margin-top: var(--gap); }
.ce-field { width: 96px; }
.ce-field > input { text-transform: uppercase; }
/* The copy button's icon: two overlapping squares, the front one filled
   with the button's own grey (widgets.h CopyButton). */
.copybtn { position: relative; flex: none; width: var(--frame); padding: 0; }
.copybtn > span { position: absolute; display: block; width: 7px; height: 7px; border: 1px solid var(--dim); }
.copybtn > .cp-back { left: 5px; top: 5px; }
.copybtn > .cp-front { left: 8px; top: 8px; background: inherit; }

/* ============================================================================
   THE RADAR PAGE
   ============================================================================
   Like the reference web radar: the T dock on the left, the CT dock on the
   right, the map centered between them; the gear, the status line, the
   bomb panel and the "Loading map..." note inside the map's area. In a
   narrow upright window (not turned) the docks sit side by side on top and
   the map's area is under them. app.js keeps these up to date (docks.js
   mapArea):
     --area-l / --area-r  where the map's area starts from the left / right
                          edge (past an open dock, plus the gap);
     --area-t / --area-b  its top (under the docks when stacked) and bottom;
     --map-t / --map-b    the map's own top and bottom (0 = the whole height);
     --edge-l/-r/-t/-b    the room kept at the window's edges: 16 px, more
                          where a phone's notch or round corners are.
   ============================================================================ */
:root {
  --area-l: 16px;
  --area-r: 16px;
  --area-t: 16px;
  --area-b: 16px;
  --map-t: 0px;
  --map-b: 0px;
  --edge-l: 16px;
  --edge-r: 16px;
  --edge-t: 16px;
  --edge-b: 16px;
  --tile: calc(var(--lh) + 2 * var(--pad));   /* a 42 px square panel: the gear */
  /* The names in the docks, in the team's color: CS2's t-color #eabe54 and
     ct-color rgb(150, 200, 250); darker on the light theme to stay readable. */
  --t-name: rgb(234, 190, 84);
  --ct-name: rgb(150, 200, 250);
}
:root[data-theme="light"] {
  --t-name: rgb(170, 120, 10);
  --ct-name: rgb(30, 110, 190);
}

.radar-page { overflow: hidden; overscroll-behavior: none; }
/* A phone held upright: the whole page turned sideways (frame.js sets the
   size and the turn). The body becomes the landscape box every fixed panel
   is placed in. */
html.turned { overflow: hidden; }
html.turned body { position: fixed; top: 0; left: 0; transform-origin: 0 0; overflow: hidden; }
.map { position: fixed; inset: 0; display: block; width: 100%; height: 100%; touch-action: none; }
/* Reads the screen's safe area (a notch, round corners) for frame.js. */
.safe-probe {
  position: fixed;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  visibility: hidden;
  pointer-events: none;
  padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px) env(safe-area-inset-left, 0px);
}

/* The settings gear: the menu's gear on its square, in a 42 px panel, at the
   top-left of the map (the reference's place). */
.gearbtn {
  position: fixed;
  z-index: 31;
  top: var(--area-t);
  left: var(--area-l);
  width: var(--tile);
  height: var(--tile);
  padding: var(--pad);
}
.gear-canvas { display: block; width: 14px; height: 14px; }
.gearbtn:focus-visible { outline: 1px solid var(--text); outline-offset: 1px; }
/* (before the page's scripts have filled them, e.g. on a slow phone: no empty boxes) */
.gearbtn:empty, .status:empty { visibility: hidden; }

/* Touch screens: fullscreen, at the top-right of the map. Its icon: four
   corners (CSS gradients, no picture). */
.fsbtn {
  position: fixed;
  z-index: 31;
  top: var(--area-t);
  right: var(--area-r);
  width: var(--tile);
  height: var(--tile);
  padding: var(--pad);
}
.fs-icon {
  display: block;
  width: 14px;
  height: 14px;
  background:
    linear-gradient(var(--text), var(--text)) left top / 5px 2px no-repeat,
    linear-gradient(var(--text), var(--text)) left top / 2px 5px no-repeat,
    linear-gradient(var(--text), var(--text)) right top / 5px 2px no-repeat,
    linear-gradient(var(--text), var(--text)) right top / 2px 5px no-repeat,
    linear-gradient(var(--text), var(--text)) left bottom / 5px 2px no-repeat,
    linear-gradient(var(--text), var(--text)) left bottom / 2px 5px no-repeat,
    linear-gradient(var(--text), var(--text)) right bottom / 5px 2px no-repeat,
    linear-gradient(var(--text), var(--text)) right bottom / 2px 5px no-repeat;
}

/* Status line + floors: right of the gear, wrapping when the map's area is
   narrow. */
.hud {
  position: fixed;
  z-index: 20;
  top: var(--area-t);
  left: calc(var(--area-l) + var(--tile) + 8px);
  right: var(--area-r);
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px;
  pointer-events: none;
}
.hud > * { pointer-events: auto; max-width: 100%; }
.fs-shown .hud { right: calc(var(--area-r) + var(--tile) + 8px); }
.status { display: flex; gap: var(--pad); height: var(--tile); white-space: nowrap; overflow: hidden; }
.status > span { flex: none; }
.status > .st-map { flex: 0 1 auto; min-width: 0; overflow: hidden; overflow: clip visible; text-overflow: ellipsis; }
/* Who gives way when the line is too short (a small phone): the viewer count
   first, then the map name (then, see .warn, the warning); "Live" never. */
.status > .st-state { flex: none; }
.status > .st-viewers { flex: 0 1000000 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* While a warning shows ("No update for 6 s", "Radar delayed by 70 s",
   "Data 120 s old, or clocks differ"; hud.js sets .warn): "Live" stays
   whole, the map name gives way first, down to its first letters, and only
   then the warning (cut at its end). Without it the warning never shrank and
   pushed the map name and "Live" out of a phone's status line.
   Flexbox shares a squeeze by flex-shrink x width, so the map name's huge
   flex-shrink takes all of it: the warning's share stays far under a pixel
   (even 0.05 px would cut "No update for 6 s" to "No update for 6..."). The
   2 px clip margin: a warning that fits keeps its last letter's edge pixel. */
.status.warn > .st-state { flex: none; }
.status.warn > .st-map { flex-shrink: 100000; min-width: 2em; }
/* (a small screen: no room for the count and the map name next to a warning) */
.compact-ui .status.warn > .st-viewers, .compact-ui .status.warn > .st-map { display: none; }
.status.warn > .st-stale { flex: 0 1 auto; min-width: 0; overflow: hidden; overflow: clip; overflow-clip-margin: 2px; text-overflow: ellipsis; }
.levels { height: var(--tile); }
.levels > .tabs { margin: 0; }

/* The settings panel: one column of the menu (276 px + padding), under the gear. */
.settings {
  position: fixed;
  z-index: 30;
  top: calc(var(--area-t) + var(--tile) + 8px);
  left: var(--area-l);
  width: calc(var(--col) + 2 * var(--pad));
  max-width: calc(100% - var(--area-l) - var(--edge-r));
  max-height: calc(100% - var(--area-t) - var(--tile) - 8px - var(--edge-b));
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* CS2 style: the Overlay style's own rows and color squares greyed out and
   inert (settingspanel.js overlayOnly), like a dead player's row. */
.settings.cs2-style .overlay-only { opacity: 0.4; pointer-events: none; }
/* A short screen (the panel scrolls): its tab row stays at the top. */
.settings .tabs { position: sticky; top: calc(-1 * var(--pad)); z-index: 1; background: var(--bg); }
/* All pages in one spot: the panel is as tall as the tallest. */
.pages { display: grid; }
.pages > .page { grid-area: 1 / 1; visibility: hidden; }
.pages > .page.shown { visibility: visible; }

/* The planted bomb: bottom middle of the map. */
.bomb {
  position: fixed;
  z-index: 20;
  left: var(--area-l);
  right: var(--area-r);
  bottom: var(--area-b);
  width: 220px;
  max-width: calc(100% - var(--area-l) - var(--area-r));
  margin: 0 auto;
  overflow: hidden;
}
/* Beside the docks (a big screen, the T dock in its own column, app.js
   layout): at the bottom of that column, under the dock, so it never covers
   the map. */
.bomb-side .bomb { left: var(--edge-l); right: auto; bottom: var(--edge-b); width: min(220px, calc(var(--area-l) - var(--edge-l) - 8px)); margin: 0; }
/* A narrow panel cuts "Bomb A" short instead of letting "30.0 s" run out of it. */
.bomb .pline > .b-left { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.b-right { margin-left: auto; }
/* A small screen (a phone held sideways): the map between the docks is
   small, so the panels over it are too: 32 px tiles instead of 42, and the
   bomb panel joins the row of the status line and the floors (after them,
   never over them); the map starts under that row (app.js COMPACT_ROW). */
.compact-ui { --tile: 32px; }
.compact-ui .gearbtn, .compact-ui .fsbtn { padding: 9px; }
.compact-ui .status, .compact-ui .levels { padding: 9px 10px; }
.compact-ui .status { gap: 10px; }
.compact-ui .bomb { position: static; flex: 0 1 200px; min-width: 120px; min-height: var(--tile); width: auto; padding: 8px; margin: 0; }
/* (no bomb: still holding its place, unseen - see app.js COMPACT_ROW) */
.compact-ui .bomb[hidden] { display: block; visibility: hidden; }

/* ---- Team docks ------------------------------------------------------------------------ */
/* The width comes from docks.js (--dock-w): the menu's column on a big
   screen, narrower on a small one. */
.docks { position: fixed; inset: 0; z-index: 10; pointer-events: none; --dock-w: 304px; }
.dock {
  position: fixed;
  display: flex;
  flex-direction: column;
  width: var(--dock-w);
  max-height: calc(100% - var(--edge-t) - var(--edge-b));
  padding-bottom: 8px;   /* + the cards' own spacing = 14 */
  pointer-events: auto;
}
/* Stacked over the map (a narrow upright window): at most half the window
   tall, the map gets the rest; the cards scroll inside. */
.docks.stacked .dock { max-height: calc(50% - var(--edge-t)); }
/* Folded: only the arrow is left, a 42 px square like the gear. */
.dock.collapsed { width: var(--tile); height: var(--tile); padding: var(--pad); }
.dock.collapsed > .divider, .dock.collapsed > .dock-rows, .dock.collapsed .dock-title { display: none; }
.dock-head { display: flex; flex: none; align-items: flex-start; gap: var(--gap); height: var(--lh); }
.dock-title { display: flex; flex: 1 1 auto; gap: var(--pad); min-width: 0; height: var(--lh); touch-action: none; }
.dock-name { flex: 1 1 auto; min-width: 0; text-align: left; white-space: nowrap; overflow: hidden; overflow: clip visible; text-overflow: ellipsis; }
.dock-count { flex: none; }
/* The arrow: a small triangle pointing to the dock's own edge while open
   ("fold it away"), the other way while folded. */
.dock-arrow { display: flex; flex: none; align-items: center; justify-content: center; width: var(--lh); height: var(--lh); }
.dock-arrow > .tri { width: 0; height: 0; border-top: 5px solid transparent; border-bottom: 5px solid transparent; border-right: 6px solid var(--text); opacity: 0.7; }
.dock.right:not(.collapsed) .tri, .dock.left.collapsed .tri { border-right: 0; border-left: 6px solid var(--text); }
.dock > .divider { flex: none; margin: var(--pad) 0 var(--gap); }
.dock-rows { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }
.dock-empty { height: calc(var(--lh) + 12px); padding: 6px 0; }

/* A player's CARD (the reference's lists, cleaner):
     [AB]  Name (you)  FLASHED ........ $4750
     [AB]  HP 100 [armor][kit] ....... 26 / 30
     ---------------------------------------- health
     [AK-47] [USP-S] [fl he sm] [c4]          the weapons            */
.prow {
  display: grid;
  grid-template-columns: 26px minmax(0, 1fr);
  grid-template-rows: var(--lh) var(--lh) auto auto;
  column-gap: var(--gap);
  row-gap: 2px;
  width: 100%;
  padding: 6px var(--gap) 4px;
  background: var(--btn);
  outline: 1px solid var(--line);
  outline-offset: -1px;
  /* The followed player: a line in his color down the left edge. */
  box-shadow: inset 2px 0 0 var(--accent, transparent);
  text-align: left;
}
.prow + .prow { margin-top: 6px; }
/* Nothing a card holds paints outside it: the names clip only sideways (tall
   accents must show), so a name stacked with dozens of combining marks
   ("Zalgo") would otherwise climb over the cards above and below (Firefox;
   Chromium already clips a button's content). The card's own hover
   background and focus outline are not its content: unchanged. */
.prow { contain: paint; }
.prow.dead > * { opacity: 0.4; }   /* menulayout.h kGreyedOutAlpha */
.prow.dead .pname { color: var(--dim); }
.ini {
  display: flex;
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: center;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
}
.ini.gone { background-color: var(--dim); color: var(--text); }   /* dead: grey, whatever his color */
.pline { display: flex; align-items: flex-start; gap: var(--inner); height: var(--lh); min-width: 0; white-space: nowrap; }
.pline > span { flex: none; }
.prow > .l1 { grid-column: 2; grid-row: 1; }
.prow > .l2 { grid-column: 2; grid-row: 2; }
.pname { flex: 0 1 auto !important; min-width: 0; overflow: hidden; overflow: clip visible; text-overflow: ellipsis; }
.prow.t .pname { color: var(--t-name); }
.prow.ct .pname { color: var(--ct-name); }
/* FLASHED / DEFUSING / PLANTING: a small tag. */
.pflags { height: 12px; margin-top: 1px; padding: 0 3px; font-size: 9px; line-height: 12px; letter-spacing: 0.3px; background: var(--box-off); color: var(--text); overflow: hidden; }
.pmoney, .pammo { margin-left: auto; }
.phl { font-size: 9px; }   /* "HP", small and grey */
.pgear { display: flex !important; align-items: center; gap: 4px; height: var(--lh); }
.pbar { display: block; height: 2px; background: var(--box-off); }
.prow > .pbar { grid-column: 1 / -1; grid-row: 3; margin: 3px 0 2px; }
.pfill { display: block; width: 0; height: 100%; }
/* The weapons: the game's white silhouettes (black on the light theme). The
   one in his hands full strength with a line in his color under it, the
   others faded. */
.pshow { display: flex; grid-column: 1 / -1; grid-row: 4; align-items: flex-end; gap: var(--gap); min-height: 18px; overflow: hidden; }
.wpn { display: block; width: auto; max-width: none; user-select: none; -webkit-user-drag: none; }
:root[data-theme="light"] .wpn { filter: brightness(0); }
.witem { display: flex; flex: none; align-items: flex-end; padding-bottom: 2px; border-bottom: 2px solid transparent; opacity: 0.45; }
.witem.on { opacity: 1; border-bottom-color: var(--hand, var(--text)); }
.wsmall { display: flex; flex: none; align-items: flex-end; gap: 3px; }
/* No pictures (an older overlay): the weapons as text chips. */
.chip { height: var(--lh); padding: 0 4px; background: var(--box-off); color: var(--dim); white-space: nowrap; }
.pshow > .chip { flex: none; }
.chip.on { color: var(--text); }   /* the one in his hands */
.pshow:has(> .chip) { flex-wrap: wrap; gap: 4px; }
/* The bomb panel's bars in the colors of the bomb's rings on the map. */
.b-fill { background: var(--text); }
.b-fill.b-timer { background: rgb(235, 60, 45); }
.b-fill.b-defuse { background: rgb(150, 200, 250); }
/* Following someone: his card stays as it is, the others go grey. */
.docks.following .prow:not(.sel) { color: var(--dim); }
.docks.following .prow:not(.sel) .pname { color: var(--dim); }
.docks.following .prow:not(.sel) .chip.on { color: var(--dim); }
.docks.following .prow:not(.sel) .witem.on { opacity: 0.6; }
.docks.following .prow:not(.sel) .pgear { opacity: 0.6; }

/* Small screens (a phone held sideways): tighter docks, the same layout. */
.docks.compact .dock { padding: 8px 8px 6px; }
.docks.compact .dock.collapsed { padding: var(--pad); }
.docks.compact .dock > .divider { margin: 8px 0 6px; }
.docks.compact .prow { grid-template-columns: 20px minmax(0, 1fr); column-gap: 6px; row-gap: 1px; padding: 4px 6px 3px; }
.docks.compact .prow + .prow { margin-top: 4px; }
.docks.compact .ini { width: 20px; height: 20px; font-size: 9px; }
.docks.compact .prow > .pbar { margin: 2px 0 1px; }
.docks.compact .pshow { gap: 5px; min-height: 14px; }
.docks.compact .phl { display: none; }

/* "Loading map..." in the middle of the map while a new map arrives. */
.mapnote {
  position: fixed;
  top: var(--map-t);
  bottom: var(--map-b);
  left: var(--area-l);
  right: var(--area-r);
  z-index: 15;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.mapnote > .panel { white-space: nowrap; }

/* ---- Ended (also the home page's box) ----------------------------------------------------- */
.ended {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gutter-t) var(--gutter-r) var(--gutter-b) var(--gutter-l);
}
.endbox { width: calc(var(--col) + 2 * var(--pad)); max-width: 100%; }
/* Home, ended.html and a radar page whose session ended: the radar's dark. */
.backdrop, #ended { background: rgb(0, 0, 0); }

/* The phoenix.pub logo, in the top-left corner of the home and "Session ended" pages (the
   user's final choice after trying it above the box): web/phoenix.png = images/phoenix.png
   cropped to its visible outline and scaled once, losslessly, to 320 px; shown at 40 px. */
.brand { position: fixed; top: var(--gutter-t); left: var(--gutter-l); width: 40px; height: 40px; display: block; }
