/* ============================================================
   THREAT SWEEP, IT eBulletins homepage widget
   Extracted from Threat-Sweep-Game/threat-sweep.html 2026-09-08.
   Loaded by index.html only, so the other 80 pages do not pay
   for it and styles.css needs no cache-buster bump.
   Fixed 380 x 460. All selectors and custom properties are
   namespaced ts- so nothing here can collide with styles.css.
   Brand: #1f4891 primary | Inter | dark SOC console skin
   The standalone preview page body rule is deliberately omitted.
   ============================================================ */

/* --- widget --- */
.ts-widget {
  --ts-w: 380px;
  --ts-h: 460px;
  --ts-cell: 34px;
  --ts-gap: 2px;

  --ts-bg:        #0d1424;
  --ts-panel:     #131c30;
  --ts-sunken:    #0a1120;
  --ts-tile:      #263757;
  --ts-tile-hi:   #33486f;
  --ts-tile-down: #1a2740;
  --ts-line:      #223052;
  --ts-brand:     #1f4891;
  --ts-accent:    #4d8bf0;
  --ts-text:      #e6edf7;
  --ts-muted:     #8798b5;
  --ts-danger:    #ef4444;
  --ts-flag:      #f59e0b;
  --ts-ok:        #10b981;

  --ts-n1: #4d8bf0;
  --ts-n2: #10b981;
  --ts-n3: #ef4444;
  --ts-n4: #8b5cf6;
  --ts-n5: #f59e0b;
  --ts-n6: #14b8a6;
  --ts-n7: #e6edf7;
  --ts-n8: #8798b5;

  --ts-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  position: relative;
  box-sizing: border-box;
  width: var(--ts-w);
  height: var(--ts-h);
  padding: 11px 12px 10px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 8px;
  background:
    radial-gradient(120% 90% at 50% 0%, #16203a 0%, var(--ts-bg) 62%);
  color: var(--ts-text);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 13px;
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  box-shadow: 0 8px 32px rgba(13, 20, 36, .28);
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.ts-widget *, .ts-widget *::before, .ts-widget *::after { box-sizing: border-box; }

/* An author display rule (.ts-form is display:flex) outranks the UA's
   [hidden]{display:none}, so el.hidden = true would set the attribute
   without actually hiding anything. */
.ts-widget [hidden] { display: none !important; }

/* --- header --- */
.ts-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  height: 34px;
  flex: none;
}
.ts-brandmark { display: flex; align-items: center; gap: 7px; min-width: 0; }
.ts-shield { width: 18px; height: 18px; flex: none; color: var(--ts-accent); }
.ts-titles { min-width: 0; }
.ts-title {
  margin: 0;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  line-height: 1.1;
  white-space: nowrap;
}
.ts-kicker {
  font-size: 8.5px;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ts-muted);
  white-space: nowrap;
}

.ts-mode {
  flex: none;
  padding: 4px 8px;
  border: 1px solid var(--ts-line);
  border-radius: 4px;
  background: var(--ts-panel);
  color: var(--ts-muted);
  font: inherit;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.ts-mode:hover { color: var(--ts-accent); border-color: var(--ts-accent); }
.ts-mode:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 1px; }

/* --- status bar --- */
.ts-status {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 30px;
  margin-top: 7px;
  padding: 0 4px;
  flex: none;
  border: 1px solid var(--ts-line);
  border-radius: 5px;
  background: var(--ts-sunken);
}
.ts-readout {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 0 5px;
  font-family: var(--ts-mono);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
}
.ts-readout svg { width: 13px; height: 13px; flex: none; }
.ts-readout--threats { color: var(--ts-danger); }
.ts-readout--timer   { color: var(--ts-accent); }
.ts-spacer { flex: 1 1 auto; }

.ts-btn {
  display: grid;
  place-items: center;
  width: 26px;
  height: 22px;
  flex: none;
  padding: 0;
  border: 1px solid var(--ts-line);
  border-radius: 4px;
  background: var(--ts-tile);
  color: var(--ts-muted);
  cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.ts-btn svg { width: 13px; height: 13px; }
.ts-btn:hover { background: var(--ts-tile-hi); color: var(--ts-text); }
.ts-btn:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 1px; }
.ts-btn[aria-pressed="true"] {
  background: rgba(245, 158, 11, .16);
  border-color: var(--ts-flag);
  color: var(--ts-flag);
}

