/* ═══════════════════════════════════════════════════════════════════════════
   Sizani — every style for the screens sizani-ui.js builds.

   This sheet and sizani-ui.js are ONE design and are owned together. The last round
   split them and they drifted into two different products: a bottom dock the script
   never emitted, a hold-to-send gesture it never implemented, an `is-*` state layer
   it never set, and a cancel window whose ten classes had no rules at all. So the
   rule here is written down: **the JS structure is the source of truth, this file's
   design intent is the source of taste.** Every selector below names a class
   sizani-ui.js actually emits. Nothing describes behaviour that does not exist.

   Sizani lives inside GoldChat's page, so this file also holds itself to five rules:

   · EVERY class is `sz-` prefixed. app.js owns .msg, .row, .btn-primary, .avatar,
     .toast and ~200 more; nothing here may collide with any of them.
   · NOTHING here is defined on :root. style.css's first rule is "ONE :root, tokens
     are defined once" — so Sizani's palette hangs off .sz-root / .sz-siren /
     .sz-sheet-host and inherits down. GoldChat's own cream screens never see a
     --sz- token, and Sizani never repaints a GoldChat surface.
   · Geometry comes from style.css's tokens (--r-md, --r-pill), each with a literal
     fallback so this sheet still renders correctly if it is ever loaded before
     style.css or on its own.
   · Anything that fights a house element rule (`input:focus`, `button`) is written
     with a `.sz-root` / `.sz-sheet-host` / `.sz-siren` ancestor, so it wins on
     specificity no matter which order the tags end up in. style.css resets button
     background and border to none, so every control in here — the tabs and Close
     included — states its own or it renders as bare text under the 44px floor.
   · Colour never carries meaning alone. Drill vs real is stated in words, drawn in a
     different hue AND fenced in hazard stripes — red/amber is the one pair a
     protanope cannot separate, and this is a screen you read at 2am.

   It looks like GoldChat, because it IS GoldChat: the everyday screens — panic,
   journey, nominees, the live incident — are drawn in the house cream and gold, on
   the house tokens (--bg, --panel, --gold-action, --r-md, --lift-1…) so a palette
   change in style.css carries through here untouched. Two surfaces stay dark, for
   the same reason GoldChat's own call screen is dark: the siren overlay and the
   ten-second cancel window are read at 2am by someone who was asleep four seconds
   ago, and a cream full-screen flash costs her the night vision she is about to
   need outdoors. Their darks are the house's own (#241f16 is #call-screen).
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══ scope + tokens ═══
   .sz-dead carries .sz-root as well, so it is inside this scope already. */
