
:root {
  /* Neutrals — warm-tinted */
  --n0:#fff; --n25:#fdfcfb; --n50:#f8f7f5; --n100:#f0eeeb; --n200:#e3e0dc;
  --n300:#ccc7c1; --n400:#a8a29a; --n500:#7e7870; --n600:#5d5851; --n700:#423f3a;
  --n800:#2b2926; --n900:#1a1917; --n950:#100f0e;

  /* Accent — indigo. Never used for status; status has its own colours. */
  --a300:#a5a6f6; --a400:#8385f0; --a500:#6366e8; --a600:#4f46d6; --a700:#3f37ad;

  /* Category, per §7. Fixed meanings, used nowhere else. */
  --fire:#e0452b; --medical:#d33a6f; --intrusion:#dd8409; --environmental:#0e93a3;
  --ok:#18845a; --warn:#b8730a; --bad:#c8371f;

  /* Semantic surfaces */
  --bg:var(--n50); --surface:var(--n0); --raised:var(--n0);
  --line:var(--n200); --line-strong:var(--n300);
  --ink:var(--n900); --ink-2:var(--n600); --ink-3:var(--n500);
  --accent:var(--a600); --accent-ink:#fff; --accent-soft:#eef0fe;
  --focus:var(--a500);

  /* Spacing — 4px base */
  --s1:.25rem; --s2:.5rem; --s3:.75rem; --s4:1rem; --s5:1.5rem;
  --s6:2rem; --s7:3rem; --s8:4rem;

  /* Type scale */
  --t-xs:.75rem; --t-sm:.8125rem; --t-md:.875rem; --t-base:.9375rem;
  --t-lg:1.125rem; --t-xl:1.5rem; --t-2xl:2rem;

  --r-sm:6px; --r-md:10px; --r-lg:14px; --r-full:999px;

  --shadow-1:0 1px 2px rgb(16 15 14 / .04), 0 1px 3px rgb(16 15 14 / .06);
  --shadow-2:0 2px 4px rgb(16 15 14 / .04), 0 8px 24px rgb(16 15 14 / .08);
  --shadow-focus:0 0 0 3px color-mix(in srgb, var(--focus) 28%, transparent);
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:var(--n950); --surface:var(--n900); --raised:var(--n800);
    --line:#2e2b28; --line-strong:#403c37;
    --ink:var(--n50); --ink-2:var(--n300); --ink-3:var(--n400);
    --accent:var(--a400); --accent-ink:var(--n950); --accent-soft:#22213a;
    --focus:var(--a400);
    --fire:#f2705a; --medical:#e8709b; --intrusion:#eda93f; --environmental:#3fb8c6;
    --ok:#45b184; --warn:#d99a3a; --bad:#e3705c;
    --shadow-1:0 1px 2px rgb(0 0 0 / .3);
    --shadow-2:0 2px 4px rgb(0 0 0 / .3), 0 8px 24px rgb(0 0 0 / .35);
  }
}

*,*::before,*::after { box-sizing:border-box; }
html { -webkit-text-size-adjust:100%; }
body {
  margin:0; background:var(--bg); color:var(--ink);
  font-family:system-ui,-apple-system,"Segoe UI Variable Text","Segoe UI",
              Roboto,"Helvetica Neue",sans-serif;
  font-size:var(--t-base); line-height:1.55;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  font-variant-numeric:tabular-nums;
}
h1,h2,h3 { margin:0; font-weight:600; letter-spacing:-.02em; line-height:1.25; }
h1 { font-size:var(--t-xl); }
h2 { font-size:var(--t-lg); }
h3 { font-size:var(--t-base); }
p { margin:0; }
a { color:var(--accent); text-decoration:none; }
a:hover { text-decoration:underline; }

/* ---- app frame ---------------------------------------------------------- */
.app { display:grid; grid-template-columns:15rem 1fr; min-height:100vh; }
@media (max-width:56rem) { .app { grid-template-columns:1fr; } }

