/* ============================================================================================
   UBQ CONTROLLER — RTS for the real world.

   `docs/ubq-architecture.md` §11: a system rail, a world-view that is a map and a list, and a
   context panel that flexes between the roster and one unit. Select, issue, watch the answers
   come back as motion on the board.

   WHY IT IS LIGHT NOW, having been dark since Brief 3.

   The dark version was argued from "a room with a wall of screens", which is a room this
   product has never been in. The actual reader is a site manager or a dispatcher, on a desktop,
   indoors, in daylight, for a whole working day — and next to the two surfaces this system
   already has, both of which are dark-on-light because a reflective panel in sunlight has no
   other option. Three tiers of one platform that do not look like one platform is a photograph
   problem before it is a design problem, and this brief's frames are the flyer's stills.

   COLOUR CARRIES MEANING HERE, and that is the opposite of the rule on the wrist. Brief 11
   removed meaning from colour on the node's panel, because a memory LCD read in daylight,
   torchlight and a scratched protector loses it. This is a trained user on a calibrated screen
   indoors, so the constraint does not apply and the bandwidth is worth having. The rule that
   survives both is the real one: **never let colour be the only carrier.** Every status here
   has a word beside its colour, for the same reason the wrist has a glyph.

   TOKENS, AND WHY THERE ARE TOKENS. The DEVICE-profile lesson from Brief 12, one tier up: v0.3
   of the node told the shell `176` in forty places and a second panel would have been forty
   edits with one of them missed. Every colour, radius and rhythm in this file is declared once
   below and read everywhere else, so a restyle for a client's palette is an edit to :root and
   nothing else. Nothing below the token block may contain a raw colour.
   ============================================================================================ */

:root {
  /* --- paper and ink -----------------------------------------------------------------
     THE GREYS WERE TEAL-TINTED and nobody had noticed, because a tint is invisible until it
     sits beside a neutral. `#f4f6f5` and `#14181b` are a cool green-white and a blue-black:
     the old brand leaking into the field it was supposed to sit on. The ramp is now the
     front page's, warm-neutral, so the two surfaces are the same product rather than two
     products that happen to share a logo. Ruled in `docs/ubq-look.md`. */
  --paper:       #faf9f7;   /* the ground behind everything */
  --panel:       #ffffff;   /* a surface that holds content */
  --panel-2:     #f2f0ec;   /* a surface behind a surface: rail, headers, table stripes */
  --panel-3:     #e7e4de;
  --ink:         #1a1a1a;   /* body text. Ruled: not pure black */
  --ink-2:       #4a4744;   /* secondary text */
  --ink-3:       #7c7771;   /* labels, units, the quiet half of a pair */
  --line:        #e3e0da;
  --line-2:      #cfcbc3;

  /* --- brand -------------------------------------------------------------------------
     THE MARK RULES THE PALETTE. `assets/UBQlogo1.png` is black, white and one orange, and the
     orange in it samples `#f15a24` exactly — the value `docs/ubq-look.md` already ruled and the
     front page was already built on. So the console's brand is that orange, and **the teal that
     stood here since Brief 3 is retired**: it was decoration from before there was a mark, and
     a product whose two surfaces brand themselves differently is two products.

     ORANGE IS FOR ACTIONS AND FOR WHERE YOU ARE — the primary button, the one click a screen is
     built around, the destination you are on, a focus ring, a hover. **It is not for
     selection**, and that is the decision in this block worth defending: a selected row and a
     warning row must never be two shades of one hue, and `--warn` is amber. A 14% orange wash
     and an 18% amber wash are the same pale warm smear, which is precisely the "two claims
     looking like one" this file has a rule against. Selection is interface state and not
     operational meaning, so selection is ink. */
  --brand:       #f15a24;
  --brand-ink:   #ffffff;
  --brand-wash:  #f15a2414;

  /* What you have picked: rows, chips, the marquee, the sort. Ink, never a hue — see above. */
  --sel:         #1a1a1a;
  --sel-wash:    #1a1a1a0d;

  /* --- functional status: the health bar, and every verdict that shares its vocabulary */
  --ok:          #1d7a4c;
  --ok-wash:     #1d7a4c16;
  --warn:        #a8620b;
  --warn-wash:   #a8620b18;
  --bad:         #b02a20;
  --bad-wash:    #b02a2016;
  --unknown:     #8b8681;
  --unknown-wash:#8b868116;

  /* --- claims: who said this ---------------------------------------------------------
     Direction (outbound), a courier's witness, and a node that is not a person. Three
     different *kinds of claim*, each with its own colour and its own word, because the
     console's oldest rule is that a screen must never let two claims look like one. */
  --out:         #2a55a8;
  --out-wash:    #2a55a814;
  --witness:     #6c3fa5;
  --witness-wash:#6c3fa514;
  --machine:     #0b6b78;   /* a telematics node: true, timed, and attested by nobody */
  --machine-wash:#0b6b7814;

  /* --- rhythm ------------------------------------------------------------------------ */
  --radius:      8px;
  --radius-sm:   5px;
  --gap:         12px;
  --topbar-h:    52px;
  --wsbar-h:     38px;
  /* The two panes' share of the row, set inline on .panes by the divider drag. Grow factors
     rather than a width, so both panes squeeze PROPORTIONALLY when the composer displaces them
     — a percentage would have taken the whole concertina out of the right-hand pane. */
  --grow-a:      50;
  --grow-b:      50;
  /* The third pane. Zero at rest; this wide while communicating. */
  --composer-w:  380px;
  --concertina:  260ms;
  --ease:        cubic-bezier(.2, .7, .2, 1);

  --shadow:      0 1px 2px #1a1a1a12, 0 6px 18px #1a1a1a0e;
  /* The last three literals in this file, and they live here for the same reason every other
     colour does: a restyle is an edit to :root and nothing else. */
  --hover:       #0000000a;   /* a press of ink over whatever is underneath */
  --pin-shadow:  #1a1a1a40;
  --glass:       #ffffffe8;   /* a tooltip that lets the map through */
  --on-bad:      #ffffff;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  color-scheme: light;
}

* { box-sizing: border-box; }
html, body { height: 100%; }

/* THE `hidden` ATTRIBUTE HAS TO WIN, and this line is why the composer's × did not work.
   `[hidden] { display: none }` lives in the UA stylesheet, and ANY author rule that sets
   `display` beats it — specificity never enters into it. The old drawer declared
   `display: flex`, so `el.hidden = true` was a no-op and the panel could not be dismissed: the
   script was right and the stylesheet quietly overruled it. Anything this file styles as flex or
   grid that the script also hides needs this, so it is stated once, globally, for all of them. */
[hidden] { display: none !important; }
body {
  margin: 0; background: var(--paper); color: var(--ink);
  font: 13.5px/1.5 var(--sans);
  -webkit-font-smoothing: antialiased;
}
a { color: inherit; text-decoration: none; }
button { font-family: inherit; }

