/* Fire Monitor — design tokens.
 *
 * The single source of colour, type and spacing. Every screen reads from here.
 * No screen defines its own value after this; if a screen needs one that is not
 * here, that is a conversation rather than a local override.
 *
 * Specified in docs/FIRE_MONITOR_DESIGN_SPEC.md section 1 (Ohad Golan, v1.0,
 * 13 August 2026). Where this file and the spec disagree, the spec is wrong and
 * gets amended — not this file quietly.
 *
 * THE SURFACE RAMP IS ANCHORED ON THE BRAND INK, NOT ON THE SPEC'S FIRST DRAFT.
 * The spec shipped with --surface-page #0E0D0C. brand/brand.json gives ink
 * #1B1D1B, "Confirmed by Emily from the source file, 2026-08-10", and that value
 * is already carried by the loader and by manifest.json's background_color.
 * Ohad, 2026-08-13: "the brand file wins — my spec is wrong, not the codebase."
 * Section 1 of the spec has been amended to match, with the provenance noted.
 */

:root {
  /* ── Surfaces ──────────────────────────────────────────────────────────
   * Warm near-black. Not grey — the warmth is what stops it reading as a
   * dashboard. */
  --surface-page:      #1B1D1B;  /* brand ink; matches loader + manifest */
  --surface-recessed:  #151715;  /* muted or inactive rows */
  --surface-row:       #1F211F;  /* list rows, chips */
  --surface-card:      #232624;  /* cards, elevated blocks */
  /* REDESIGN 2026-10-27 (Ohad approved; docs/design/fire-monitor-redesign-
   * 2026-10-27.html): one neutral grey scale from hephaestus.solutions, the
   * warm browns go. The page stays the brand ink (brand.json). */
  --surface-raised:    #262927;  /* blocks inside a card */
  --hairline:          #2E312F;  /* all borders and dividers */

  /* ── Text ──────────────────────────────────────────────────────────────
   * Measured against --surface-page (#1B1D1B), not assumed:
   *   --text-primary    15.06:1   passes 4.5:1
   *   --text-secondary   5.53:1   passes 4.5:1
   *   --text-muted       5.52:1   raised from 3.12:1, then again to clear
   *
   * --text-muted WAS #6F6960 at 3.12:1, below the spec's own platform-
   * checklist threshold at the 11px it is specified for. Ohad, 2026-08-13:
   * "timestamps and freshness lines are not decoration here -- 'checked 4 min
   * ago' is what tells someone whether to trust the screen, and it has to be
   * readable at 11px in daylight."
   *
   * It went to #8A8279 first, which I said would clear 4.5:1 and did not --
   * 4.48 on the page, 3.68 on a raised block. The failing value SHIPPED while
   * the gap was reported, because a builder who substitutes a better number
   * when the specified one misses has stopped building to a specification.
   * Ohad then set #99928A: "the rule is the rule; the number changes."
   *
   * Measured on every ground that carries body text:
   *   page 5.52 · recessed 5.86 · row 5.27 · card 4.97 · raised 4.53
   * ALL FIVE CLEAR 4.5:1, including the tightest. Still below
   * --text-secondary (5.53 on the page), so the hierarchy holds by colour as
   * well as by size and letter-spacing.
   *
   * The five numbers above were WRONG in the first draft of this comment --
   * carried over from a calculation against a different base. A comment
   * stating measurements nobody re-measures is the same class as one asserting
   * a guarantee nobody checks, so these are the values the test computes. */

  /* REDESIGN 2026-10-27: the site's light #ECECEC and neutral greys. Measured
   * (lowest ground, --surface-raised): primary 12.44, secondary 5.83, muted
   * 4.84 -- all clear 4.5:1, muted still below secondary. */
  --text-primary:      #ECECEC;
  /* Body copy a step below primary: the neutral of the old warm #C6BDAE
   * (Home "when" lines, plan text, sheet sentences). 9.9:1 on the page. */
  --text-body:         #C9C9C9;
  --text-secondary:    #A3A3A3;
  --text-muted:        #949494;

  /* ── Severity ──────────────────────────────────────────────────────────
   * The ONLY place colour encodes meaning.
   *
   * THE ACCENT RULE: --sev-very-high is the brand colour and appears only when
   * something is genuinely urgent. Never a button fill, never a heading, never
   * decoration. If the screen is calm the orange is absent, and that absence is
   * information the customer reads without being told.
   *
   * NAMED EXCEPTION — THE UNARMED-CHANNEL WARNING. Ruled by Ohad 2026-09-11
   * (walk Defect 10), written here so the rule is amended rather than broken
   * in silence. Screen: index.html #unarmed-warning, shown in the place form
   * after a save when NEITHER alert channel is on. Its "Turn on notifications"
   * and "Email me alerts" are BOTH brand-orange fills, equal weight. Why this
   * panel is the urgent state the rule reserves: its own sentence is "no alert
   * can reach you yet" — a place is watched and nothing will tell the customer
   * about a fire near it. Neither channel is primary; each is a missing way to
   * be reached. NOTHING ELSE INHERITS THIS: a new fill elsewhere needs its own
   * named exception here, or it is the rule being broken.
   *
   * ══ SUPERSEDED 2026-10-27 BY THE APPROVED REDESIGN ══════════════════════
   * Ohad approved docs/design/fire-monitor-redesign-2026-10-27.html: the brand
   * orange is now also the active tab, the one primary button per screen, and
   * the High severity. The rule above stands as history; the redesign's own
   * rule is "one primary (orange) button per screen".
   *
   * ONE SEVERITY RAMP, used by every surface (map markers, clusters, legend,
   * list dots, Home and sheet rails, Alerts dots). Low to Extreme, warm only:
   * no green, no purple, no blue. High IS the brand orange (Ohad's call (a)).
   * Very high and danger were tuned from the reference's placeholders to clear
   * contrast; Extreme marks carry a light ring because no deep red can show on
   * a near-black ground.
   *
   * Contrast on --surface-card, measured:
   *   --sev-low        10.70:1  safe as text; dark text on its chip
   *   --sev-moderate    7.33:1  safe as text; dark text on its chip
   *   --sev-high        4.35:1  rail, icon, large text; dark text on its chip
   *   --sev-very-high   3.09:1  rail and icon only; white text on its chip (4.94)
   *   --sev-extreme     1.41:1  fill only, with a light ring; white text (11.6)
   *   --sev-approach    5.42:1  safe as text
   *   --sev-gone        1.63:1  rail only; as text it is unreadable */
  --brand-orange:      #FF3F1A;
  --sev-low:           #F6D48B;
  --sev-moderate:      #F2A33A;
  --sev-high:          #FF3F1A;
  --sev-very-high:     #D0362F;
  --sev-extreme:       #7A1414;
  --sev-gone:          #4A4642;
  --sev-approach:      #FF6B47;
  /* Text on a severity chip: dark on Low, Moderate, High; white on Very high,
   * Extreme (Ohad's call (b)). */
  --on-sev-light:      #1B1D1B;
  --on-sev-dark:       #FFFFFF;
  /* The one danger red for error text (replaces six hard-coded reds). The
   * reference's #E5484D measured 3.9:1 on a card; this clears 4.5. */
  --danger:            #F06368;

  /* ── The quiet rail ────────────────────────────────────────────────────
   * NAMED, NOT BORROWED. A calm property gets a rail like any other row, and
   * it must not reach for a severity token to get one: --sev-gone means "no
   * longer detected", which is a statement about a FIRE, not about a property
   * with nothing near it.
   *
   * It is --hairline's value, and it has its own name so that changing what a
   * quiet property looks like cannot silently change every border in the app.
   *
   * THE GREEN IS GONE. #5ce0b0 said "watched and clear" in the one colour the
   * palette does not contain, and section 5 forbids what it says: no green, no
   * tick, no all-clear. */
  /* MOVES WITH --hairline BY DESIGN, and the guard is what said so.
     tests/test_design_tokens.py asserts --rail-quiet == --hairline: the quiet
     rail carries the hairline's VALUE and its own NAME, so changing what a
     calm property looks like cannot silently change every border in the app.
     Changing the two panel tokens on 2026-08-23 without this left them
     desynced, and the parity guard caught it in the same run. */
  --rail-quiet:        #2E312F;

  /* ── Type ──────────────────────────────────────────────────────────────
   * NO WEB FONT. A deliberate choice, not a shortcut: zero bytes, zero render
   * delay, native on iOS and Android, and it respects Dynamic Type and Android
   * font scaling for free — both review items. The brand typeface lives in the
   * wordmark, which is an image. */
  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;

  --size-hero:         44px;  /* distance on a card, weight 500, tabular */
  --size-hero-compact: 32px;  /* distance in a list row */
  --size-title:        17px;  /* screen title */
  --size-row-title:    14px;
  --size-body:         13px;  /* line-height 1.5 */
  --size-meta:         11px;  /* letter-spacing 0.8px, --text-muted */

  /* Two weights only. Never 600 or 700. */
  --weight-regular:    400;
  --weight-medium:     500;

  --line-body:         1.5;
  --track-meta:        0.8px;

  /* ── Spacing and shape ─────────────────────────────────────────────────
   * Nothing between these steps. */
  --space-1:  4px;
  --space-2:  6px;
  --space-3:  8px;
  --space-4:  12px;
  --space-5:  16px;
  --space-6:  20px;
  --space-7:  24px;

  /* SEVERITY RAILS HAVE SQUARE CORNERS. A 3px left border with a rounded
   * corner looks broken. */
  --radius-card:       12px;  /* cards WITHOUT a rail */
  --radius-railed:     0;     /* cards WITH a severity rail */
  --radius-control:    8px;   /* chips and controls */
  --rail-width:        3px;

  /* Platform checklist: 44x44pt minimum for anything tappable, and a 44px
   * minimum row height in every list. Tokens so a screen cannot quietly
   * choose 36. */
  --tap-min:           44px;
  --row-min-height:    44px;
}