.sz-root,
.sz-sheet-host {
  /* surfaces — GoldChat's own, read from style.css; the literals are its values */
  --sz-bg:       var(--bg, #f6efe0);
  --sz-bg2:      var(--bg2, #faf6ec);
  --sz-panel:    var(--panel, #ffffff);
  --sz-panel2:   var(--panel2, #f4ecd9);
  --sz-line:     var(--line, #e8dbbe);
  --sz-hairline: var(--hairline, rgba(170, 135, 45, .18));
  --sz-lift-1:   var(--lift-1, 0 1px 2px rgba(60, 45, 10, .05));
  --sz-lift-3:   var(--lift-3, 0 1px 2px rgba(60, 45, 10, .05), 0 18px 48px rgba(60, 45, 10, .14));

  /* ink — the house measurements, against cream */
  --sz-ink:   var(--text, #3b3122);          /* 10.9:1 */
  /* one shade darker than the house --muted/--placeholder: those are measured for
     GoldChat's 15px chat copy and sit at 4.3:1 and 3.6:1 on cream, and Sizani's
     small print is read at 2am. These hold 5:1 on cream and on the white cards. */
  --sz-muted: #6f6350;                        /*  5.0:1 on cream */
  --sz-dim:   #6b5f48;                        /*  5.3:1 — the quietest ink allowed in here */

  /* brand. --gold-action is the ONE gold that carries white text at AA, so it is the
     gold for every fill and every gold word in here; the pale --accent-soft is a tint,
     never ink. */
  --sz-gold:      var(--gold-action, #8f6a12);
  --sz-gold-deep: var(--gold-hover, #7d5c0f);
  --sz-gold-soft: var(--accent-soft, #ecd085);
  --sz-gold-line: var(--bubble-line, rgba(168, 126, 24, .28));
  --sz-on-gold:   #ffffff;

  /* alarm. The slab and the siren edge keep their own red — it carries white at
     4.7:1 and it is the one colour in GoldChat that means "now". Red as TEXT on
     cream is the house --danger, which is tuned for exactly that. */
  --sz-red:      #d6382c;
  --sz-red-hot:  #ef4a3a;
  --sz-red-deep: #7d1c14;
  --sz-red-ink:  #3a0d09;
  --sz-red-glow: rgba(214, 56, 44, .34);
  --sz-red-text: var(--danger, #a33b49);
  --sz-red-soft: var(--danger-soft, rgba(163, 59, 73, .10));
  --sz-red-line: rgba(163, 59, 73, .42);

  /* drill. Never red, never near-red. */
  --sz-drill:        var(--accent-soft, #ecd085);
  --sz-drill-ink:    var(--text, #3b3122);
  --sz-drill-stripe: rgba(59, 49, 34, .16);

  --sz-ok:        var(--ok, #2c6e34);
  --sz-ok-soft:   rgba(44, 110, 52, .10);
  --sz-ok-line:   rgba(44, 110, 52, .38);
  --sz-warn:      #8a5a0a;                   /* 5.9:1 on cream */
  --sz-warn-ink:  #8a5a0a;
  --sz-warn-soft: rgba(176, 122, 18, .12);
  --sz-warn-line: rgba(176, 122, 18, .42);

  --sz-focus: var(--focus, 0 0 0 3px rgba(199, 154, 46, .32));

  --sz-pad: 16px;
  --sz-safe-b: env(safe-area-inset-bottom, 0px);
  --sz-safe-t: env(safe-area-inset-top, 0px);
}

/* The two alarm surfaces. .sz-cancelwin lives INSIDE .sz-root, so the dark set is
   restated on it and cascades to its card and its copy — and only there. */
.sz-siren,
.sz-cancelwin {
  --sz-bg:       #14100a;
  --sz-bg2:      #1d1810;
  --sz-panel:    #241f16;
  --sz-panel2:   #2e2718;
  --sz-line:     rgba(246, 239, 224, .14);
  --sz-hairline: rgba(246, 239, 224, .08);
  --sz-ink:   #f6efe0;   /* 16.4:1 */
  --sz-muted: #b2a98f;   /*  8.0:1 */
  /* Measured against the LIGHTEST ground this token can land on, not the darkest. Both
     alarm surfaces share this block, and the cancel card is --sz-red-ink #3a0d09 —
     lighter than --sz-bg #14100a and lighter than the #241f16 panel. The old #8b8269 held
     its stated ratio on the background alone: it was 4.43:1 on the cancel card, which is
     where .sz-pin-why actually renders ("Your PIN is required. Without it this alert keeps
     running." — the one line on that screen saying what happens if she does nothing, and
     the only ink there under 7:1). This value clears AA on all three: 4.9:1 on the card,
     4.8:1 on the panel, 5.5:1 on the background — and is still plainly quieter than
     --sz-muted, which is 7.2:1 on the card. */
  --sz-dim:   #948a70;   /*  4.9:1 on the cancel card — the lightest ground in here */
  --sz-gold:      #ecd085;
  --sz-gold-deep: #c79a2e;
  --sz-gold-soft: #ecd085;
  --sz-gold-line: rgba(236, 208, 133, .32);
  --sz-on-gold:   #1a1508;
  --sz-red-text:  #ff9c90;
  --sz-red-soft:  rgba(214, 56, 44, .10);
  --sz-red-line:  rgba(214, 56, 44, .45);
  --sz-drill-ink:    #1a1508;
  --sz-drill-stripe: rgba(26, 21, 8, .18);
  --sz-ok:        #6cc17f;
  --sz-ok-soft:   rgba(108, 193, 127, .10);
  --sz-ok-line:   rgba(108, 193, 127, .34);
  --sz-warn:      #e0a83c;
  --sz-warn-ink:  #f0c08a;
  --sz-warn-soft: rgba(224, 168, 60, .12);
  --sz-warn-line: rgba(224, 168, 60, .42);
  /* .sz-siren is NOT inside .sz-root, so nothing cascades down to it: every token it
     reads has to be stated here, or the declaration that uses it is dropped —
     which is a siren with no red edge and no safe-area padding. Complete set. */
  --sz-red:      #d6382c;
  --sz-red-hot:  #ef4a3a;
  --sz-red-deep: #7d1c14;
  --sz-red-ink:  #3a0d09;
  --sz-red-glow: rgba(214, 56, 44, .34);
  --sz-drill:    #ecd085;
  --sz-lift-1:   0 1px 2px rgba(0, 0, 0, .3);
  --sz-lift-3:   0 14px 40px rgba(0, 0, 0, .55);
  --sz-pad: 16px;
  --sz-safe-b: env(safe-area-inset-bottom, 0px);
  --sz-safe-t: env(safe-area-inset-top, 0px);
  /* style.css's gold glow all but disappears on black, so the alarm surfaces draw a
     dark separator ring inside a cream ring, which reads on any surface here. */
  --sz-focus: 0 0 0 2px var(--sz-bg), 0 0 0 5px var(--sz-ink);
}

/* style.css resets `* { box-sizing: border-box; margin: 0; padding: 0 }` and every width
   and padding below is written against that. Stated again inside Sizani's own scope so the
   claim at the top of this file — that it renders correctly on its own — is true rather
   than a dependency on which tag the page happens to load first. Without the border-box
   half, the PIN field's 100% width plus its own padding overflows the cancel card on a
   375px phone. Element selectors, not `*`, for the margin half: `.sz-root *` would outrank
   the class rules further down that set a deliberate margin. */
.sz-root, .sz-siren, .sz-sheet-host,
.sz-root *, .sz-siren *, .sz-sheet-host * { box-sizing: border-box; }
.sz-root h1, .sz-root h2, .sz-root h3, .sz-root p, .sz-root ol,
.sz-siren h1, .sz-siren h2, .sz-siren h3, .sz-siren p, .sz-siren ol,
.sz-sheet-host h1, .sz-sheet-host h2, .sz-sheet-host h3, .sz-sheet-host p {
  margin: 0; padding: 0;
}

/* ═══ the shell ═══
   z-index ladder, chosen against app.js's real numbers: .modal 30, .viewer 40,
   .overlay-top 45, .toast 60, .call-mini 80, #call-screen 90.
   · .sz-root      50   — above chat and its modals, below the toast and a live call.
   · .sz-cancelwin  5   — INSIDE .sz-root, above its panes. See the block below.
   · .sz-sheet-host 56  — Sizani's own dialogs, above its screens, below the toast.
   · .sz-siren    1000  — a live alarm outranks EVERYTHING, the call screen included.
     Someone is running to a person in the dark; a video call must not cover it. */
.sz-root {
  position: fixed; inset: 0; z-index: 50;
  display: flex; flex-direction: column;
  background: var(--sz-bg);
  color: var(--sz-ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: contain;
}
.sz-root[hidden], .sz-hidden { display: none !important; }

/* the top bar. The safe-area padding is not decoration: without it Close sits under
   the notch on every iPhone with one. */
.sz-top {
  flex: none; display: flex; align-items: center; gap: 10px;
  padding: calc(10px + var(--sz-safe-t)) 12px 10px;
  /* and no rule under it: .sb-header (style.css:260-263) is bare --bg2 and hands the
     hairline to the .sb-tabs strip below, which .sz-tabs already draws. Stating one here
     as well put two --line rules within 45px of each other with the same --bg2 on either
     side of the first — a seam GoldChat's own header does not have. */
  background: var(--sz-bg2);
}
/* .btn-ghost's shape, with a border so it keeps a 44px target on the cream */
.sz-root .sz-top-close {
  flex: none; min-height: 44px; min-width: 64px; padding: 10px 14px;
  border: 1px solid var(--sz-line); border-radius: var(--r-md, 12px);
  background: var(--sz-panel); color: var(--sz-ink);
  font: inherit; font-size: 15px; font-weight: 700; cursor: pointer;
  transition: background .15s, border-color .15s;
}
.sz-root .sz-top-close:hover { background: var(--sz-panel2); }
.sz-top-title { flex: 1; min-width: 0; font-size: 17px; font-weight: 800; letter-spacing: -0.02em; }
.sz-top-note {
  flex: none; font-size: 12px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  color: var(--sz-dim);
}

/* primary navigation. style.css resets `button` to no background and no border, so
   without these rules the four tabs render as bare 19px-tall text. */
/* the same strip as Chats · Calls · Moments · Requests (.sb-tabs): equal columns,
   muted words, a gold underline on the one that is open. */
.sz-tabs {
  flex: none; display: flex; gap: 2px;
  padding: 0 8px; background: var(--sz-bg2);
  border-bottom: 1px solid var(--sz-line);
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.sz-tabs::-webkit-scrollbar { display: none; }
.sz-root .sz-tab {
  flex: 1 1 0; min-height: 44px; padding: 12px 4px;
  border: 0; border-bottom: 2.5px solid transparent; border-radius: 0;
  background: transparent; color: var(--sz-muted);
  font: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer; white-space: nowrap;
  transition: color .15s, border-color .15s;
}
.sz-root .sz-tab:hover { color: var(--sz-ink); }
.sz-root .sz-tab.sz-tab-on {
  color: var(--gold-deep, #a87e18); border-bottom-color: var(--accent, #c79a2e); font-weight: 800;
}

/* The one scrolling surface. body{overflow:hidden} in style.css means every screen
   in this app scrolls itself or not at all. */
.sz-body {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  padding: 14px var(--sz-pad) 18px;
}
.sz-pane { display: flex; flex-direction: column; gap: 14px; }

.sz-h3 { font-size: 15.5px; font-weight: 800; letter-spacing: -0.01em; color: var(--sz-ink); }
.sz-row { display: flex; flex-wrap: wrap; gap: 8px; }
.sz-row > * { flex: 1 1 auto; }

/* ═══ buttons ═══
   44px is the floor everywhere in Sizani; 60 on anything pressed under stress.
   `.sz-root` ancestors so `button{background:none;border:none}` cannot undercut. */
.sz-root .sz-btn,
.sz-sheet-host .sz-btn,
.sz-siren .sz-btn {
  /* style.css:133 paints EVERY [aria-busy="true"] control's label `transparent
     !important` and draws the house spinner as an ::after at `position:absolute;
     inset:0; margin:auto`. Nothing in here can outrank an !important, so the label
     going transparent is the house behaviour and fine — but the ring has to land ON
     the button. Without a positioned button its containing block is .sz-root (fixed,
     z-index 50) and the spinner renders in the DEAD CENTRE OF THE SCREEN while the
     control reads as an empty slab. sizani-ui.js sets aria-busy on five controls
     (640 PIN submit, 1226 panic, 1702 arm journey, 1879 add nominee, 2444 the siren's
     "I'm going"); .sz-panic was the only one already relative. */
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 13px 18px;
  border: 1px solid var(--sz-line); border-radius: var(--r-md, 12px);
  background: var(--sz-panel); color: var(--sz-ink);
  font: inherit; font-size: 15px; font-weight: 700; letter-spacing: -0.01em;
  cursor: pointer; text-align: center;
  transition: background .15s, border-color .15s, transform .06s;
}
/* …and the ring has to be visible on the fill it is drawn over. The house spinner is
   white (style.css:137): right on the gold and the red, invisible on the white ones —
   .sz-btn's own surface since the restyle, and the siren's white "I'm going". These are
   0-3-0 against the bare attribute rule's 0-1-0. */
.sz-root .sz-btn[aria-busy="true"]::after,
.sz-sheet-host .sz-btn[aria-busy="true"]::after {
  border-color: rgba(59, 49, 34, .22); border-top-color: var(--sz-ink);
}
.sz-root .sz-btn-primary[aria-busy="true"]::after,
.sz-root .sz-btn-danger[aria-busy="true"]::after,
.sz-sheet-host .sz-btn-primary[aria-busy="true"]::after,
.sz-sheet-host .sz-btn-danger[aria-busy="true"]::after {
  border-color: rgba(255, 255, 255, .35); border-top-color: #fff;
}
.sz-siren .sz-siren-go[aria-busy="true"]::after {
  border-color: rgba(20, 16, 10, .22); border-top-color: #14100a;
}
.sz-root .sz-btn:hover, .sz-sheet-host .sz-btn:hover, .sz-siren .sz-btn:hover {
  background: var(--sz-panel2);
}
.sz-root .sz-btn:active, .sz-sheet-host .sz-btn:active { transform: translateY(1px); }
.sz-root .sz-btn:disabled, .sz-sheet-host .sz-btn:disabled, .sz-siren .sz-btn:disabled {
  opacity: .45; cursor: default; transform: none;
}
.sz-root .sz-btn-lg, .sz-sheet-host .sz-btn-lg { min-height: 60px; font-size: 17px; width: 100%; }

/* .btn-primary: the AA gold with white on it; on the dark surfaces the pale gold
   with dark ink, via the scoped tokens. */
.sz-root .sz-btn-primary, .sz-sheet-host .sz-btn-primary, .sz-siren .sz-btn-primary {
  background: var(--sz-gold); color: var(--sz-on-gold); border-color: transparent; font-weight: 700;
}
/* The .sz-siren arm is not optional. .sz-btn-primary IS emitted on the alarm overlay —
   makeFallback('siren') builds the GBV Command Centre number as one (sizani-ui.js:927) —
   and with only two arms here the rule that matches it on hover is `.sz-siren .sz-btn:hover`
   (0-3-0) above, which repaints the slab --sz-panel2 (#2e2718) while this rule's
   `color: var(--sz-on-gold)` (#1a1508 in the dark scope) and its transparent border stay
   put: 1.23:1, a near-black label on a near-black slab one shade off the #241f16 card
   behind it. On a phone with no airtime and no data that button is the only control on
   the screen that still does anything. --sz-gold-deep is #c79a2e on the dark surfaces and
   carries #1a1508 at 7.0:1 — the same darken-on-hover step .btn-primary takes in the house. */
.sz-root .sz-btn-primary:hover, .sz-sheet-host .sz-btn-primary:hover,
.sz-siren .sz-btn-primary:hover { background: var(--sz-gold-deep); }
.sz-root .sz-btn-danger, .sz-sheet-host .sz-btn-danger {
  background: var(--sz-red); color: #fff; border-color: transparent; font-weight: 800;
}
/* Every text button in the house gets DARKER under a pointer — .btn-primary to
   --gold-hover, .btn-danger from #a33b49 to #8d3140 (style.css:132) — because the label
   has to survive the hover. This one reached for --sz-red-hot, the siren-edge red: white
   on #ef4a3a is 3.68:1, so "Cancel this alert" and "Open the cancel window" drop under AA
   at 17px/800 the moment a cursor lands, and on iOS the first tap latches it. #b62f24 is
   the same red a third of a stop down — 6.14:1 with white, the size of step the house
   takes. --sz-red-hot is left alone: the siren edge and the map pin need it bright on black. */
.sz-root .sz-btn-danger:hover, .sz-sheet-host .sz-btn-danger:hover { background: #b62f24; }
/* rung 3's opener. Deliberately NOT the red slab — it opens a conversation, it does
   not publish, and a control that looks like the final act invites a thumb. */
.sz-root .sz-btn-danger-quiet {
  background: transparent; color: var(--sz-red-text); border-color: var(--sz-red-line);
}
.sz-root .sz-btn-danger-quiet:hover { background: var(--sz-red-soft); }
.sz-root .sz-btn-quiet, .sz-sheet-host .sz-btn-quiet, .sz-siren .sz-btn-quiet {
  background: transparent; border-color: var(--sz-hairline); color: var(--sz-muted); font-weight: 600;
}
.sz-root .sz-btn-quiet:hover, .sz-sheet-host .sz-btn-quiet:hover {
  background: var(--sz-panel2); color: var(--sz-ink);
}

/* Visible focus on every interactive control, on every surface in here. */
.sz-root :focus-visible,
.sz-sheet-host :focus-visible,
.sz-siren :focus-visible {
  outline: none; box-shadow: var(--sz-focus); border-radius: var(--r-sm, 8px);
}
.sz-root .sz-btn:focus-visible,
.sz-sheet-host .sz-btn:focus-visible,
.sz-siren .sz-btn:focus-visible { border-radius: var(--r-md, 12px); }

/* ═══ fields ═══
   `input:focus` in style.css is 0-1-1 and would otherwise beat a bare `.sz-input`
   whichever order the sheets load in, so every state here carries an ancestor. */
.sz-field { display: flex; flex-direction: column; gap: 6px; text-align: left; }
.sz-label { font-size: 12px; font-weight: 800; color: var(--sz-muted); letter-spacing: .02em; }
.sz-root .sz-input, .sz-sheet-host .sz-input {
  width: 100%; font: inherit; font-size: 16px; /* 16px: anything smaller zooms iOS Safari */
  color: var(--sz-ink); background: var(--sz-panel);
  border: 1px solid var(--sz-line); border-radius: var(--r-md, 12px);
  padding: 14px; min-height: 52px; outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.sz-root .sz-input::placeholder, .sz-sheet-host .sz-input::placeholder { color: var(--sz-dim); }
.sz-root .sz-input:hover, .sz-sheet-host .sz-input:hover { border-color: #d9c79c; }
.sz-root .sz-input:focus, .sz-sheet-host .sz-input:focus {
  border-color: var(--accent, #c79a2e); box-shadow: var(--sz-focus);
}
.sz-root .sz-input:disabled { opacity: .5; cursor: not-allowed; }

/* ═══ the PIN control ═══
   One control, four callers: the ten-second cancel, stand-down, the journey check-in
   and the journey cancel. It is thumbed once, in the dark, sometimes inside ten
   seconds — so it is the largest field in the product and it never drops below the
   16px iOS no-zoom floor. The cancel window's PIN is this same control, because that
   window now renders inside .sz-root where these selectors reach it. */
.sz-pin { display: flex; flex-direction: column; gap: 8px; }
.sz-pin-label { font-size: 12px; font-weight: 800; color: var(--sz-muted); letter-spacing: .02em; }
.sz-root .sz-pin-input, .sz-sheet-host .sz-pin-input {
  width: 100%; font: inherit;
  text-align: center; font-size: 30px; font-weight: 800;
  letter-spacing: 14px; padding: 14px 14px 14px 28px; /* offset the trailing letter-space */
  min-height: 64px; font-variant-numeric: tabular-nums;
  color: var(--sz-ink); background: var(--sz-panel);
  border: 1px solid var(--sz-line); border-radius: var(--r-md, 12px); outline: none;
  transition: border-color .15s, box-shadow .15s;
}
.sz-root .sz-pin-input::placeholder, .sz-sheet-host .sz-pin-input::placeholder {
  color: var(--sz-dim); letter-spacing: 6px; font-size: 20px; font-weight: 700;
}
.sz-root .sz-pin-input:focus, .sz-sheet-host .sz-pin-input:focus {
  border-color: var(--accent, #c79a2e); box-shadow: var(--sz-focus);
}
/* inside the dark cancel window the field stays a white field with dark digits:
   the scoped cream ink would otherwise be typed on white. */
.sz-cancelwin .sz-pin-input { background: #fff; color: #3b3122; border-color: rgba(246, 239, 224, .3); }
.sz-cancelwin .sz-pin-input::placeholder { color: #8b7c62; }
.sz-pin-why { font-size: 12.5px; line-height: 1.5; color: var(--sz-dim); }

.sz-err {
  font-size: 13.5px; font-weight: 700; color: var(--sz-red-text); line-height: 1.5;
  background: var(--sz-red-soft); border: 1px solid var(--sz-red-line);
  border-radius: var(--r-md, 12px); padding: 11px 12px;
}
.sz-err-big { font-size: 15px; line-height: 1.55; }
/* too_many_attempts: a live countdown, never a dead gate — and when the refusal came
   without a number, a sentence that says so rather than a guessed minute. */
.sz-lock {
  font-size: 13.5px; font-weight: 700; line-height: 1.5; color: var(--sz-warn-ink);
  background: var(--sz-warn-soft); border: 1px solid var(--sz-warn-line);
  border-radius: var(--r-md, 12px); padding: 11px 12px;
  font-variant-numeric: tabular-nums;
}

/* ═══ notes, tags, banners ═══ */
.sz-note {
  font-size: 13.5px; line-height: 1.55; color: var(--sz-muted);
  background: var(--sz-panel2); border: 1px solid var(--sz-hairline);
  border-radius: var(--r-md, 12px); padding: 12px 13px;
}
.sz-note-quiet {
  background: transparent; border-color: transparent; padding: 2px 2px;
  font-size: 12.5px; color: var(--sz-dim);
}
.sz-note-warn {
  color: var(--sz-warn-ink); border-color: var(--sz-warn-line);
  background: var(--sz-warn-soft);
}
.sz-done {
  font-size: 14px; line-height: 1.55; color: var(--sz-ink);
  background: var(--sz-ok-soft); border: 1px solid var(--sz-ok-line);
  border-radius: var(--r-md, 12px); padding: 12px 13px;
}

/* .sz-shown is the transition hook sizani-ui.js adds alongside removing the inline
   display; it deliberately carries no rule, so a pane appears without waiting on this
   sheet. Never give it `display`: the hidden attribute and the inline style are the
   two mechanisms that must not be able to disagree with each other. */

/* the drill chip. Never red, never near-red, always the word. */
.sz-tag {
  display: inline-flex; align-items: center; align-self: flex-start; gap: 6px;
  font-size: 11.5px; font-weight: 900; letter-spacing: .1em; text-transform: uppercase;
  border-radius: var(--r-sm, 8px); padding: 6px 10px;
  color: var(--sz-drill-ink); background: var(--sz-drill);
}
.sz-tag-drill {
  background:
    repeating-linear-gradient(135deg, var(--sz-drill-stripe) 0 9px, transparent 9px 18px),
    var(--sz-drill);
}
/* the transport did not say. Not a drill, not confirmed real — and drawn as neither. */
.sz-tag-unsure {
  color: var(--sz-ink); background: transparent;
  border: 1px dashed var(--sz-line);
}

.sz-banner {
  display: flex; flex-direction: column; gap: 4px;
  padding: 13px 14px; border-radius: var(--r-md, 12px);
  border: 1px solid var(--sz-line); background: var(--sz-panel);
  box-shadow: var(--sz-lift-1);
}
.sz-banner-title { font-size: 15px; font-weight: 800; line-height: 1.3; }
.sz-banner-sub { font-size: 13px; line-height: 1.5; color: var(--sz-muted); }
.sz-banner-live {
  border-color: var(--sz-red-line);
  background: linear-gradient(180deg, var(--sz-red-soft), transparent 70%), var(--sz-panel);
}
.sz-banner-live .sz-banner-title { color: var(--sz-red-text); }
.sz-banner-drill {
  border: 2px dashed var(--sz-gold-line);
  background:
    repeating-linear-gradient(135deg, rgba(199, 154, 46, .10) 0 11px, transparent 11px 22px),
    var(--sz-panel);
}
/* NOT --sz-drill. In the everyday scope that token is --accent-soft (#ecd085) — the pale
   tint .sz-tag carries dark ink ON, and the rule this file states for itself at the top:
   the pale gold is a tint, never ink. As text on this banner's white --sz-panel it is
   1.51:1 (1.38:1 over the hazard stripe), so the one sentence on the Panic tab that says
   the running alert is practice is not on the screen — quieter than the red live banner
   beside it, which is exactly backwards. It read ~10:1 before the restyle only because
   --sz-panel was #241f16; the token did not move, the surface under it did. --sz-gold-deep
   is 6.16:1 on the panel and 5.65:1 over the stripe, is still nowhere near the red a drill
   may not borrow, and turns back into #c79a2e by itself if this banner is ever drawn on
   the dark surfaces. The word DRILL, the dashed edge and the stripes all stay, so colour
   is still not carrying the meaning alone. */
.sz-banner-drill .sz-banner-title { color: var(--sz-gold-deep); }

/* ═══ 1. COVERAGE — stated before she presses, never after ═══
   Three states, all of them an answer. There is deliberately no fourth "loading"
   look: a spinner where the armed-response answer belongs reads as a promise, so
   the unknown state says the words "not confirmed" instead. The guard below makes
   that structural — a spinner dropped in here later still will not render. */
.sz-cov {
  display: flex; flex-direction: column; gap: 4px;
  padding: 13px 14px; border-radius: var(--r-md, 12px);
  border: 1px solid var(--sz-line); background: var(--sz-panel);
  border-left-width: 5px; box-shadow: var(--sz-lift-1);
}
.sz-cov .sz-spinner, .sz-cov [aria-busy="true"] { display: none !important; }
.sz-cov-line { font-size: 15px; font-weight: 800; letter-spacing: -0.01em; }
.sz-cov-sub { font-size: 12.5px; line-height: 1.5; color: var(--sz-muted); }
.sz-cov-ring {
  font-size: 12.5px; line-height: 1.5; color: var(--sz-dim);
  padding-top: 6px; margin-top: 2px; border-top: 1px solid var(--sz-hairline);
}
/* The wash paints ON the card, not instead of it. --sz-muted and --sz-dim are measured
   against bare cream and against the white panels; replacing the panel with a 10–12% wash
   puts them on a ground darker than either, and .sz-cov-sub lands at 4.48:1 there — the one
   ink in this file under AA for body copy, on the card that answers "is anybody coming".
   Layering the wash over --sz-panel restores the measured ground (line 5.40:1, sub 5.11:1,
   ring 5.45:1 / off: 5.18, 5.14, 5.48) and makes all three coverage states read as the same
   white card, which is how .sz-cov-unknown already draws itself. */
.sz-cov-on { border-left-color: var(--sz-ok); background: linear-gradient(var(--sz-ok-soft), var(--sz-ok-soft)), var(--sz-panel); }
.sz-cov-on .sz-cov-line { color: var(--sz-ok); }
.sz-cov-off { border-left-color: var(--sz-warn); background: linear-gradient(var(--sz-warn-soft), var(--sz-warn-soft)), var(--sz-panel); }
.sz-cov-off .sz-cov-line { color: var(--sz-warn-ink); }
.sz-cov-unknown { border-style: dashed; border-left-color: var(--sz-dim); }
.sz-cov-unknown .sz-cov-line { color: var(--sz-ink); }

/* ═══ THE PANIC CONTROL ═══
   Bottom-docked, outside the scrolling pane, so a thumb reaches it on a 320px-wide
   phone without a second hand — and inset from every edge, because a control flush
   to the bezel is one a palm finds in a pocket.

   It is a PLAIN TAP. That was settled: rungs 0 and 1 are cheap and fire on any
   press, and the false-alarm defence is the ten-second PIN-gated cancel window
   below, not a hold. A hold costs her seconds at the moment she has none, so there
   is no ring, no rising veil, no --sz-hold and no `touch-action: none` here — that
   last one blocked scrolling on a 184px target sitting mid-page. */
.sz-panic-dock {
  flex: none; display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 12px var(--sz-pad) calc(16px + var(--sz-safe-b));
  /* --bg2 under a --line hairline, which is how #composer and #recorder (style.css:490,
     658) draw the bottom dock on every other screen in this app. The gradient that stood
     here was a scrim for the dark design; the restyle re-coloured it to the cream without
     noticing that this dock is a `flex: none` sibling of .sz-body, never an overlay —
     nothing scrolls under it, so transparent → .92-cream → --bg all composited to the same
     #f6efe0 and it painted nothing. That left the panic screen with a --bg2 band at the
     top and, at the bottom, a hairline with the body colour on both sides of it. */
  background: var(--sz-bg2);
  border-top: 1px solid var(--sz-line);
}
.sz-panic-dock .sz-row { width: 100%; justify-content: center; }
.sz-panic-wrap { position: relative; display: flex; align-items: center; justify-content: center; }

.sz-root .sz-panic {
  position: relative;
  width: min(184px, 52vw); height: min(184px, 52vw);
  min-width: 148px; min-height: 148px;
  border-radius: 50%; border: 0; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  padding: 10px;
  background: radial-gradient(120% 120% at 50% 12%, var(--sz-red-hot), var(--sz-red) 46%, var(--sz-red-deep) 100%);
  color: #fff; font: inherit;
  box-shadow: 0 0 0 6px rgba(214, 56, 44, .14), var(--sz-lift-3);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;   /* kills the 300ms delay; does NOT block a scroll */
  user-select: none; -webkit-user-select: none;
}
/* the word. 27px, and it is `sz-panic-word` because that is the class the script
   emits — styling `sz-panic-label` here is what rendered it at the button's
   inherited 16px for a whole round. */
.sz-panic-word {
  font-size: 27px; font-weight: 900; letter-spacing: .02em; line-height: 1.05;
  text-align: center; text-shadow: 0 1px 2px rgba(0, 0, 0, .35);
}
.sz-panic-sub {
  font-size: 12px; font-weight: 700; line-height: 1.3; text-align: center;
  color: rgba(255, 255, 255, .88); letter-spacing: .02em;
}
.sz-root .sz-panic:hover { filter: brightness(1.05); }
.sz-root .sz-panic:active { transform: scale(.985); }
.sz-root .sz-panic:focus-visible { box-shadow: var(--sz-focus), var(--sz-lift-3); }
.sz-root .sz-panic:disabled { opacity: .6; cursor: default; }

/* ═══ 2. THE CANCEL WINDOW — ten seconds, and it needs her PIN ═══
   The highest-stakes surface in the product and the only one with a deadline running
   against it, so four things are structural rather than left to chance:

     · it renders INSIDE .sz-root, where the --sz-* tokens resolve — outside that
       scope every colour below falls back to nothing;
     · it is absolutely positioned above the panes, because .sz-root is fixed,
       opaque and z-index 50, and a static block on document.body paints underneath
       it — invisible for exactly the ten seconds it exists;
     · its PIN field is the shared .sz-pin-input, so it inherits the same 30px /
       16px-plus sizing as every other and iOS never zooms it;
     · there is no plain "Cancel" button anywhere in this block. The PIN field IS the
       cancel control, because the person holding the phone may not be her. */
.sz-cancelwin {
  position: absolute; inset: 0; z-index: 5;
  display: flex; align-items: flex-end; justify-content: center;
  padding: calc(12px + var(--sz-safe-t)) 12px calc(12px + var(--sz-safe-b));
  background: rgba(8, 6, 3, .86);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  overflow-y: auto; overscroll-behavior: contain;
  /* `color` is not a custom property. The dark block above swaps TOKENS; .sz-root has
     already resolved `color: var(--sz-ink)` against its own cream --sz-ink, and that
     computed #3b3122 inherits straight through this element — redefining --sz-ink on a
     descendant cannot re-run a declaration that lives on an ancestor. So every node in
     here that does not name a colour is painted in the cream scope's ink on the #3a0d09
     card: 1.33:1. There is exactly one such node and it is the headline — .sz-cw-title,
     "Alert raised", then "This alert is live" / "The drill is live" when the ten seconds
     run out; on a real alert cwTag is hidden, so it is the card's only heading. .sz-siren
     states this line in its own block and .sz-sheet-host in its; this surface is INSIDE
     .sz-root, so it needs it more, not less — and a line added here later cannot inherit
     the wrong ink in silence. */
  color: var(--sz-ink);
}
.sz-cw-card {
  width: 100%; max-width: 480px; margin: auto 0 0;
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px; border-radius: var(--r-lg, 18px);
  background: var(--sz-red-ink); border: 1px solid rgba(214, 56, 44, .45);
  box-shadow: 0 -14px 44px rgba(0, 0, 0, .55);
}
.sz-cw-title { font-size: 19px; font-weight: 900; letter-spacing: -0.02em; }
.sz-cw-mismatch {
  font-size: 13.5px; font-weight: 700; line-height: 1.5; color: var(--sz-warn-ink);
  background: rgba(224, 168, 60, .12); border: 1px solid rgba(224, 168, 60, .42);
  border-radius: var(--r-md, 12px); padding: 11px 12px;
}
.sz-cw-what { display: flex; flex-direction: column; gap: 7px; }
.sz-cw-line { font-size: 13.5px; line-height: 1.5; color: rgba(246, 239, 224, .84); }

/* the countdown is the biggest thing on the screen, because it is the only thing
   with a deadline. Tabular figures so 10 → 9 does not shift the layout. */
.sz-cw-count { display: flex; align-items: baseline; gap: 12px; }
.sz-cw-num {
  flex: none; font-size: 52px; font-weight: 900; line-height: 1;
  font-variant-numeric: tabular-nums; color: #fff; min-width: 76px;
}
.sz-cw-unit { flex: 1; min-width: 0; font-size: 14px; font-weight: 700; color: rgba(246, 239, 224, .82); line-height: 1.35; }
.sz-cw-count-done .sz-cw-num { color: var(--sz-warn); }

/* a second reading of the same number, for anyone who cannot read 52px of digits
   fast. The width is set inline by sizani-ui.js on each tick. */
.sz-cw-bar { height: 6px; border-radius: 3px; background: rgba(255, 255, 255, .16); overflow: hidden; }
.sz-cw-bar-fill { display: block; height: 100%; width: 100%; background: #fff; border-radius: 3px; }
.sz-cw-count-done + .sz-cw-bar .sz-cw-bar-fill { background: var(--sz-warn); }

.sz-cw-pin { display: block; }
.sz-cw-foot { display: flex; flex-wrap: wrap; gap: 8px; }
.sz-cw-foot > * { flex: 1 1 auto; }
/* the drill window: same layout, unmistakably not an emergency */
.sz-cancelwin .sz-tag-drill { align-self: flex-start; }

/* ═══ 3. RUNG 3 — a deliberate act, and never on the panic path ═══
   Written as CSS rather than left to good intentions: if a publish control is ever
   dropped into the panic dock, the cancel window or the siren, it does not render. */
.sz-panic-dock .sz-publish,
.sz-cancelwin .sz-publish,
.sz-siren .sz-publish { display: none !important; }

.sz-publish {
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px; border-radius: var(--r-lg, 18px);
  background: var(--sz-panel);
  border: 2px solid var(--sz-red-line); box-shadow: var(--sz-lift-1);
}
/* :not(.sz-note-warn), because this rule is 0-2-0 and .sz-note-warn is 0-1-0 — so as written
   the publish box repaints the one note in it that is not boilerplate ("this alert was
   cancelled as a false alarm, so it cannot be published" — the reason the button is gone) in
   the same red wash, with the same ink, as the two notes above it. The exclusion keeps this
   rule off that element; :not() carries its argument's specificity, so this is still 0-3-0
   and still beats a bare .sz-note inside the box. */
.sz-publish .sz-note:not(.sz-note-warn) { background: var(--sz-red-soft); border-color: var(--sz-red-line); color: var(--sz-ink); }

/* ═══ the outbox — silent, always on, and honest ═══
   Small, quiet, factual. It never says "live" while it is holding fixes, and it is
   never a spinner: "3 fixes waiting" is the whole design. The number comes from
   Sizani.outbox.state().pending at paint time, so this line is never drawn from a
   counter that a reload has quietly reset to zero. */
.sz-root .sz-outbox {
  flex: none; margin: 0 var(--sz-pad) 8px; align-self: flex-start;
  font-size: 12.5px; font-weight: 600; line-height: 1.45; color: var(--sz-muted);
  background: var(--sz-panel2); border: 1px solid var(--sz-hairline);
  border-radius: var(--r-md, 12px); padding: 8px 12px;
}
/* The `.sz-root` ancestor is load-bearing on BOTH halves. The base rule above carries it,
   which makes it 0-2-0; written bare these modifiers are 0-1-0 and lose to it outright, so
   "3 fixes waiting" has been drawing in the same muted ink and the same hairline as the
   idle line and the one signal that says her fixes have not left this phone never appeared.
   Same ancestor, same weight, and source order decides — which is what these two were
   always written to rely on. (Waiting then reads --sz-warn-ink on --sz-panel2, 5.03:1.) */
.sz-root .sz-outbox-waiting { color: var(--sz-warn-ink); border-color: var(--sz-warn-line); }
.sz-root .sz-outbox-offline { color: var(--sz-dim); }

/* ═══ journeys — the dead-man switch ═══ */
.sz-journey { display: flex; flex-direction: column; gap: 12px; }
.sz-jcard {
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px; border-radius: var(--r-lg, 18px);
  background: var(--sz-panel); border: 1px solid var(--sz-gold-line); box-shadow: var(--sz-lift-1);
}
.sz-jlabel { font-size: 16px; font-weight: 800; }
.sz-jclock { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 10px; }
.sz-jclock-num {
  font-size: 40px; font-weight: 900; line-height: 1; font-variant-numeric: tabular-nums;
  color: var(--sz-gold);
}
.sz-jclock-sub { font-size: 13px; font-weight: 700; color: var(--sz-muted); line-height: 1.4; }
.sz-jclock-over .sz-jclock-num { color: var(--sz-red-text); }
.sz-jform { display: flex; flex-direction: column; gap: 12px; }
/* minute presets */
.sz-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.sz-root .sz-chip {
  min-height: 44px; padding: 10px 16px; border-radius: var(--r-pill, 999px);
  background: var(--sz-panel); border: 1px solid var(--sz-line);
  color: var(--sz-ink); font: inherit; font-size: 14px; font-weight: 700; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.sz-root .sz-chip:hover { border-color: var(--sz-gold-line); background: var(--sz-panel2); }
.sz-root .sz-chip.sz-chip-on {
  background: var(--sz-gold); border-color: transparent; color: var(--sz-on-gold); font-weight: 800;
}

/* ═══ nominees — five seats, and the empty ones are drawn as seats ═══ */
.sz-seats { display: flex; flex-direction: column; gap: 8px; }
.sz-addbox { display: flex; flex-direction: column; gap: 12px; }
.sz-seat {
  display: flex; flex-direction: column; gap: 4px;
  padding: 13px 14px; border-radius: var(--r-md, 12px);
  background: var(--sz-panel); border: 1px solid var(--sz-line);
  border-left-width: 5px; border-left-color: var(--sz-line); box-shadow: var(--sz-lift-1);
}
.sz-seat-name { font-size: 15px; font-weight: 800; }
.sz-seat-phone { font-size: 12.5px; color: var(--sz-muted); font-variant-numeric: tabular-nums; }
.sz-seat-status { font-size: 13px; line-height: 1.45; color: var(--sz-ink); }
.sz-seat-why { font-size: 12.5px; line-height: 1.5; color: var(--sz-dim); }
.sz-seat-live { border-left-color: var(--sz-ok); }
.sz-seat-live .sz-seat-status { color: var(--sz-ok); }
.sz-seat-cold { border-left-color: var(--sz-warn); }
.sz-seat-cold .sz-seat-status { color: var(--sz-warn-ink); }
.sz-seat-unreachable { border-left-color: var(--sz-dim); }
.sz-seat-unreachable .sz-seat-status { color: var(--sz-muted); }
.sz-seat-empty {
  border-style: dashed; border-left-style: dashed; background: transparent; box-shadow: none;
  border-color: var(--sz-line); border-left-color: var(--sz-line);
}
.sz-seat-empty .sz-seat-name { color: var(--sz-dim); font-weight: 700; }
.sz-seat-empty .sz-seat-status { color: var(--sz-dim); }
.sz-root .sz-seat-remove { align-self: flex-start; margin-top: 6px; min-height: 44px; }

/* ═══ the live incident ═══ */
.sz-inc { display: flex; flex-direction: column; gap: 14px; }
.sz-inc-head { display: flex; flex-direction: column; gap: 3px; }
.sz-inc-status { font-size: 19px; font-weight: 900; letter-spacing: -0.02em; }
.sz-inc-when { font-size: 12.5px; color: var(--sz-muted); }
.sz-inc-what {
  display: flex; flex-direction: column; gap: 8px;
  padding: 13px 14px; border-radius: var(--r-md, 12px);
  background: var(--sz-panel); border: 1px solid var(--sz-line); box-shadow: var(--sz-lift-1);
}
.sz-inc-line { font-size: 13.5px; line-height: 1.55; color: var(--sz-ink); }

.sz-standdown {
  display: flex; flex-direction: column; gap: 12px;
  padding: 16px; border-radius: var(--r-lg, 18px);
  background: var(--sz-panel); border: 1px solid var(--sz-red-line); box-shadow: var(--sz-lift-1);
}
.sz-tally, .sz-trail {
  display: flex; flex-direction: column; gap: 8px;
  padding: 14px; border-radius: var(--r-md, 12px);
  background: var(--sz-panel); border: 1px solid var(--sz-line); box-shadow: var(--sz-lift-1);
}
.sz-tally-line { font-size: 13.5px; line-height: 1.5; color: var(--sz-muted); }
.sz-tally-big { font-size: 17px; font-weight: 800; color: var(--sz-ink); line-height: 1.35; }
.sz-fixes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.sz-fix {
  display: flex; align-items: baseline; gap: 10px;
  padding: 8px 0; border-bottom: 1px solid var(--sz-hairline);
}
.sz-fix:last-child { border-bottom: 0; }
.sz-fix-time { flex: none; font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; min-width: 48px; }
.sz-fix-meta { flex: 1; min-width: 0; font-size: 12.5px; color: var(--sz-muted); font-variant-numeric: tabular-nums; }

/* ═══ 5. THE SIREN OVERLAY ═══
   Operating condition: outdoors or in bed, at night, read by someone who was asleep
   4 seconds ago and is holding the phone at arm's length. So: one screen, one
   action, type sized to be read without glasses, and no chrome to hunt through.
   It never shows video, never names a suspect, never offers a way to share — the
   guards at the bottom of this block make that structural, not a promise. */
.sz-siren {
  position: fixed; inset: 0; z-index: 1000;
  display: flex; flex-direction: column; gap: 10px;
  padding: calc(18px + var(--sz-safe-t)) 18px calc(18px + var(--sz-safe-b));
  background: linear-gradient(180deg, #3a0d09 0%, #1c0705 58%, #140403 100%);
  color: var(--sz-ink);   /* 14.8:1 on the lightest band above */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  overflow-y: auto; overscroll-behavior: contain;
  -webkit-font-smoothing: antialiased;
}
/* the edge is the "loud". It is a border, not a flash: a full-screen strobe at 2am
   costs the reader the night vision she is about to need outdoors. Fixed rather than
   absolute so it does not scroll away with the content. */
.sz-siren::before {
  content: ''; position: fixed; inset: 0; pointer-events: none; z-index: 1;
  border: 7px solid var(--sz-red-hot);
  animation: sz-siren-edge 1.15s steps(1, end) infinite;
}
@keyframes sz-siren-edge { 50% { border-color: var(--sz-red-deep); } }
.sz-siren > * { position: relative; z-index: 2; }

.sz-siren-tag { flex: none; }
.sz-siren-title {
  flex: none; margin: 0;
  font-size: clamp(21px, 6.2vw, 30px); font-weight: 800; line-height: 1.2; letter-spacing: -0.02em;
}
/* the distance is the single most useful number on this screen: can I get there? */
.sz-siren-dist {
  flex: none;
  font-size: clamp(40px, 14vw, 76px); font-weight: 900; line-height: 1;
  letter-spacing: -0.03em; font-variant-numeric: tabular-nums;
}
.sz-siren-where { flex: none; font-size: 15px; color: rgba(246, 239, 224, .86); line-height: 1.45; }
.sz-siren-map {
  flex: none; height: clamp(120px, 26vh, 220px);
  border-radius: var(--r-md, 12px); overflow: hidden;
  background: #0d0a06; border: 1px solid rgba(246, 239, 224, .18);
  display: flex; align-items: center; justify-content: center;
}
.sz-siren-map .sz-note {
  background: transparent; border: 0; text-align: center; color: var(--sz-muted);
}
/* the drawn map. No tiles, no CDN — the rings are at a stated scale and this phone's
   own position is drawn against them. */
.sz-map { display: block; width: 100%; height: 100%; }
.sz-map-ring { fill: none; stroke: rgba(246, 239, 224, .26); stroke-width: 1; }
.sz-map-cross { stroke: rgba(246, 239, 224, .12); stroke-width: 1; }
.sz-map-n, .sz-map-scale { fill: rgba(246, 239, 224, .62); font-size: 10px; font-weight: 700; }
.sz-map-scene { fill: var(--sz-red-hot); stroke: #fff; stroke-width: 2; }
.sz-map-me { fill: var(--sz-gold); stroke: #14100a; stroke-width: 1.5; }
.sz-map-leg { stroke: var(--sz-gold); stroke-width: 1.5; stroke-dasharray: 4 3; }

/* Fixed copy. Word for word, and never abbreviated to fit — it is the difference
   between a witness and a second casualty, so it gets its own framed block and a
   size you can read at arm's length. */
.sz-siren .sz-siren-instruction {
  flex: none;
  font-size: clamp(19px, 5.2vw, 24px); font-weight: 800; line-height: 1.5;
  color: #fff;
  background: rgba(255, 255, 255, .07);
  border-left: 5px solid var(--sz-red-hot);
  border-radius: var(--r-md, 12px);
  padding: 14px 16px; margin: 4px 0;
}

/* exactly one action, and it stays under the thumb however far the screen scrolls */
.sz-siren-action {
  flex: none; position: sticky; bottom: 0; z-index: 3;
  padding: 10px 0 4px;
  background: linear-gradient(transparent, rgba(20, 4, 3, .92) 34%, rgba(20, 4, 3, .98));
}
.sz-siren .sz-siren-go {
  width: 100%; min-height: 76px; border: 0; border-radius: var(--r-md, 12px);
  background: #fff; color: #14100a;
  font: inherit; font-size: 25px; font-weight: 900; letter-spacing: -0.01em;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 34px rgba(0, 0, 0, .5);
  transition: transform .06s, background .15s;
}
.sz-siren .sz-siren-go:hover { background: #f2ece0; }
.sz-siren .sz-siren-go:active { transform: translateY(1px); }
.sz-siren .sz-siren-go:focus-visible { box-shadow: 0 0 0 3px #14100a, 0 0 0 7px #fff; }
/* after the ack: the screen states what her tap did — including the honest case
   where it was recorded but does not hold off the loud alert. */
.sz-siren-result { flex: none; display: flex; flex-direction: column; gap: 10px; }
.sz-siren-said { font-size: 19px; font-weight: 900; }
.sz-siren-result .sz-note { background: rgba(255, 255, 255, .07); border-color: rgba(246, 239, 224, .18); color: var(--sz-ink); }
.sz-siren .sz-siren-foot {
  flex: none; margin-top: auto; padding-top: 8px;
  font-size: 12.5px; line-height: 1.5; color: rgba(246, 239, 224, .62);
}

/* The three things this screen must never carry. Written as CSS so a later edit
   cannot quietly add them back: no video of anybody, no share affordance, no
   identification of a person. */
.sz-siren video,
.sz-siren .sz-share,
.sz-siren .sz-suspect { display: none !important; }

/* the drill siren — same layout, and unmistakable at a glance: amber, hazard-fenced,
   and the word DRILL is the first thing in the reading order. */
.sz-siren-drill { background: linear-gradient(180deg, #2b2416 0%, #191509 62%, #14100a 100%); }
.sz-siren-drill::before {
  border-color: var(--sz-drill);
  border-image: repeating-linear-gradient(135deg, var(--sz-drill) 0 14px, #14100a 14px 28px) 7;
  animation: none;
}
.sz-siren-drill .sz-siren-title, .sz-siren-drill .sz-siren-dist { color: var(--sz-drill); }
.sz-siren.sz-siren-drill .sz-siren-instruction { border-left-color: var(--sz-drill); }
.sz-siren-drill .sz-siren-action { background: linear-gradient(transparent, rgba(25, 21, 9, .92) 34%, rgba(25, 21, 9, .98)); }
.sz-siren-drill .sz-siren-go { background: var(--sz-drill); color: var(--sz-drill-ink); }
.sz-siren-drill .sz-siren-go:hover { background: #f4dda2; }
.sz-siren-drill .sz-map-scene { fill: var(--sz-drill); }

/* the transport did not carry the answer yet. Neither dressed as an emergency nor
   dismissed as practice — the incident lookup decides within the second, and until
   it does this screen is honest about not knowing. */
.sz-siren-unsure { background: linear-gradient(180deg, #241f16 0%, #191509 62%, #14100a 100%); }
.sz-siren-unsure::before { border-color: rgba(246, 239, 224, .34); animation: none; }
.sz-siren.sz-siren-unsure .sz-siren-instruction { border-left-color: var(--sz-ink); }
.sz-siren-unsure .sz-siren-action { background: linear-gradient(transparent, rgba(25, 21, 9, .92) 34%, rgba(25, 21, 9, .98)); }

/* ═══ the confirm sheet ═══
   Its own DOM, not GoldChat's dialog. .sz-sheet-host is the backdrop the script
   builds; .sz-sheet is the card inside it. */
.sz-sheet-host {
  position: fixed; inset: 0; z-index: 56;
  display: flex; align-items: flex-end; justify-content: center;
  background: rgba(46, 36, 12, .38);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
  color: var(--sz-ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  animation: sz-sheet-fade .14s ease-out;
}
.sz-sheet {
  width: 100%; max-width: 480px; max-height: 88vh; overflow-y: auto;
  background: var(--sz-panel); border: 1px solid var(--sz-line); border-bottom: 0;
  border-radius: var(--r-lg, 18px) var(--r-lg, 18px) 0 0;
  padding: 20px var(--sz-pad) calc(20px + var(--sz-safe-b));
  display: flex; flex-direction: column; gap: 12px;
  box-shadow: var(--sz-lift-3);
  animation: sz-sheet-rise .16s ease-out;
}
/* .modal fades and .modal-card rises, at .14s and .16s ease-out (style.css:675, 682).
   This sheet took the backdrop colour, the blur and the --lift-3 from that recipe and
   left the motion behind, so every dialog in GoldChat eases in and the one that asks
   "start a drill?" arrives as a hard cut. Same timings, same curve, sz- names of its
   own: `fade` and `rise` belong to style.css and this file does not reach into another
   sheet's namespace. Nothing here is signalled BY the motion, and style.css:853 zeroes
   the duration under reduced motion, so that reader loses nothing. */
@keyframes sz-sheet-fade { from { opacity: 0; } }
@keyframes sz-sheet-rise { from { transform: translateY(8px); opacity: .6; } }
.sz-sheet-danger { border-color: var(--sz-red-line); }
.sz-sheet-title { font-size: 18px; font-weight: 800; letter-spacing: -0.02em; margin: 0; }
.sz-sheet-line { font-size: 14px; line-height: 1.55; color: var(--sz-muted); }
.sz-sheet-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; }
.sz-sheet-actions > * { flex: 1 1 44%; }
/* the confirming half is never the default and never focused; it is simply labelled
   with the verb it performs. */
.sz-sheet-danger .sz-btn-confirm { font-weight: 800; }

/* ═══ the module did not load ═══
   Not a styling problem — a safety screen that merely looks broken is worse than
   one that says so. */
.sz-dead {
  justify-content: center; gap: 12px; padding: 24px var(--sz-pad) calc(24px + var(--sz-safe-b));
}
.sz-dead-title { font-size: 20px; font-weight: 900; line-height: 1.25; color: var(--sz-red-text); }
.sz-dead-body { font-size: 15px; line-height: 1.6; color: var(--sz-ink); }

/* ═══ small phones and short screens ═══
   The panic control keeps its 148px floor; everything above it gives way instead. */
@media (max-width: 360px) {
  .sz-root { --sz-pad: 13px; }
  .sz-cw-num { font-size: 44px; min-width: 62px; }
  .sz-panic-word { font-size: 24px; }
}
@media (max-height: 640px) {
  .sz-panic-dock { padding-top: 8px; gap: 6px; }
  .sz-root .sz-panic { width: 152px; height: 152px; }
  .sz-siren-map { height: 100px; }
  .sz-siren .sz-siren-instruction { margin: 2px 0; padding: 12px 14px; }
}
/* landscape: the instruction and the one action must both survive a 380px-tall window */
@media (orientation: landscape) and (max-height: 520px) {
  .sz-siren { padding-top: calc(10px + var(--sz-safe-t)); padding-bottom: calc(10px + var(--sz-safe-b)); }
  .sz-siren-map { display: none; }
  .sz-siren-dist { font-size: clamp(32px, 9vh, 52px); }
  .sz-siren .sz-siren-go { min-height: 62px; font-size: 21px; }
  .sz-panic-dock { flex-direction: row; justify-content: center; align-items: center; }
  .sz-root .sz-panic { width: 132px; height: 132px; min-width: 132px; min-height: 132px; }
  .sz-panic-word { font-size: 21px; }
}

/* ═══ accessibility ═══
   style.css already neutralises animation globally under reduced motion, but this is
   stated here too so the siren is not relying on someone else's rule: without the
   blink it keeps a solid, saturated 7px edge — the loudness is in the contrast and
   the type size, never in the motion. */
@media (prefers-reduced-motion: reduce) {
  /* `animation: none` belongs on every variant. The border COLOUR does not. This rule is
     0-1-1 — the same weight as .sz-siren-unsure::before and .sz-siren-drill::before — and
     it sits later in the file, so written bare it repaints the not-confirmed siren's cream
     edge in --sz-red-hot and dresses an unconfirmed alert as a confirmed emergency for
     everyone who has Reduce Motion on. (The drill survives only because its border-image
     happens to paint over the colour; that is luck, not design.) The plain siren already
     declares this colour in its own rule, so the :not() copy stays purely as the
     belt-and-braces this block was written to be. */
  .sz-siren::before { animation: none; }
  .sz-siren:not(.sz-siren-drill):not(.sz-siren-unsure)::before { border-color: var(--sz-red-hot); }
  .sz-root *, .sz-siren *, .sz-sheet-host * { transition-duration: .001ms !important; }
}
@media (prefers-contrast: more) {
  .sz-root, .sz-sheet-host {
    /* --sz-dim has to actually MOVE here. #6b5f48 is the base value at the top of this
       file copied verbatim, so the bump was a no-op and every surface that reads it —
       .sz-top-note, .sz-cov-ring, .sz-pin-why, .sz-note-quiet, .sz-seat-why,
       .sz-outbox-offline and both placeholders — answered Increase Contrast with no
       change at all, while --sz-muted moved from 5.13:1 to 6.75:1 and overtook it. The
       dark arm two lines down does move its own (#8b8269 → #c8bfa5), which is what made
       this no-op invisible. #594e3a is 7.12:1 on cream and 8.15:1 on the white cards, and
       keeps --sz-dim the same one step past --sz-muted that the base pair has at rest. */
    --sz-muted: #5d5140; --sz-dim: #594e3a; --sz-line: #c9b98f;
    --sz-hairline: rgba(170, 135, 45, .4);
  }
  .sz-siren, .sz-cancelwin {
    --sz-muted: #ded5bd; --sz-dim: #c8bfa5; --sz-line: rgba(246, 239, 224, .34);
    --sz-hairline: rgba(246, 239, 224, .22);
  }
  /* The .sz-siren ancestor is load-bearing, not decoration: the rule this overrides is
     `.sz-siren .sz-siren-instruction` (0-2-0), so written bare this is 0-1-0 and loses
     whatever the source order is — a media query adds no specificity, and the bump
     silently never applied. Every other rule in this file that touches the instruction
     (the reduced-motion block, the max-height:640px block) already carries the ancestor. */
  .sz-siren .sz-siren-instruction { background: rgba(255, 255, 255, .14); }
}
/* A pointer-coarse device must not lose a press to a text selection drag. */
@media (pointer: coarse) {
  .sz-panic, .sz-siren-go { -webkit-user-select: none; user-select: none; }
}