/* --- the system bar --------------------------------------------------------------------
   Was a 190 px column holding seven words. On a board whose job is showing two things at once,
   a fifth of the width went to navigation that changes once an hour — and a bar grows RIGHTWARD
   as destinations are added, which a column cannot do without getting taller and emptier at the
   same time. Still navigation and system state and nothing else. */

body { display: flex; flex-direction: column; overflow: hidden; }
.top {
  height: var(--topbar-h); flex: none; display: flex; align-items: center; gap: 18px;
  padding: 0 16px; background: var(--panel); border-bottom: 1px solid var(--line);
}
/* THE MARK IS THE MARK NOW, not three letterspaced characters approximating one.

   IT IS THE WORDMARK HERE AND THE FULL LOCKUP ON THE LOGIN AND THE FRONT PAGE, and that is a
   size decision rather than a branding one. "FIELD & FLEET" is 17% of the lockup's height, so
   in a top bar tall enough for a working board it renders at five or six pixels — not small
   type but a grey smear, which makes the whole mark look out of focus. A strapline nobody can
   read is worse than no strapline, so the bar gets the same mark with that line dropped. The
   login card and the front page's header both have the room and both use the full lockup. */
.mark { display: flex; align-items: center; gap: 9px; flex: none; }
.mark img { display: block; height: 26px; width: auto; }
.mark span {
  font-size: 9px; letter-spacing: .18em; font-weight: 600; color: var(--ink-3);
  text-transform: uppercase; align-self: center; padding-left: 9px;
  border-left: 1px solid var(--line-2);
}
.topnav { display: flex; align-items: center; gap: 2px; min-width: 0; overflow: hidden; }
.topnav a {
  display: flex; align-items: center; gap: 5px; padding: 6px 11px; border-radius: var(--radius-sm);
  color: var(--ink-2); font-size: 12px; letter-spacing: .05em; text-transform: uppercase;
  font-weight: 600; white-space: nowrap;
}
.topnav a:hover { color: var(--ink); background: var(--panel-2); }
.topnav a.on { color: var(--brand); background: var(--brand-wash); }
.topnav a.later { color: var(--ink-3); font-weight: 500; }
.topnav a .tag {
  font-size: 9px; letter-spacing: .08em; color: var(--ink-3); border: 1px solid var(--line-2);
  border-radius: 3px; padding: 0 4px; font-weight: 500;
}
.sys {
  margin-left: auto; display: flex; align-items: center; gap: 10px; flex: none;
  font-size: 11px; color: var(--ink-3);
}
.sys .pack { font-family: var(--mono); font-size: 10px; }
.sys .out-link:hover { color: var(--ink); }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line-2); flex: none; }
.dot.live { background: var(--ok); animation: ping 1.6s ease-out; }
@keyframes ping {
  from { box-shadow: 0 0 0 0 var(--ok); }
  to   { box-shadow: 0 0 0 9px transparent; }
}
main { flex: 1; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }

/* --- headers (assurance, briefings, soon) ------------------------------------------------ */

.head {
  padding: 0 18px; height: 48px; border-bottom: 1px solid var(--line); background: var(--panel);
  display: flex; align-items: center; gap: 14px; flex: none;
}
.head h1 {
  margin: 0; font-size: 13px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-2);
}
.head .sub { color: var(--ink-3); font-size: 12px; font-variant-numeric: tabular-nums; }
.head .right { margin-left: auto; color: var(--ink-3); font-size: 11px; font-family: var(--mono); }

/* ===========================================================================================
   SHELVED — the rules below serve console/shelved/track.brief13.js and nothing on a live page.
   Kept here rather than in a stylesheet no page loads, because a file nothing imports is just as
   dead and harder to find. Restoring the workspace frame restores these with it. The sections
   concerned are: the workspace bar, the panes and the concertina, the list half of the
   world-view, the roster view, the unit face, activities/movements/flags, the live feed, compose.
   The token palette, the system bar, status, map furniture, assurance, briefings and the empty
   states are all LIVE and shared.
   =========================================================================================== */

/* --- the workspace bar ------------------------------------------------------------------
   Workspace tabs on the left, the global selection on the right. The selection lives HERE and
   not inside a pane, because it is global: it survives changing a pane's view, dragging the
   divider and switching workspace. Both panes can see it, which is the point. */

.wsbar {
  height: var(--wsbar-h); flex: none; display: flex; align-items: center; gap: 10px;
  padding: 0 12px; background: var(--panel-2); border-bottom: 1px solid var(--line);
}
.ws-tabs { display: flex; align-items: center; gap: 2px; flex: none; }
.ws-tabs button {
  border: 1px solid transparent; background: transparent; cursor: pointer;
  padding: 5px 11px; border-radius: var(--radius-sm);
  font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3);
}
.ws-tabs button:hover { color: var(--ink); background: var(--hover); }
.ws-tabs button.on {
  color: var(--brand); background: var(--panel); border-color: var(--line-2);
}
.ws-count {
  font-size: 11px; color: var(--ink-3); font-variant-numeric: tabular-nums; flex: none;
  padding-left: 4px; border-left: 1px solid var(--line-2);
}
.ws-right { margin-left: auto; color: var(--ink-3); font-size: 11px; font-family: var(--mono); flex: none; }

/* SELECTION IS FIRST-CLASS STATE and this is where it is said out loud. One / team / all has to
   be unambiguous, because every command below keys off it and a highlight is not a sentence. */
.selbar { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; min-width: 0; }
.selbar.none { color: var(--ink-3); }
.selbar .who { font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.selbar .n {
  font-family: var(--mono); background: var(--sel); color: var(--brand-ink);
  border-radius: 999px; padding: 1px 7px; font-size: 11px; flex: none;
}
.selbar .clear {
  border: 0; background: transparent; color: var(--ink-3); cursor: pointer; font-size: 15px;
  line-height: 1; padding: 0 2px;
}
.selbar .clear:hover { color: var(--ink); }
.act {
  border: 1px solid var(--line-2); background: var(--panel); border-radius: var(--radius-sm);
  color: var(--ink); padding: 5px 10px; font-size: 12px; font-weight: 600; cursor: pointer;
  white-space: nowrap;
}
.act:hover:not(:disabled) { border-color: var(--brand); color: var(--brand); }
.act:disabled { color: var(--ink-3); cursor: default; font-weight: 500; }
.act.primary { background: var(--brand); border-color: var(--brand); color: var(--brand-ink); }
.act.primary:hover:not(:disabled) { filter: brightness(1.08); color: var(--brand-ink); }
.act.out { border-color: var(--out); color: var(--out); }
.act.out:hover:not(:disabled) { background: var(--out-wash); }

/* --- the panes, and the concertina --------------------------------------------------------
   TWO AT REST, THREE WHILE COMMUNICATING, and the third DISPLACES rather than covers. The row
   is a flex line of four tracks: pane A, the divider, pane B, and the composer, whose basis is
   zero until the operator acts. Opening it squeezes A and B narrower; closing concertinas them
   back out. Nothing is ever hidden behind it, which is the whole argument: at the moment of
   composing, WHO you are sending to and WHAT it is about are exactly the two things you still
   need on screen.

   The two panes hold their RATIO through the squeeze because they are grow factors sharing what
   is left rather than percentages of the whole. That is the one detail that makes this read as a
   concertina and not as the right-hand pane being eaten. */

.panes { flex: 1; min-height: 0; display: flex; align-items: stretch; }
.pane {
  display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--panel);
  flex: 1 1 0;
}
.pane[data-pane="0"] { flex-grow: var(--grow-a); }
.pane[data-pane="1"] { flex-grow: var(--grow-b); }
.pane-head {
  height: 34px; flex: none; display: flex; align-items: center; gap: 8px; padding: 0 8px 0 10px;
  border-bottom: 1px solid var(--line); background: var(--panel-2);
}
.pane-note { font-size: 11px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pane-title {
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-2); flex: none;
}
.viewpick {
  border: 1px solid var(--line-2); background: var(--panel); color: var(--ink);
  border-radius: var(--radius-sm); padding: 3px 6px; font: inherit; font-size: 11px;
  font-weight: 700; letter-spacing: .06em; text-transform: uppercase; cursor: pointer;
}
.viewpick:focus { outline: none; border-color: var(--brand); }
.pane-body { flex: 1; min-height: 0; position: relative; overflow: auto; }
/* The map fills its pane and must not scroll with it. */
.pane-body.is-map { overflow: hidden; }