/* --- board --- */
.ts-boardwrap {
  flex: 1 1 auto;
  display: grid;
  place-items: center;
  min-height: 0;
  margin: 7px 0;
}
.ts-board {
  display: grid;
  gap: var(--ts-gap);
  padding: 4px;
  border: 1px solid var(--ts-line);
  border-radius: 6px;
  background: var(--ts-sunken);
}

.ts-cell {
  width: var(--ts-cell);
  height: var(--ts-cell);
  padding: 0;
  display: grid;
  place-items: center;
  border: none;
  border-radius: 3px;
  background: var(--ts-tile);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .06);
  color: var(--ts-text);
  font-family: var(--ts-mono);
  font-size: 15px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: background .1s;
}
.ts-cell:hover:not(.ts-open) { background: var(--ts-tile-hi); }
.ts-cell:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: -2px; }
.ts-cell:active:not(.ts-open) { background: var(--ts-tile-down); }
.ts-cell svg { width: 17px; height: 17px; pointer-events: none; }

.ts-cell.ts-open {
  background: rgba(255, 255, 255, .022);
  box-shadow: none;
  cursor: default;
}
.ts-cell.ts-open.ts-num { cursor: pointer; }
.ts-cell.ts-flagged { color: var(--ts-flag); }
.ts-cell.ts-mine {
  background: rgba(239, 68, 68, .16);
  color: var(--ts-danger);
}
.ts-cell.ts-boom {
  background: var(--ts-danger);
  color: #fff;
}
.ts-cell.ts-wrong { color: var(--ts-muted); }
.ts-cell.ts-wrong svg { opacity: .45; }
.ts-cell.ts-contained {
  background: rgba(16, 185, 129, .16);
  color: var(--ts-ok);
}

.ts-n-1 { color: var(--ts-n1); } .ts-n-2 { color: var(--ts-n2); }
.ts-n-3 { color: var(--ts-n3); } .ts-n-4 { color: var(--ts-n4); }
.ts-n-5 { color: var(--ts-n5); } .ts-n-6 { color: var(--ts-n6); }
.ts-n-7 { color: var(--ts-n7); } .ts-n-8 { color: var(--ts-n8); }

/* --- ticker --- */
.ts-ticker {
  height: 15px;
  flex: none;
  padding: 0 2px;
  overflow: hidden;
  color: var(--ts-muted);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .01em;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.ts-ticker b { color: var(--ts-text); font-weight: 600; }

/* --- end overlay --- */
.ts-over {
  position: absolute;
  inset: 0;
  z-index: 5;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 13px;
  /* Light scrim only. The report itself is a solid card, so the grid
     stays plainly readable above and below it rather than competing
     with the copy. */
  background: rgba(9, 15, 28, .46);
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity .22s ease;
}
.ts-over.ts-show { opacity: 1; visibility: visible; }

.ts-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 13px 18px 11px;
  border: 1px solid #2c3d63;
  border-radius: 8px;
  background: rgba(10, 16, 30, .965);
  box-shadow: 0 12px 34px rgba(0, 0, 0, .5);
}

.ts-quizcard { gap: 7px; }
.ts-qthreat {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  color: var(--ts-danger);
  text-wrap: balance;
}
.ts-qtext {
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--ts-text);
  text-wrap: pretty;
}
.ts-options { display: grid; gap: 5px; }
.ts-option {
  padding: 7px 10px;
  border: 1px solid var(--ts-line);
  border-radius: 5px;
  background: rgba(255, 255, 255, .035);
  color: var(--ts-text);
  font: inherit;
  font-size: 10.5px;
  line-height: 1.35;
  text-align: left;
  text-wrap: pretty;
  cursor: pointer;
  transition: background .14s, border-color .14s;
}
.ts-option:hover:not(:disabled) {
  background: rgba(77, 139, 240, .14);
  border-color: var(--ts-accent);
}
.ts-option:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 1px; }
.ts-option:disabled { cursor: default; }
.ts-option.ts-right {
  border-color: var(--ts-ok);
  background: rgba(16, 185, 129, .16);
  color: var(--ts-ok);
}
.ts-option.ts-wrongpick {
  border-color: var(--ts-danger);
  background: rgba(239, 68, 68, .16);
  color: var(--ts-danger);
}
.ts-qfoot {
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: .05em;
  text-transform: uppercase;
  color: var(--ts-muted);
  text-wrap: pretty;
}
.ts-qfoot.ts-good-t { color: var(--ts-ok); }
.ts-qfoot.ts-bad-t  { color: var(--ts-danger); }