.side {
  background:var(--surface); border-right:1px solid var(--line);
  padding:var(--s5) var(--s4); display:flex; flex-direction:column; gap:var(--s5);
}
@media (max-width:56rem) { .side { border-right:0; border-bottom:1px solid var(--line); } }

.mark { display:flex; align-items:center; gap:var(--s2); font-weight:650;
        letter-spacing:-.02em; }
.mark .dot { width:.6rem; height:.6rem; border-radius:var(--r-full);
             background:var(--fire); box-shadow:0 0 0 3px color-mix(in srgb,var(--fire) 20%,transparent); }

/* A breadcrumb, not a label.
   This said "Dealer: Development", which reads as an identity claim — as though
   the signed-in platform administrator WERE that dealer. They are not; they
   navigated into it. A breadcrumb says location, which is what this is, and its
   first segment is the way back out, so no separate control is needed. */
.crumbs { display:flex; align-items:center; gap:var(--s2); margin-bottom:var(--s5);
          font-size:var(--t-md); color:var(--ink-3); }
.crumbs strong { color:var(--ink); font-weight:560; }
.crumbs span { color:var(--n400); }

.nav { display:flex; flex-direction:column; gap:1px; }
.nav a {
  display:flex; align-items:center; gap:var(--s3); padding:var(--s2) var(--s3);
  border-radius:var(--r-sm); color:var(--ink-2); font-size:var(--t-md);
  font-weight:500; transition:background .12s ease, color .12s ease;
}
.nav a:hover { background:var(--n100); color:var(--ink); text-decoration:none; }
@media (prefers-color-scheme:dark){ .nav a:hover { background:var(--raised); } }
.nav a[aria-current="page"] { background:var(--accent-soft); color:var(--accent); font-weight:600; }
.nav .count { margin-left:auto; font-size:var(--t-xs); color:var(--ink-3);
              font-variant-numeric:tabular-nums; }

.side .foot { margin-top:auto; display:flex; flex-direction:column; gap:var(--s2);
              border-top:1px solid var(--line); padding-top:var(--s4); }
.who { font-size:var(--t-sm); color:var(--ink-2); overflow-wrap:anywhere; }
.who .role { display:inline-block; margin-top:var(--s1); padding:.05rem .45rem;
             border:1px solid var(--line-strong); border-radius:var(--r-full);
             font-size:var(--t-xs); color:var(--ink-3); }

.main { padding:var(--s6) var(--s6) var(--s8); max-width:72rem; }
@media (max-width:56rem) { .main { padding:var(--s5) var(--s4) var(--s7); } }

.head { display:flex; align-items:flex-start; gap:var(--s4); margin-bottom:var(--s5); }
.head .grow { flex:1; min-width:0; }
/* The kicker naming what this page is. Quiet enough that the name still leads,
   loud enough to answer "what am I looking at" without reading the breadcrumb. */
.head .kind { font-size:var(--t-xs); font-weight:600; letter-spacing:.08em;
              text-transform:uppercase; color:var(--n500); margin-bottom:var(--s1); }
.lede { color:var(--ink-2); font-size:var(--t-md); margin-top:var(--s1); }

/* ---- surfaces ----------------------------------------------------------- */
.card { background:var(--surface); border:1px solid var(--line);
         border-radius:var(--r-lg); box-shadow:var(--shadow-1); overflow:hidden; }
.card + .card { margin-top:var(--s5); }
.card-head { display:flex; align-items:center; gap:var(--s3);
              padding:var(--s4) var(--s5); border-bottom:1px solid var(--line); }
.card-head .grow { flex:1; }
.card-body { padding:var(--s5); }

.tiles { display:grid; gap:var(--s4);
         grid-template-columns:repeat(auto-fit,minmax(11rem,1fr)); margin-bottom:var(--s5); }
.tile { background:var(--surface); border:1px solid var(--line);
        border-radius:var(--r-lg); padding:var(--s4) var(--s5);
        box-shadow:var(--shadow-1); transition:box-shadow .15s ease, transform .15s ease; }