.divider { flex: 0 0 6px; background: var(--line); cursor: col-resize; position: relative; }
.divider::after {
  content: ""; position: absolute; inset: 0 -3px; /* a 12 px grab target on a 6 px line */
}
.divider:hover, .divider.dragging { background: var(--brand); }
body.resizing { cursor: col-resize; user-select: none; }

/* THE COMPOSER — the third pane. A pane in the layout and not in the pane machinery: no
   workspace can name it, it is not in the view registry, and the poll cannot rebuild it.
   `visibility` rather than `display` because a track that is `display: none` cannot animate
   open — and because hidden visibility takes its fields out of the tab order, which a zero-width
   overflow would not. It is delayed on the way out so the fields are still there to see sliding
   shut, and immediate on the way in. */
.pane.composer {
  flex: 0 0 0px; overflow: hidden; visibility: hidden;
  /* An INSET shadow rather than a border, so the content box is exactly `--composer-w` and the
     children below can be held at that width without overflowing it by the border's 1px — which
     a `.pane-body` with `overflow: auto` would have answered with a permanent 1px scrollbar. */
  box-shadow: inset 1px 0 0 var(--line-2);
  transition: flex-basis var(--concertina) var(--ease),
              visibility 0s linear var(--concertina);
}
.panes.composing .pane.composer {
  flex-basis: var(--composer-w); visibility: visible; transition-delay: 0s;
}
/* The contents keep their width while the track clips them, so the composer SLIDES rather than
   reflowing its form through 380 intermediate widths. */
.pane.composer > * { min-width: var(--composer-w); }
.pane.composer .pane-head { padding-right: 4px; }
.pane.composer .pane-body { padding: 14px; }
.pane.composer .x {
  margin-left: auto; border: 0; background: transparent; color: var(--ink-3); cursor: pointer;
  font-size: 20px; line-height: 1; padding: 0 8px; flex: none;
}
.pane.composer .x:hover { color: var(--ink); }

@media (prefers-reduced-motion: reduce) {
  .pane.composer { transition-duration: 0s; }
}

/* One pane at a time when there is not room for two. The ceiling is two by choice; the floor is
   one by arithmetic — a 420 px pane is not a viewport, it is a column of ellipses.

   AND THE CONCERTINA STOPS HERE, honestly. Displacing needs width to displace into: on one
   500 px pane, squeezing to make room for a 380 px composer leaves neither readable. So below
   this breakpoint the composer is what it used to be everywhere — a full-width drawer over the
   top. The affordance degrades to the thing it replaced rather than to a worse version of
   itself. */
@media (max-width: 900px) {
  .divider, .pane[data-pane="1"] { display: none; }
  .pane.composer {
    position: fixed; z-index: 900; left: 0; right: 0; bottom: 0;
    top: calc(var(--topbar-h) + var(--wsbar-h));
    flex-basis: auto; transition: none;
    box-shadow: var(--shadow);   /* over the top now, so it casts one rather than drawing a seam */
  }
  .pane.composer > * { min-width: 0; }
}

#map-host { display: none; }
#map { position: absolute; inset: 0; }
.leaflet-container { background: var(--panel-3); font: 12px var(--sans); }
.leaflet-control-attribution { font-size: 9px; }

/* The marquee: spatial selection, drawn where the hand is. */
.marquee {
  position: absolute; z-index: 600; border: 1.5px dashed var(--sel);
  background: var(--sel-wash); pointer-events: none;
}

/* --- the list half of the world-view ---------------------------------------------------
   File-Explorer duality. The map selects SPATIALLY — pan, zoom, click, marquee. The list selects
   BY ATTRIBUTE — sort a column, filter to a word, click, shift-click. Neither is a view of the
   other: they are two ways of naming the same set, and the set is what persists. */

.listview table { width: 100%; border-collapse: collapse; font-size: 13px; }
.listview th {
  position: sticky; top: 0; z-index: 2; background: var(--panel-2);
  text-align: left; font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 700; padding: 8px 12px; border-bottom: 1px solid var(--line);
  cursor: pointer; user-select: none; white-space: nowrap;
}
.listview th.sorted { color: var(--sel); }
.listview td { padding: 8px 12px; border-bottom: 1px solid var(--line); vertical-align: middle; }
.listview tr { cursor: pointer; }
.listview tr:hover td { background: var(--panel-2); }
.listview tr.sel td { background: var(--sel-wash); box-shadow: inset 3px 0 0 var(--sel); }
.filters { display: flex; justify-content: flex-end; padding: 8px 12px; }
.filters input {
  width: 220px; background: var(--panel); color: var(--ink); border: 1px solid var(--line-2);
  border-radius: var(--radius-sm); padding: 6px 9px; font: inherit; font-size: 12.5px;
}
.filters input:focus { outline: none; border-color: var(--brand); }

/* --- status: the pack's binding constraint, drawn ---------------------------------------
   §11's "health bar". The SLOT is config-driven — `console/pack.json` declares what is
   measured — so nothing here names readiness or freshness. It renders whatever parts the
   server sends, in the order the pack declared them, with a word beside every colour. */