.ts-verdict {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ts-muted);
}
.ts-headline {
  margin: 0;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -.01em;
  line-height: 1.15;
  text-wrap: balance;
}
.ts-headline.ts-bad  { color: var(--ts-danger); }
.ts-headline.ts-good { color: var(--ts-ok); }

.ts-detail {
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--ts-muted);
  text-wrap: pretty;   /* keeps a lone word off the last line */
}
.ts-detail b { color: var(--ts-text); font-weight: 600; }

.ts-stats {
  display: flex;
  justify-content: center;
  gap: 22px;
  padding: 6px 0;
  border-top: 1px solid var(--ts-line);
  border-bottom: 1px solid var(--ts-line);
}
.ts-stat-v {
  font-family: var(--ts-mono);
  font-size: 17px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.ts-stat-l {
  white-space: nowrap;
  font-size: 8px;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ts-muted);
}

/* --- soft newsletter prompt --- */
.ts-capture { display: grid; gap: 6px; }
.ts-capture-copy {
  font-size: 10.5px;
  line-height: 1.45;
  color: var(--ts-muted);
  text-wrap: pretty;
}
.ts-form { display: flex; gap: 5px; }
.ts-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 30px;
  padding: 0 9px;
  border: 1px solid var(--ts-line);
  border-radius: 4px;
  background: var(--ts-sunken);
  color: var(--ts-text);
  font: inherit;
  font-size: 11.5px;
}
.ts-input::placeholder { color: #5d6f8f; }
.ts-input:focus { outline: none; border-color: var(--ts-accent); }

.ts-cta {
  flex: none;
  height: 30px;
  min-width: 92px;      /* holds steady between Subscribe and Sending */
  padding: 0 12px;
  border: none;
  border-radius: 4px;
  background: var(--ts-brand);
  color: #fff;
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .15s;
}
.ts-cta:hover:not(:disabled) { background: #2a5aae; }
.ts-cta:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 2px; }
.ts-cta:disabled { opacity: .6; cursor: default; }

.ts-capture-copy.ts-err { color: var(--ts-danger); }
.ts-input.ts-invalid { border-color: var(--ts-danger); }
.ts-input:disabled { opacity: .6; cursor: default; }

.ts-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
}
.ts-divider { width: 1px; height: 10px; background: var(--ts-line); }

.ts-link {
  padding: 4px 2px;
  border: none;
  background: none;
  color: var(--ts-accent);
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
}
.ts-link:hover { color: var(--ts-text); }
.ts-link:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 1px; }

/* --- peek: pull the report away so the whole grid is legible --- */
.ts-restore {
  position: absolute;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%);
  padding: 7px 14px;
  border: 1px solid var(--ts-line);
  border-radius: 5px;
  background: rgba(10, 16, 30, .95);
  color: var(--ts-accent);
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .09em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transition: opacity .18s ease;
}
.ts-restore:hover { color: var(--ts-text); border-color: var(--ts-accent); }
.ts-restore:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 2px; }

.ts-over.ts-peek { background: transparent; }
.ts-over.ts-peek .ts-card { opacity: 0; visibility: hidden; }
.ts-over.ts-peek .ts-restore { opacity: 1; visibility: visible; }
.ts-card { transition: opacity .18s ease; }