a.tile:hover { box-shadow:var(--shadow-2); transform:translateY(-1px); text-decoration:none; }
.tile .n { font-size:var(--t-2xl); font-weight:640; letter-spacing:-.03em; line-height:1.1; }
.tile .label { color:var(--ink-3); font-size:var(--t-sm); margin-top:var(--s1);
               text-transform:uppercase; letter-spacing:.06em; font-weight:600; }

/* ---- detail screens ------------------------------------------------------ */
.facts { display:grid; gap:var(--s4) var(--s6); margin:0;
         grid-template-columns:repeat(auto-fit,minmax(13rem,1fr)); }
.facts div { min-width:0; }
.facts dt { font-size:var(--t-xs); text-transform:uppercase; letter-spacing:.06em;
            font-weight:600; color:var(--ink-3); margin-bottom:var(--s1); }
.facts dd { margin:0; font-size:var(--t-base); overflow-wrap:anywhere; }

/* ---- tables ------------------------------------------------------------- */
.rows { width:100%; border-collapse:collapse; }
.rows th { text-align:left; font-size:var(--t-xs); text-transform:uppercase;
           letter-spacing:.06em; color:var(--ink-3); font-weight:600;
           padding:var(--s3) var(--s5); border-bottom:1px solid var(--line); }
.rows td { padding:var(--s3) var(--s5); border-bottom:1px solid var(--line);
           font-size:var(--t-md); vertical-align:middle; }
.rows tr:last-child td { border-bottom:0; }
.rows tbody tr { transition:background .1s ease; }
.rows tbody tr:hover { background:var(--n50); }
@media (prefers-color-scheme:dark){ .rows tbody tr:hover { background:var(--raised); } }
.rows .strong { font-weight:560; color:var(--ink); }
.rows .muted { color:var(--ink-3); }
.mono { font-family:ui-monospace,SFMono-Regular,"SF Mono",Menlo,monospace;
        font-size:var(--t-sm); }

.empty { padding:var(--s7) var(--s5); text-align:center; color:var(--ink-3); }
.empty .big { font-size:var(--t-lg); color:var(--ink-2); font-weight:560;
              margin-bottom:var(--s2); letter-spacing:-.01em; }

/* ---- controls ----------------------------------------------------------- */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:var(--s2);
  padding:.5rem .9rem; border:1px solid transparent; border-radius:var(--r-sm);
  background:var(--accent); color:var(--accent-ink);
  font:inherit; font-size:var(--t-md); font-weight:560; cursor:pointer;
  transition:filter .12s ease, box-shadow .12s ease, transform .06s ease;
  white-space:nowrap;
}
.btn:hover { filter:brightness(1.07); text-decoration:none; }
.btn:active { transform:translateY(1px); }
.btn.ghost { background:transparent; border-color:var(--line-strong); color:var(--ink); }
.btn.ghost:hover { background:var(--n100); filter:none; }
@media (prefers-color-scheme:dark){ .btn.ghost:hover { background:var(--raised); } }
.btn.quiet { background:transparent; color:var(--ink-2); padding:.35rem .5rem; }
.btn.quiet:hover { background:var(--n100); color:var(--ink); filter:none; }
@media (prefers-color-scheme:dark){ .btn.quiet:hover { background:var(--raised); } }
.btn.danger { background:transparent; border-color:var(--line-strong); color:var(--bad); }
.btn.danger:hover { background:color-mix(in srgb,var(--bad) 10%,transparent); filter:none; }
.btn:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible {
  outline:none; box-shadow:var(--shadow-focus); border-color:var(--focus);
}

.field { display:flex; flex-direction:column; gap:var(--s2); margin-bottom:var(--s4); }
.field label { font-size:var(--t-sm); font-weight:560; color:var(--ink-2); }
.field .hint { font-size:var(--t-sm); color:var(--ink-3); line-height:1.45; }
input[type=text],input[type=email],input[type=password],select {
  width:100%; padding:.55rem .7rem; border:1px solid var(--line-strong);
  border-radius:var(--r-sm); background:var(--surface); color:var(--ink);
  font:inherit; font-size:var(--t-md); transition:border-color .12s ease, box-shadow .12s ease;
}
input::placeholder { color:var(--n400); }
.grid2 { display:grid; gap:0 var(--s4); grid-template-columns:1fr 1fr; }
@media (max-width:36rem){ .grid2 { grid-template-columns:1fr; } }
.actions { display:flex; gap:var(--s3); align-items:center; margin-top:var(--s5); }
.actions .spacer { flex:1; }