.bar { display: inline-flex; gap: 2px; align-items: center; vertical-align: middle; }
.bar i { display: block; width: 15px; height: 6px; border-radius: 2px; background: var(--unknown); }
.bar i[data-state="good"] { background: var(--ok); }
.bar i[data-state="warn"] { background: var(--warn); }
.bar i[data-state="bad"] { background: var(--bad); }
.bar i[data-state="unknown"] { background: transparent; box-shadow: inset 0 0 0 1px var(--line-2); }
.statusword { font-size: 11px; color: var(--ink-3); }
[data-state="good"] > .statusword { color: var(--ok); }
[data-state="warn"] > .statusword { color: var(--warn); }
[data-state="bad"] > .statusword { color: var(--bad); }

/* --- the roster view: the list of units, flexing to one unit ----------------------------
   §11's context panel, now assignable to either pane. Nothing selected and it is the roster:
   every unit, its bar, its silence. One unit selected and it is that unit in full, with the
   actions that apply to it — and a way back to the list that keeps the selection. It never
   empties and never becomes a third thing. */

.back {
  border: 1px solid var(--line-2); background: var(--panel); color: var(--ink-2); cursor: pointer;
  font-size: 11px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 4px 9px; border-radius: var(--radius-sm); margin: 10px 0 4px 12px;
}
.back:hover { color: var(--brand); border-color: var(--brand); }
.pane-sub {
  padding: 8px 12px; border-bottom: 1px solid var(--line); background: var(--panel-2);
  font-size: 11px; color: var(--ink-3); display: flex; align-items: center; gap: 8px;
}
.pane-sub .tally { margin-left: auto; font-family: var(--mono); }

/* a roster row */
.unit {
  padding: 9px 12px; border-bottom: 1px solid var(--line); cursor: pointer;
  display: grid; grid-template-columns: 1fr auto; gap: 4px 10px; align-items: center;
}
.unit:hover { background: var(--panel-2); }
.unit.sel { background: var(--sel-wash); box-shadow: inset 3px 0 0 var(--sel); }
.unit .who { font-weight: 600; display: flex; align-items: center; gap: 6px; min-width: 0; }
.unit .who .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.unit .who.unknown .name { font-family: var(--mono); font-weight: 500; color: var(--ink-2); }
.unit .when {
  font-size: 11px; color: var(--ink-3); font-family: var(--mono); text-align: right;
  white-space: nowrap;
}
.unit .line2 { grid-column: 1 / -1; display: flex; align-items: center; gap: 8px; min-width: 0; }
.unit .act-text {
  color: var(--ink-2); font-size: 12px; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; flex: 1;
}

/* The kind chip. A unit is node-agnostic and may be a person, a vehicle or a crew, so the
   board says which — briefly, and in a word rather than only in a colour. */
.kind {
  font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; font-weight: 700;
  border-radius: 3px; padding: 1px 5px; border: 1px solid var(--line-2); color: var(--ink-3);
  flex: none;
}
.kind[data-kind="vehicle"] { color: var(--machine); border-color: var(--machine); background: var(--machine-wash); }
.kind[data-kind="crew"] { color: var(--out); border-color: var(--out); background: var(--out-wash); }

/* --- the unit face --------------------------------------------------------------------- */

.face { padding: 14px 12px; }
.face h2 { margin: 0 0 2px; font-size: 17px; }
.face h2.unknown { font-family: var(--mono); font-size: 15px; color: var(--ink-2); }
.face .role { color: var(--ink-3); font-size: 12px; margin-bottom: 14px; }
.face h3 {
  font-size: 10.5px; letter-spacing: .11em; text-transform: uppercase; color: var(--ink-3);
  border-top: 1px solid var(--line); padding-top: 12px; margin: 18px 0 9px; font-weight: 700;
}
.face dl { display: grid; grid-template-columns: 104px 1fr; gap: 6px 10px; margin: 0 0 14px; }
.face dt {
  color: var(--ink-3); font-size: 10.5px; letter-spacing: .05em; text-transform: uppercase;
  padding-top: 2px;
}
.face dd { margin: 0; font-family: var(--mono); font-size: 11.5px; word-break: break-word; }

.statusblock {
  border: 1px solid var(--line); border-radius: var(--radius); padding: 11px 12px;
  margin-bottom: 14px; background: var(--panel-2);
}
.statusblock .top { display: flex; align-items: center; gap: 9px; margin-bottom: 8px; }
.statusblock .top .label {
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
  font-weight: 700;
}
.statusblock .part {
  display: flex; align-items: baseline; gap: 8px; font-size: 12px; padding: 3px 0;
}
.statusblock .part .k { color: var(--ink-3); min-width: 78px; }
.statusblock .part .v { font-weight: 600; }
.statusblock .part[data-state="good"] .v { color: var(--ok); }
.statusblock .part[data-state="warn"] .v { color: var(--warn); }
.statusblock .part[data-state="bad"] .v { color: var(--bad); }
.statusblock .part[data-state="unknown"] .v { color: var(--ink-3); font-weight: 500; }
.statusblock .declared {
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--line);
  font-size: 10.5px; color: var(--ink-3); line-height: 1.45;
}

/* The node stack: what this unit reports through, and what each of those is entitled to
   claim. §3's membrane, on screen — and the one place a controller can see that a pin came
   from a box on a dashboard rather than from a person. */
.node {
  display: flex; gap: 8px; align-items: baseline; padding: 7px 0;
  border-bottom: 1px solid var(--line); font-size: 12px;
}
.node:last-child { border-bottom: 0; }
.node .nid { font-family: var(--mono); font-size: 11px; color: var(--ink-2); }
.node .says { color: var(--ink-3); font-size: 11px; flex: 1; }
.node .attest {
  font-size: 9.5px; letter-spacing: .06em; text-transform: uppercase; font-weight: 700;
  border-radius: 3px; padding: 1px 5px; border: 1px solid var(--line-2); color: var(--ink-3);
}
.node .attest[data-attested="false"] { color: var(--machine); border-color: var(--machine); }

.rowline { display: flex; align-items: baseline; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--line); font-size: 12.5px; }
.rowline:last-child { border-bottom: 0; }
.rowline .grow { flex: 1; min-width: 0; }
.rowline .when { font-family: var(--mono); font-size: 11px; color: var(--ink-3); white-space: nowrap; }
.muted { color: var(--ink-3); }
.small { font-size: 11.5px; }

/* --- activities, movements and flags — the WHAT, in whichever pane holds it --------------
   This was a fixed strip under the map, 216 px tall whether or not anybody was reading it. It is
   now a first-class pane and the DEFAULT left one, because the doing is what a controller is
   controlling: an activity is a wrapper that contains the units assigned to it, the objects
   carried in it, its place and its dependency, and the roster is a list of its participants.

   The rules for the strip's own chrome — `.strip`, `.tabs` and a second `.panes` that put
   `overflow: auto` on the pane row — were still in this file after the frame stopped using
   them, and the stray `.panes` was quietly reaching the live layout. Deleted with this rewrite.
*/