.ts-sr {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

@media (prefers-reduced-motion: reduce) {
  .ts-widget *, .ts-widget *::before { transition-duration: .01ms !important; }
}

/* ============================================================
   HOMEPAGE PLACEMENT + MOBILE FIT
   Added on embed 2026-09-08. Not part of the standalone game.
   Kept in this file rather than styles.css so styles.css keeps
   its ?v=3 and the other 80 pages are untouched. Because this
   file only loads on the homepage, these overrides cannot leak
   onto article pages, whose sidebars still hide on mobile.
   ============================================================ */

/* Two levels on purpose. .ts-fit is the LAYOUT box and is sized to the scaled
   dimensions; .ts-widget keeps its real 380 x 460 and is transformed down to
   fill it. Putting the transform on .ts-fit itself does not work: a transform
   leaves the layout box at full size, so a 380px box stayed 380px inside a
   272px grid track and pushed the page sideways. Sizing the box and scaling
   the contents means the track only ever sees the scaled width. */
.ts-fit {
  --ts-s: 1;
  width:  calc(var(--ts-w, 380px) * var(--ts-s));
  height: calc(var(--ts-h, 460px) * var(--ts-s));
  margin-inline: auto;
}

.ts-fit > .ts-widget {
  transform: scale(var(--ts-s));   /* --ts-s inherits from .ts-fit */
  transform-origin: top left;
}

/* styles.css hides .hero__sidebar below 1024px. The game is meant to show on
   phones, so that is reverted here. .hero__grid is already one column at this
   width, so the widget stacks under the cover story. */
@media (max-width: 1024px) {
  /* SPECIFICITY TRAP, found in testing: styles.css collapses the hero to one
     column here with a plain `.hero__grid` rule, but
     `.hero__grid:has(.hero__sidebar)` is more specific and wins even inside
     this media query. The 380px column therefore survived to 320px and pushed
     the page into a sideways scroll. The collapse has to be restated at
     matching specificity. */
  .hero__grid:has(.hero__sidebar) { grid-template-columns: minmax(0, 1fr); }
  .hero__grid .hero__sidebar { display: flex; }
}

/* The widget is a fixed 380px block whose copy was measured at that width, and
   its ticker is white-space: nowrap. Reflowing it would truncate the ticker and
   reintroduce runts, so it is scaled instead. Each step is the largest scale
   that still fits 380px inside the viewport minus the container's 48px of
   padding, so the widget never overflows and never triggers a sideways scroll. */
/* Each step's scaled width (380 x scale) is checked against the narrowest
   viewport in its band minus 48px, and every band clears it by at least 3px.
   An earlier ladder overflowed by 0.2px at a 329px viewport, which is why the
   headroom is now explicit rather than assumed. Unscaled above 435px, where
   the widget clears the container by 8px. */
@media (max-width: 435px) { .ts-fit { --ts-s: .94; } }  /* 409-435, +3.8px */
@media (max-width: 408px) { .ts-fit { --ts-s: .89; } }  /* 390-408, +3.8px */
@media (max-width: 389px) { .ts-fit { --ts-s: .85; } }  /* 374-389, +3.0px */
@media (max-width: 373px) { .ts-fit { --ts-s: .81; } }  /* 359-373, +3.2px */
@media (max-width: 358px) { .ts-fit { --ts-s: .73; } }  /* 329-358, +3.6px */
@media (max-width: 328px) { .ts-fit { --ts-s: .67; } }  /* to 320,  +17.4px */

/* ============================================================
   BRIEFING GATE + TERMINAL BUTTON + SCANLINE ARM
   Added 2026-09-09.

   Why it exists: mechanically the game never needed a start
   button. Threats are seeded after the first tap, with that cell
   and its eight neighbours excluded, so the opening move is
   always safe and the board was live on load. The problem was
   discoverability: on a news homepage a dark 9x9 grid reads as
   decoration, and one line of 10px text was the only thing
   saying otherwise.

   It also gives the difficulty chip a purpose. It sits in the
   header, where almost nobody would find it; the briefing puts
   the choice in front of the player before the run starts.

   Shown once per page load. Reset and Play again go straight to
   a live board, because a gate on every replay is friction with
   nothing to buy.
   ============================================================ */

.ts-brief {
  position: absolute;
  inset: 0;
  z-index: 6;                    /* above .ts-over (5) on load */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 8px;
  padding: 20px;
  text-align: center;
  /* Heavier than the report's scrim: this one is meant to hide the
     board, not sit beside it. */
  background:
    radial-gradient(120% 90% at 50% 0%, rgba(22, 32, 58, .97) 0%, rgba(10, 16, 30, .98) 62%);
  transition: opacity .28s ease, visibility .28s ease;
}

.ts-brief[hidden] { display: none; }
.ts-brief.ts-brief--out { opacity: 0; visibility: hidden; pointer-events: none; }

.ts-brief__shield {
  width: 30px;
  height: 30px;
  color: var(--ts-accent);
  stroke-width: 1.6;
}

/* The category label. One word above the title does more to say "this is a
   game" than any amount of premise copy underneath it. */
.ts-brief__eyebrow {
  margin: 0;
  color: var(--ts-accent);
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
}

/* Attribution on the gate itself. The header's kicker is behind the scrim at
   8px, so without this nothing marks the panel as editorial rather than a
   third-party embed, which is the cheapest trust signal available here. */
.ts-brief__from {
  margin: -4px 0 2px;
  color: var(--ts-muted);
  font-size: 10px;
  letter-spacing: .02em;
}

.ts-brief__title {
  margin: 0;
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -.015em;
  line-height: 1.1;
}

/* Difficulty, restated here because the header chip is easy to miss.
   Same handler as .ts-mode, so the two can never disagree. */
.ts-brief__level {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ts-muted);
}