/* ---- badges ------------------------------------------------------------- */
.chip { display:inline-flex; align-items:center; gap:var(--s2);
        padding:.15rem .55rem; border-radius:var(--r-full);
        font-size:var(--t-xs); font-weight:600; letter-spacing:.01em;
        border:1px solid var(--line-strong); color:var(--ink-2); }
.chip .swatch { width:.5rem; height:.5rem; border-radius:var(--r-full); }
.chip.fire .swatch{background:var(--fire)} .chip.medical .swatch{background:var(--medical)}
.chip.intrusion .swatch{background:var(--intrusion)}
.chip.environmental .swatch{background:var(--environmental)}

/* An incident label. The hue comes from the row (--incident-hue), so two rows
   of the same incident match and the eye can pair them without reading the
   number. Saturation and lightness are fixed so every hue stays legible in both
   themes; only the hue varies. */
.chip.incident { border-color:hsl(var(--incident-hue) 45% 50% / .5); }
.chip.incident .swatch { background:hsl(var(--incident-hue) 55% 48%); }
@media (prefers-color-scheme:dark){
  .chip.incident .swatch { background:hsl(var(--incident-hue) 60% 62%); }
}
a.chip { text-decoration:none; }
a.chip:hover { border-color:var(--ink-3); color:var(--ink); }
/* The isolated view, where an incident's events finally sit together. */
.incident-head { display:flex; align-items:center; gap:var(--s3); flex-wrap:wrap; }

/* A row that has just arrived.
   THE ROW HAS TO GROW, or nothing has arrived — it has appeared. A table row
   takes its full height the instant it is inserted, so animating only opacity
   and a small offset leaves everything below it JUMPING down while the new
   row's contents fade in on the spot. The eye reads that as a redraw.
   So the cells animate their own padding and line-height from nothing to their
   natural values. The row's height follows, and every row beneath it slides
   down continuously for the whole half-second instead of teleporting once.
   Three things, each saying something the others cannot:
     the GROWTH says a row was inserted here and pushed the rest down;
     the FADING TINT says which rows are new for a few seconds after the
     movement is over and can no longer say anything at all. */
/* 1.55 is the body's line-height, written out as a number because the keyword
   "normal" cannot be interpolated — animating to it would snap at the end
   rather than ease, which is exactly the jump this exists to remove. */
@keyframes feed-grow {
  from { padding-top:0; padding-bottom:0; line-height:0; opacity:0; }
  55%  { opacity:1; }
  to   { padding-top:var(--s3); padding-bottom:var(--s3); line-height:1.55; opacity:1; }
}
@keyframes feed-settle {
  from { background:var(--accent-soft); }
  to   { background:transparent; }
}
/* cubic-bezier(.16,1,.3,1) decelerates hard and then eases the last few pixels,
   which is what makes it read as settling into place rather than stopping.
   The opacity finishes early, at 55%, so the text is legible while the row is
   still opening — the content arrives, then the space around it finishes. */
.rows tr.is-new > td {
  animation: feed-grow .6s cubic-bezier(.16,1,.3,1) both var(--stagger, 0ms);
}
.rows tr.is-new {
  animation: feed-settle 3s ease-out both var(--stagger, 0ms);
}
/* Motion is the point here, but it is not worth making somebody ill over. With
   reduced motion the tint still marks what is new; only the movement goes. */
@media (prefers-reduced-motion: reduce) {
  .rows tr.is-new > td { animation:none; }
  .rows tr.is-new { animation: feed-settle 3s ease-out both; }
}
/* The live beacon.
   A dot with a ring expanding out of it, slowly. It says the page is still
   asking — which is otherwise invisible, because a feed that has quietly
   stopped looks exactly like a feed with nothing to report.
   MOTION IS THE HEALTHY STATE, and its absence is the signal. When polling
   fails the ring stops and the dot turns amber, so a stalled feed is something
   the eye catches rather than something you have to read. */