.happening {
  display: grid; grid-template-columns: 108px 1fr auto; gap: 12px; align-items: start;
  padding: 11px 12px; border-bottom: 1px solid var(--line); cursor: pointer;
}
.happening:hover { background: var(--panel-2); }
.happening.sel { background: var(--sel-wash); }
.happening .kindcol { display: flex; flex-direction: column; gap: 4px; }
.happening .name { font-weight: 600; }
.happening .detail { color: var(--ink-2); font-size: 12px; margin-top: 2px; }
.happening .chain { margin-top: 5px; font-size: 12px; }
.happening .acts { display: flex; flex-direction: column; gap: 6px; align-items: flex-end; }

/* The dependency verdict. Three states and never two: `unknown` is not a shade of blocked. */
.dep {
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase; font-weight: 700;
  border-radius: 3px; padding: 2px 6px; border: 1px solid;
}
.dep[data-dep="clear"] { color: var(--ok); border-color: var(--ok); background: var(--ok-wash); }
.dep[data-dep="blocked"] { color: var(--bad); border-color: var(--bad); background: var(--bad-wash); }
.dep[data-dep="unknown"] { color: var(--ink-3); border-color: var(--line-2); }
.arrow { color: var(--ink-3); font-family: var(--mono); }

/* The adjutant. It proposes; a human issues. The panel is deliberately not styled as an
   alert or an answer — it is a suggestion with its working shown, and the working is the
   reason anybody should believe it. */
.propose {
  border: 1px solid var(--out); border-left-width: 3px; border-radius: var(--radius);
  background: var(--out-wash); padding: 11px 13px; margin: 11px 12px;
}
.propose .lead { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.propose .badge-ai {
  font-size: 9.5px; letter-spacing: .09em; text-transform: uppercase; font-weight: 700;
  color: var(--out); border: 1px solid var(--out); border-radius: 3px; padding: 1px 5px;
}
.propose h4 { margin: 0; font-size: 13.5px; }
.propose .why { color: var(--ink-2); font-size: 12.5px; margin: 7px 0 0; }
.propose .cands { margin-top: 9px; display: flex; flex-direction: column; gap: 5px; }
.propose .cand {
  display: flex; align-items: baseline; gap: 8px; font-size: 12px; padding: 4px 0;
  border-top: 1px solid var(--line);
}
.propose .cand .nm { font-weight: 600; min-width: 92px; }
.propose .cand .rs { color: var(--ink-2); flex: 1; }
.propose .cand.no .nm, .propose .cand.no .rs { color: var(--ink-3); }
.propose .cand.no .rs { text-decoration: line-through; text-decoration-color: var(--line-2); }
.propose .foot { margin-top: 10px; display: flex; gap: 8px; align-items: center; }
.propose .foot .note { font-size: 11px; color: var(--ink-3); }

/* A contingency flag states graph-truth and nothing else. §10: never "theft", never a claim
   to be responding. Loud enough to be seen; worded so that the operator owns the meaning. */
.flag {
  border: 1px solid var(--bad); border-left-width: 3px; border-radius: var(--radius);
  background: var(--bad-wash); padding: 11px 13px; margin: 11px 12px;
}
.flag h4 { margin: 0 0 5px; font-size: 12.5px; color: var(--bad); letter-spacing: .04em; text-transform: uppercase; }
.flag p { margin: 0; font-size: 12.5px; }
.flag .foot { margin-top: 7px; font-size: 11px; color: var(--ink-3); }

/* --- the live feed --------------------------------------------------------------------- */

.ev {
  padding: 8px 12px; border-bottom: 1px solid var(--line); cursor: pointer;
  display: grid; grid-template-columns: 3px 1fr auto; gap: 10px; align-items: start;
}
.ev:hover { background: var(--panel-2); }
.ev .bar-l { width: 3px; align-self: stretch; border-radius: 2px; background: var(--line-2); min-height: 22px; }
.ev[data-type="checkin"] .bar-l { background: var(--ok); }
.ev[data-type="position"] .bar-l { background: var(--machine); }
.ev[data-type^="briefing"] .bar-l,
.ev[data-type="scene_confirmed"] .bar-l { background: var(--out); }
.ev .who { font-weight: 600; }
.ev .who.unknown { font-family: var(--mono); font-weight: 500; color: var(--ink-2); }
.ev .what { color: var(--ink-2); }
.ev .meta { font-size: 11px; color: var(--ink-3); font-family: var(--mono); text-align: right; white-space: nowrap; }
.ev.fresh { animation: arrive 2.4s ease-out; }
@keyframes arrive { 0% { background: var(--ok-wash); } 100% { background: transparent; } }

/* Direction went the other way, so it is drawn the other way: its own colour and a bar on
   the right. A controller scanning the feed has to see which rows are the estate's own doing
   without reading a word of them — an outbound instruction that reads like an operative's
   action is how somebody ends up believing a person volunteered what they were asked for. */
.ev.dir { box-shadow: inset -3px 0 0 var(--out); }
.ev.dir .bar-l { background: var(--out); }
.ev.dir .what { color: var(--out); }
.ev.dir.fresh { animation: arrive-out 2.4s ease-out; }
@keyframes arrive-out { 0% { background: var(--out-wash); } 100% { background: transparent; } }

.chip {
  display: inline-block; font-size: 10px; letter-spacing: .04em; padding: 1px 5px;
  border-radius: 3px; border: 1px solid var(--line-2); color: var(--ink-2); margin-left: 5px;
  font-family: var(--mono); white-space: nowrap;
}
.chip.gps { color: var(--ok); border-color: var(--ok); background: var(--ok-wash); }
.chip.nogps { color: var(--warn); border-color: var(--warn); background: var(--warn-wash); }
.chip.late { color: var(--warn); border-color: var(--warn); }
.chip.cmd { color: var(--out); border-color: var(--out); }
.chip.witness { color: var(--witness); border-color: var(--witness); background: var(--witness-wash); }
.chip.machine { color: var(--machine); border-color: var(--machine); background: var(--machine-wash); }
.chip.bad { color: var(--bad); border-color: var(--bad); background: var(--bad-wash); }

/* --- map furniture ---------------------------------------------------------------------- */

/* THE PIN. A unit is node-agnostic, so the marker carries three independent facts and keeps
   them independent: what KIND of thing this is (shape), what its declared constraint says
   (fill), and how long since anything was heard from it (opacity). Three facts, three
   channels — a marker that mixed them would be a marker a controller has to decode. */
.pin {
  display: block; width: 14px; height: 14px; box-sizing: border-box;
  border: 2px solid var(--panel); background: var(--unknown);
  box-shadow: 0 0 0 1.5px var(--unknown), 0 1px 3px var(--pin-shadow);
  border-radius: 50%;
}
.pin[data-kind="vehicle"] { border-radius: 3px; width: 15px; height: 15px; }
.pin[data-kind="crew"] { border-radius: 2px; transform: rotate(45deg); }
.pin[data-state="good"] { background: var(--ok); box-shadow: 0 0 0 1.5px var(--ok), 0 1px 3px var(--pin-shadow); }
.pin[data-state="warn"] { background: var(--warn); box-shadow: 0 0 0 1.5px var(--warn), 0 1px 3px var(--pin-shadow); }
.pin[data-state="bad"] { background: var(--bad); box-shadow: 0 0 0 1.5px var(--bad), 0 1px 3px var(--pin-shadow); }
/* Silence is drawn by fading, not by colouring: a unit nobody has heard from is not in a
   worse state, it is in an unknown one, and those are different sentences. */
.pin[data-stale="aging"] { opacity: .72; }
.pin[data-stale="stale"] { opacity: .45; background: transparent; box-shadow: 0 0 0 1.5px var(--line-2); }
.pin[data-stale="never"] { opacity: .4; background: transparent; box-shadow: 0 0 0 1.5px var(--line-2); }
.pin[data-sel="1"] {
  outline: 2px solid var(--brand); outline-offset: 3px; opacity: 1;
}

.leaflet-tooltip.nametag {
  background: var(--glass); border: 1px solid var(--line-2); color: var(--ink);
  box-shadow: var(--shadow); padding: 2px 7px; border-radius: var(--radius-sm);
  font: 12px var(--sans); white-space: nowrap;
}
.leaflet-tooltip.nametag::before { display: none; }
.leaflet-tooltip.nametag b { font-weight: 600; }
.leaflet-tooltip.nametag b.unknown { font-family: var(--mono); font-weight: 500; color: var(--ink-2); }
.leaflet-tooltip.nametag span { color: var(--ink-3); font-size: 10px; margin-left: 6px; font-family: var(--mono); }
.leaflet-tooltip.nametag[data-state="stale"] { opacity: .62; }
.leaflet-tooltip.nametag[data-state="aging"] { opacity: .84; }
.leaflet-tooltip.placetag {
  background: transparent; border: 0; box-shadow: none; color: var(--ink-3);
  font: 700 10px var(--sans); letter-spacing: .12em; text-transform: uppercase;
}
.leaflet-tooltip.placetag::before { display: none; }

/* --- compose ---------------------------------------------------------------------------- */

.compose { margin-top: 10px; display: flex; flex-direction: column; gap: 3px; }
.compose-l {
  font-size: 10.5px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .07em;
  margin-top: 8px; font-weight: 700;
}
.compose input, .compose select, .compose textarea {
  background: var(--panel); color: var(--ink); border: 1px solid var(--line-2);
  border-radius: var(--radius-sm); padding: 7px 8px; font: inherit; font-size: 12.5px; width: 100%;
}
.compose input:focus, .compose select:focus, .compose textarea:focus {
  outline: none; border-color: var(--brand);
}
.compose textarea { resize: vertical; line-height: 1.45; }
.compose .act { margin-top: 10px; width: 100%; text-align: center; }
.compose-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; }
.compose-note { font-size: 11.5px; color: var(--warn); margin-top: 6px; }
.ask-note { color: var(--ink-3); font-size: 11px; line-height: 1.5; margin-top: 7px; }
.ask-row { margin: 14px 0 4px; }
.ask-more {
  margin-top: 8px; background: none; border: 0; padding: 0; color: var(--ink-2);
  font: inherit; font-size: 12px; cursor: pointer; text-decoration: underline;
  text-underline-offset: 3px;
}
.ask-more:hover { color: var(--ink); }