/* ── VISIBLE KEYBOARD FOCUS (platform checklist §6) ─────────────────────────
 *
 * MEASURED 2026-08-14: this app had ZERO :focus-visible rules and three
 * :focus mentions in total. Every browser draws its own default outline, and
 * several of this app's controls override it to nothing by setting a custom
 * border — so tabbing through Settings gave no reliable indication of where
 * you were.
 *
 * It is on Ohad's checklist because Apple and Google both check it, and it is
 * the item on that list with a real user behind it rather than a reviewer:
 * somebody operating this one-handed with a switch control, or on a keyboard,
 * cannot use a screen whose focus is invisible.
 *
 * :focus-visible, NOT :focus. A plain :focus ring fires on mouse clicks too,
 * which is why the outlines were removed in the first place; :focus-visible is
 * the browser telling us the focus came from a keyboard. Styling that instead
 * gives keyboard users the ring back without giving mouse users a ring they
 * did not ask for and will ask to have removed again.
 *
 * TWO COLOURS, because one does not work on both grounds. The ring is the
 * approach orange on dark surfaces — it is the only accent in the palette that
 * is not a severity, so it cannot be mistaken for a fire state.
 *
 * outline-offset is what makes it visible against a control that already has a
 * border: without it the ring sits on top of the border and reads as a colour
 * change rather than as focus. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--sev-approach);
  outline-offset: 2px;
  border-radius: var(--radius-control);
}

/* A focus ring must never be animated away for someone who asked for less
 * motion — and must never be the ONLY thing that moved. */