.beacon { display:inline-flex; align-items:center; gap:var(--s2); }
.beacon-dot { position:relative; width:.5rem; height:.5rem; border-radius:var(--r-full);
              background:var(--ok); flex:none; }
.beacon-dot::after {
  content:""; position:absolute; inset:0; border-radius:var(--r-full);
  background:var(--ok); animation: beacon 2.6s ease-out infinite;
}
@keyframes beacon {
  0%   { opacity:.55; transform:scale(1); }
  70%  { opacity:0;   transform:scale(3.2); }
  100% { opacity:0;   transform:scale(3.2); }
}
.beacon[data-state="stalled"] .beacon-dot { background:var(--warn); }
.beacon[data-state="stalled"] .beacon-dot::after { animation:none; }
/* Without motion the ring cannot say anything, so the dot carries it alone —
   and the stalled colour still does its job. */
@media (prefers-reduced-motion: reduce) {
  .beacon-dot::after { animation:none; }
}

/* How many arrived while you were reading further down.
   It leaves on a fade. The count going away is not news, and something
   blinking out of the header pulls the eye to the one spot where nothing just
   happened — the opposite of what an attention cue is for. Arriving is still
   instant: that IS news.
   The duration is mirrored in feedscript.go, which hides the element once the
   fade has played; a transition cannot run on display:none. */
.feed-new { background:var(--accent-soft); color:var(--accent); border-radius:var(--r-full);
            padding:.15rem .55rem; font-size:var(--t-xs); font-weight:600;
            transition: opacity .45s ease-out; }
.feed-new[data-leaving] { opacity:0; }
.feed-new[hidden] { display:none; }
@media (prefers-reduced-motion: reduce) {
  .feed-new { transition:none; }
}

.note { display:flex; gap:var(--s3); padding:var(--s3) var(--s4);
        border-radius:var(--r-md); font-size:var(--t-md); line-height:1.5;
        border:1px solid var(--line-strong); background:var(--n100); color:var(--ink-2); }
@media (prefers-color-scheme:dark){ .note { background:var(--raised); } }
.note.bad { border-color:color-mix(in srgb,var(--bad) 45%,var(--line));
            background:color-mix(in srgb,var(--bad) 8%,transparent); color:var(--ink); }
.note strong { color:var(--ink); font-weight:600; }

/* ---- viewing as another user -------------------------------------------- */
/* Deliberately loud. Forgetting you are wearing someone else's face is the
   whole hazard of the feature, so it is warm-coloured, sticky, and the only
   element on any page allowed to look like this. */
.viewing { position:sticky; top:0; z-index:10; display:flex; align-items:center;
           gap:var(--s4); margin:calc(var(--s6) * -1) calc(var(--s6) * -1) var(--s5);
           padding:var(--s3) var(--s6); font-size:var(--t-md);
           background:color-mix(in srgb,var(--intrusion) 16%,var(--surface));
           border-bottom:2px solid var(--intrusion); color:var(--ink); }
.viewing .grow { flex:1; }
.viewing .btn { background:var(--intrusion); color:#fff; padding:.35rem .8rem; }
@media (max-width:56rem){ .viewing { margin:calc(var(--s5) * -1) calc(var(--s4) * -1) var(--s5);
                                     padding:var(--s3) var(--s4); } }

/* ---- sign in ------------------------------------------------------------ */
.signin { min-height:100vh; display:grid; place-items:center; padding:var(--s5); }
.signin .box { width:100%; max-width:23rem; }
.signin .brandline { display:flex; align-items:center; gap:var(--s2);
                     justify-content:center; margin-bottom:var(--s5);
                     font-size:var(--t-lg); font-weight:650; letter-spacing:-.02em; }
.signin .card-body { padding:var(--s6); }
.signin h1 { font-size:var(--t-lg); margin-bottom:var(--s1); }
.signin .lede { margin-bottom:var(--s5); }
.signin .btn { width:100%; margin-top:var(--s2); }