/* The composer's own styling is with the panes, near the top of this file — it is a pane now.
   What is left here is the FORM inside it, which is unchanged: composing is still an act rather
   than a view, and it still cannot be reached by a poll. What changed is where the act happens.
*/

/* --- assurance / briefings (unchanged in shape, restyled by the tokens) ------------------- */

/* Assurance and Briefings are single-surface pages and scroll as one. */
.wrap { flex: 1; min-height: 0; overflow-y: auto; padding: 20px 22px 60px; }
.group { border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 18px; background: var(--panel); box-shadow: var(--shadow); }
.group-head { padding: 13px 16px; border-bottom: 1px solid var(--line); display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.group-head h2 { margin: 0; font-size: 14.5px; }
.group-head .hash { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.group-head .counts { margin-left: auto; display: flex; gap: 6px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th {
  text-align: left; font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 700; padding: 9px 16px; border-bottom: 1px solid var(--line);
}
td { padding: 9px 16px; border-bottom: 1px solid var(--line); vertical-align: top; }
tr:last-child td { border-bottom: none; }
td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.dwell { font-family: var(--mono); font-size: 11px; color: var(--ink-3); }
.pill { font-size: 10px; padding: 1px 6px; border-radius: 999px; border: 1px solid var(--line-2); color: var(--ink-2); font-family: var(--mono); white-space: nowrap; }
.pill.done { color: var(--ok); border-color: var(--ok); background: var(--ok-wash); }
.pill.open { color: var(--warn); border-color: var(--warn); background: var(--warn-wash); }
.board .question { color: var(--ink-2); font-size: 13px; margin: 0; padding: 11px 16px 0; }
.board .unknown { font-family: var(--mono); font-weight: 500; color: var(--ink-2); }
.board tr.state-abandoned { background: var(--warn-wash); }
.board tr.state-waiting { background: var(--out-wash); }
.board tr.state-none { background: var(--panel-2); }
.footnote { color: var(--ink-3); font-size: 12px; max-width: 640px; line-height: 1.6; }
.footnote code { font-family: var(--mono); color: var(--ink-2); }
.scene { display: flex; gap: 8px; align-items: baseline; padding: 2px 0; }
.scene .id { font-family: var(--mono); font-size: 11px; color: var(--ink-2); min-width: 62px; }

/* --- empty / soon / gate ------------------------------------------------------------------ */

.empty { padding: 44px 20px; text-align: center; color: var(--ink-3); font-size: 12.5px; }
.empty.small { padding: 20px 16px; font-size: 12px; text-align: left; }
.soon { flex: 1; display: grid; place-items: center; padding: 40px; }
.soon-card { max-width: 460px; text-align: center; }
.soon-card h2 { font-size: 14px; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 14px; }
.soon-card p { color: var(--ink-2); }
.soon-card .muted { color: var(--ink-3); font-size: 13px; }
.cta { display: inline-block; margin-top: 18px; border: 1px solid var(--line-2); border-radius: var(--radius-sm); padding: 8px 16px; font-size: 13px; }
.cta:hover { border-color: var(--brand); color: var(--brand); }
body.gate { display: grid; place-items: center; background: var(--panel-2); }
.card { width: 340px; background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 28px; box-shadow: var(--shadow); }
/* The login card has the room, so it gets the FULL lockup — strapline and all, stacked above
   the form rather than sitting in a bar. This is the one screen in the console where somebody
   is looking at the product rather than through it. */
.mark.big { display: block; margin-bottom: 20px; padding: 0; }
.mark.big img { height: 46px; }
.mark.big span {
  display: block; border-left: 0; padding: 9px 0 0; align-self: auto;
}
.card .muted { color: var(--ink-3); font-size: 12px; line-height: 1.55; margin: 0 0 20px; }
.card label { display: block; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 6px; font-weight: 700; }
.card input {
  width: 100%; background: var(--panel); border: 1px solid var(--line-2);
  border-radius: var(--radius-sm); padding: 10px 12px; color: var(--ink); font: 14px var(--sans);
}
.card input:focus { outline: none; border-color: var(--brand); }
.card button {
  width: 100%; margin-top: 16px; background: var(--brand); color: var(--brand-ink); border: 0;
  border-radius: var(--radius-sm); padding: 11px; font: 700 14px var(--sans); cursor: pointer;
}
.card .error { color: var(--bad); font-size: 12px; margin: 12px 0 0; }


/* ===========================================================================================
   THE EXECUTION SCREEN — Brief 14
   =========================================================================================== */

/* --- the frame: a bar, then two fixed regions -------------------------------------------- */

.exbar {
  display: flex; align-items: center; gap: 10px; height: var(--wsbar-h);
  padding: 0 12px; background: var(--panel-2); border-bottom: 1px solid var(--line);
  flex: 0 0 auto;
}
.unitstrip { display: flex; align-items: center; gap: 6px; overflow-x: auto; flex: 1; }
.ex-right { display: flex; align-items: center; gap: 12px; font-size: 11.5px; color: var(--ink-3); font-family: var(--mono); }
.ex-poll { min-width: 44px; text-align: right; }

/* SELECTION IS A CHIP AND IT IS SINGLE. The count reads open-over-total: two things still to
   prove out of three jobs is the pair a controller is holding in their head anyway. */
.uchip {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  border: 1px solid var(--line-2); border-radius: 999px; padding: 4px 11px;
  background: var(--panel); font-size: 12.5px; color: var(--ink-2);
}
.uchip:hover { border-color: var(--brand); color: var(--brand); }
.uchip.on { border-color: var(--sel); background: var(--sel); color: var(--brand-ink); }
.ucount { font-family: var(--mono); font-size: 10.5px; opacity: .8; }

.exbody { flex: 1; display: flex; min-height: 0; }
/* 46/54, not a draggable divider. The right-hand side is a map and wants the wider half; the
   left is a column of text and reads worse the wider it gets. A drag handle here would be a
   control offering a choice that does not have a wrong answer to correct. */
.ops {
  flex: 0 0 46%; min-width: 0; overflow-y: auto; padding: 12px;
  border-right: 1px solid var(--line); background: var(--paper);
}
.geo { flex: 1; min-width: 0; position: relative; }
.geo #map { position: absolute; inset: 0; }

.ops-head { display: flex; align-items: baseline; gap: 10px; margin: 2px 2px 12px; }
.ops-head h2 { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin: 0; }

/* --- the task card ----------------------------------------------------------------------- */

.task {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 13px; margin-bottom: 10px; box-shadow: var(--shadow);
}
.t-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.t-seq {
  font-family: var(--mono); font-size: 11px; color: var(--ink-3);
  border: 1px solid var(--line-2); border-radius: 3px; padding: 0 5px;
}
.t-verb { font-size: 10.5px; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-3); font-weight: 700; }
.t-name { font-size: 14px; font-weight: 600; color: var(--ink); flex: 1; }
.t-head .statusword { font-size: 10.5px; letter-spacing: .06em; }
/* A task's own state word is a sibling of the label rather than a child of a [data-state] host,
   so it carries the colour itself — same three tones, same rule that every colour has a word. */
.statusword[data-state="good"] { color: var(--ok); }
.statusword[data-state="warn"] { color: var(--warn); }
.statusword[data-state="bad"] { color: var(--bad); }
.statusword[data-state="out"] { color: var(--out); }
.statusword[data-state="unknown"] { color: var(--ink-3); }

.t-where { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 7px 0 2px; font-size: 12px; color: var(--ink-2); }
.t-slot i { font-style: normal; font-size: 10px; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); margin-right: 5px; }
.t-slot.bad { color: var(--bad); }

/* A SENTENCE, NOT A COLOUR. An unscoped task and an uninterpretable role both get told to the
   operator in words, because both are things only the author can put right. */
.t-flag {
  margin: 8px 0 2px; padding: 7px 9px; font-size: 12px; line-height: 1.5;
  color: var(--warn); background: var(--warn-wash);
  border: 1px solid var(--warn); border-radius: var(--radius-sm);
}

/* --- the duty row: the smallest thing on this screen ------------------------------------- */

.duties { margin: 9px 0 4px; border-top: 1px solid var(--line); }
.duty { padding: 8px 0 7px; border-bottom: 1px solid var(--line); }
.duty:last-child { border-bottom: 0; padding-bottom: 2px; }
.d-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.d-label { font-size: 13px; color: var(--ink); flex: 1; }
.d-req { font-size: 10.5px; font-family: var(--mono); color: var(--ink-3); white-space: nowrap; }
/* Whose duty it is, when it is not whoever holds the work (W3). Same weight as the
   requirement beside it: both are the plan rather than the record. */
.d-holder { font-size: 10.5px; color: var(--ink-3); white-space: nowrap; }

/* A scope, typed. Monospace because it is an address and not a phrase — a dotted path reads
   wrong in a proportional font and a typo in one is invisible. */
.scopein { font-family: var(--mono); font-size: 11px; width: 15em; margin-right: 6px; }

/* THE COMPLETION PREDICATE (W6). Above the duties, because it is what the task is judged by and
   the duties are only the half of it somebody owes. */
.criteria { margin: 6px 0 2px; padding: 6px 8px; border-left: 2px solid var(--line); }
.c-head { font-size: 11px; color: var(--ink-2); margin-bottom: 4px; }
.crit { display: flex; gap: 6px; align-items: baseline; flex-wrap: wrap; padding: 2px 0; }
.c-text { font-size: 12px; }
.c-why { font-size: 10.5px; color: var(--ink-3); }

.d-was { margin-top: 4px; font-size: 11.5px; color: var(--ink-2); font-family: var(--mono); }
.d-was b { color: var(--ok); font-weight: 700; letter-spacing: .05em; }

/* PRESENT BUT UNCONFIRMED. Washed in the warn tone rather than the bad one: nothing has gone
   wrong, and a controller who reads this as a fault will stop trusting the distinction. */
.d-senses {
  margin-top: 5px; padding: 6px 8px; font-size: 11.5px; line-height: 1.5;
  color: var(--ink-2); background: var(--warn-wash);
  border-left: 2px solid var(--warn); border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
.d-refused { margin-top: 4px; font-size: 11px; color: var(--ink-3); font-style: italic; }
.d-act { display: flex; align-items: center; gap: 9px; margin-top: 7px; }
.d-act .cta { margin-top: 0; padding: 5px 12px; font-size: 12px; background: var(--panel); }
/* The one click the whole screen is built around gets the brand, once. Nothing else on this
   page is a filled button, so there is never a question about which control is the action. */
.duty[data-state="present-unconfirmed"] .cta {
  border-color: var(--brand); background: var(--brand); color: var(--brand-ink);
}
.d-act .cta[disabled] { opacity: .55; }

/* --- brief, resources, asks -------------------------------------------------------------- */

.t-brief { margin-top: 8px; }
.t-brief.none { font-size: 11.5px; color: var(--ink-3); font-style: italic; }
.t-screens {
  margin: 6px 0 0; padding: 8px 10px; background: var(--panel-2);
  border-radius: var(--radius-sm); font-size: 12.5px; line-height: 1.55; color: var(--ink-2);
}
.t-screens p { margin: 0 0 6px; }
.t-screens p:last-child { margin-bottom: 0; }
.t-res { margin-top: 8px; font-size: 12px; color: var(--ink-2); }
.t-res i, .cluster i { font-style: normal; font-size: 10px; letter-spacing: .07em; text-transform: uppercase; color: var(--ink-3); margin-right: 6px; }
.t-asks { margin-top: 8px; border-top: 1px dashed var(--line); padding-top: 6px; }
.t-asks .ask-row { font-size: 11.5px; color: var(--ink-2); margin-top: 3px; }
.t-now { margin: -4px 0 12px 4px; font-size: 11px; color: var(--ink-3); font-family: var(--mono); }

.chip.good { color: var(--ok); border-color: var(--ok); background: var(--ok-wash); }
.chip.out { color: var(--out); border-color: var(--out); background: var(--out-wash); }
.chip.warnchip { color: var(--warn); border-color: var(--warn); background: var(--warn-wash); }

/* --- help: the escalation stub's arriving half ------------------------------------------- */

.helpbox {
  background: var(--panel); border: 1px solid var(--out); border-radius: var(--radius);
  padding: 10px 12px; margin-bottom: 12px;
}
.helpbox h2 { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--out); margin: 0 0 7px; }
.help-row { font-size: 12.5px; color: var(--ink-2); padding: 3px 0; display: flex; align-items: baseline; gap: 7px; flex-wrap: wrap; }
.replybox { margin-top: 9px; border-top: 1px solid var(--line); padding-top: 9px; }
.replybox label { display: block; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 5px; }
.replybox textarea {
  width: 100%; box-sizing: border-box; font: 13px var(--sans); color: var(--ink);
  background: var(--panel); border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  padding: 7px 9px; resize: vertical;
}

/* --- shared small controls ---------------------------------------------------------------- */

.linky { font-size: 11.5px; color: var(--ink-2); text-decoration: underline; text-underline-offset: 2px; margin-left: 8px; }
.linky:hover { color: var(--brand); }
.linky.bad { color: var(--bad); }
.linky[disabled] { opacity: .35; text-decoration: none; }
.errbox {
  font-size: 12px; color: var(--bad); background: var(--bad-wash);
  border: 1px solid var(--bad); border-radius: var(--radius-sm); padding: 7px 9px; margin-bottom: 10px;
}
.okbox { font-size: 11.5px; color: var(--ok); font-family: var(--mono); margin-left: 10px; }

/* ===========================================================================================
   THE AUTHORING SCREEN — use cases 1 to 5
   =========================================================================================== */

.cfg { flex: 1; display: flex; flex-direction: column; min-height: 0; }
.cfg-tabs {
  display: flex; align-items: center; gap: 4px; height: var(--wsbar-h); padding: 0 12px;
  background: var(--panel-2); border-bottom: 1px solid var(--line); flex: 0 0 auto;
}
.cfg-tab {
  font-size: 12.5px; color: var(--ink-2); padding: 5px 12px; border-radius: var(--radius-sm);
  border: 1px solid transparent;
}
.cfg-tab:hover { background: var(--hover); }
.cfg-tab.on { background: var(--panel); border-color: var(--line-2); color: var(--ink); font-weight: 600; }
.cfg-body { flex: 1; overflow-y: auto; padding: 18px 20px 60px; }
.cfg-pane { max-width: 880px; }
.cfg-pane h2 { font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 8px; }
.cfg-pane h3 { font-size: 13px; color: var(--ink); margin: 26px 0 10px; }
.cfg-pane h4 { font-size: 12.5px; color: var(--ink); margin: 0 0 6px; }
/* The explanation of WHY a field exists sits with the field. A configure screen whose reasoning
   lives only in a document is a configure screen filled in by guesswork. */
.lede { font-size: 12.5px; line-height: 1.6; color: var(--ink-2); margin: 0 0 16px; max-width: 70ch; }

.cfg-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.cfg-table th {
  text-align: left; font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-3); padding: 6px 8px; border-bottom: 1px solid var(--line-2); font-weight: 700;
}
.cfg-table td { padding: 8px; border-bottom: 1px solid var(--line); color: var(--ink-2); vertical-align: top; }
.cfg-table b { color: var(--ink); font-weight: 600; }