.ts-brief__chip {
  padding: 4px 9px;
  border: 1px solid var(--ts-line);
  border-radius: 4px;
  background: var(--ts-panel);
  color: var(--ts-text);
  font: inherit;
  letter-spacing: .1em;
  cursor: pointer;
  transition: color .15s, border-color .15s;
}
.ts-brief__chip:hover { border-color: var(--ts-accent); color: var(--ts-accent); }
.ts-brief__chip:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 2px; }

/* ── Terminal button ──────────────────────────────────────────
   Reads as a command line rather than a button, which is both the
   clearest "this is interactive" signal available in this palette
   and a nod to the mono the rest of the site now uses for data. */
.ts-cmd {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-top: 4px;
  /* Sized generously on purpose. .ts-fit scales the whole widget down on a
     phone (0.67 at 320px), so every control inside it shrinks with the
     board: at 9px padding this button rendered 23px tall at 320px, under the
     24px WCAG 2.5.8 floor. At 13px it clears it. Nothing inside a uniformly
     scaled widget can reach the 44px ideal at 320px without changing how the
     widget scales, so the primary action is made the most comfortable
     target rather than all of them. */
  padding: 13px 18px;
  border: 1px solid #2f4472;
  border-radius: 5px;
  background: var(--ts-sunken);
  color: var(--ts-text);
  font-family: var(--ts-mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .02em;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.ts-cmd:hover { border-color: var(--ts-accent); background: #0d1730; }
.ts-cmd:focus-visible { outline: 2px solid var(--ts-accent); outline-offset: 2px; }
.ts-cmd__prompt { color: var(--ts-ok); }

/* Block cursor, the one piece of motion on an idle widget. It is what
   makes the grid read as live rather than printed. */
.ts-cmd__caret {
  width: 7px;
  height: 13px;
  background: var(--ts-accent);
  animation: ts-blink 1.05s steps(1, end) infinite;
}
@keyframes ts-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* ── Scanline arm ─────────────────────────────────────────────
   On start the grid sweeps once, top-left to bottom-right, before
   play begins. --i is set per cell in JS so the delay follows
   reading order. Total run is capped at ~420ms: long enough to
   register, short enough that nobody waits for it. */
.ts-board.ts-arming { pointer-events: none; }

.ts-board.ts-arming .ts-cell {
  animation: ts-sweep .34s ease-out both;
  animation-delay: calc(var(--i, 0) * 4.5ms);
}

@keyframes ts-sweep {
  0%   { background: var(--ts-tile); box-shadow: inset 0 1px 0 rgba(255,255,255,.06); }
  38%  { background: var(--ts-accent); box-shadow: 0 0 10px rgba(77, 139, 240, .55); }
  100% { background: var(--ts-tile); box-shadow: inset 0 1px 0 rgba(255,255,255,.06); }
}

/* Respect reduced motion: keep the gate and the button, drop the
   sweep and the blink. The existing prefers-reduced-motion block
   only shortens transitions, not animations. */
@media (prefers-reduced-motion: reduce) {
  .ts-board.ts-arming .ts-cell { animation: none; }
  .ts-cmd__caret { animation: none; opacity: 1; }
}

/* ── Control legend on the briefing gate ──────────────────────
   Added 2026-09-09. Scanning was explained in the ticker, but flagging was
   not explained anywhere: the only route to it was an unlabelled icon in the
   status bar, a right click, or knowing to long press. Most players would
   never find the mechanic, which is half the game.

   Icons are the same marks the game uses, so recognising the flag here means
   recognising the flag button later. */
.ts-brief__how {
  margin: 2px 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 7px;
  max-width: 268px;
  text-align: left;
}

.ts-brief__how li {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  color: var(--ts-muted);
  font-size: 10.5px;
  line-height: 1.45;
  text-wrap: pretty;
}

.ts-brief__how svg {
  flex: none;
  width: 13px;
  height: 13px;
  margin-top: 1px;
  color: var(--ts-accent);
}