@media (prefers-reduced-motion: reduce) {
  :where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
    transition: none;
  }
}

/* ── THE BRAND MARK, SHARED ────────────────────────────────────────────────
 *
 * One asset, one treatment, defined once. Ohad, 2026-08-17, choosing the
 * loader's mark over the square icon: "the loader is seen on every launch and
 * the signup page once, so the loader is the one people learn as our mark.
 * Making the rarer surface match the commoner one is the right direction."
 *
 * IT LIVES HERE RATHER THAN BEING COPIED INTO EACH PAGE. Copying it is the
 * same-markup-twice shape Track B refused for the email shells, and it drifts —
 * which is exactly how these five pages ended up on the pre-rebrand palette in
 * the first place. This file is already linked by index.html and all five
 * public pages, and it already carries a shared :focus-visible rule, so it is
 * the shared foundation rather than a pure token list.
 *
 * THE RINGS ARE STILL HERE, AND THAT IS DELIBERATE. On the splash they SPIN —
 * sp-orbit and splash-pulse make them a progress indicator. A perpetual
 * spinner on a static signup form would say "working" when nothing is
 * happening, so the shared class is the mark at rest and the splash layers its
 * animation on top. What Ohad approved in the comparison was the still
 * version; this is that.
 *
 * THE ORANGE IS LITERAL, for the same reason the pages keep theirs: the only
 * token holding #FF3F1A is --sev-very-high, and a brand mark is not a severity.
 */
.brand-mark{
  position: relative;
  width: 160px;
  height: 160px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.brand-mark::before,
.brand-mark::after{
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 2px solid transparent;
  pointer-events: none;
}
.brand-mark::before{
  border-top-color: #FF3F1A;
  border-right-color: rgba(255, 63, 26, 0.4);
}
.brand-mark::after{
  inset: 14px;
  border-bottom-color: rgba(255, 122, 61, 0.55);
  border-left-color: rgba(255, 122, 61, 0.2);
}
.brand-mark img{
  width: 108px;
  height: 108px;
  object-fit: contain;
  filter: drop-shadow(0 0 18px rgba(255, 63, 26, 0.45));
}