.cfg-form { display: flex; flex-direction: column; gap: 12px; max-width: 620px; }
.f { display: block; }
.f > span { display: block; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 5px; font-weight: 700; }
.f > i { display: block; font-style: normal; font-size: 11.5px; line-height: 1.5; color: var(--ink-3); margin-top: 4px; }
.f.inline { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.f.inline > span { margin: 0; text-transform: none; letter-spacing: 0; font-size: 12.5px; color: var(--ink-2); font-weight: 400; }
.f.inline > i { flex-basis: 100%; margin: 0; }
.cfg-form input, .cfg-form select, .cfg-form textarea {
  width: 100%; box-sizing: border-box; font: 13px var(--sans); color: var(--ink);
  background: var(--panel); border: 1px solid var(--line-2); border-radius: var(--radius-sm);
  padding: 7px 9px;
}
.cfg-form input[type="checkbox"] { width: auto; }
.cfg-form input:focus, .cfg-form select:focus, .cfg-form textarea:focus { outline: 2px solid var(--brand-wash); border-color: var(--brand); }
.cfg-form fieldset { border: 1px solid var(--line); border-radius: var(--radius); padding: 12px 14px; }
.cfg-form legend { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3); font-weight: 700; padding: 0 6px; }
.cfg-form .small { color: var(--ink-3); line-height: 1.55; margin: 0 0 10px; max-width: 66ch; }
.noderow, .dodrow { display: flex; gap: 7px; margin-bottom: 7px; }
.cfg-act { display: flex; align-items: center; gap: 10px; }
.cfg-act .cta { margin-top: 0; }
.cfg-act select { width: auto; min-width: 180px; }

.bindcard, .queuecard {
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 14px; margin-bottom: 12px; max-width: 620px;
}
.members, .cluster { margin: 7px 0; font-size: 12.5px; }
.members .x { margin-left: 5px; color: var(--ink-3); font-size: 11px; }
.members .x:hover { color: var(--bad); }
.queuecard ol { margin: 0; padding-left: 22px; font-size: 12.5px; color: var(--ink-2); }
.queuecard li { padding: 4px 0; }
.queuecard li.on { color: var(--ink); font-weight: 600; }
.qact { float: right; }
