:root{
  color-scheme:dark;
  --bg:#0B1523; --bg-2:#0d1a2b; --panel:#0F1D2E; --panel-2:#132a41;
  --line:rgba(143,163,187,.18); --line-strong:rgba(143,163,187,.34);
  --ink:#E6EDF5; --ink-strong:#fff; --slate:#8FA3BB; --slate-dim:#6b7f98;
  --crimson:#C0192B; --crimson-bright:#E11D2E; --amber:#D9A441; --teal:#3FB0AC; --green:#3f9d6b;
  --amber-ink:#D9A441;
  --grid-line:rgba(143,163,187,.035);
  --bg-glow:rgba(192,25,43,.10);
  --hover-row:rgba(143,163,187,.05);
  --hover-tint:rgba(143,163,187,.08);
  --topbar-grad:linear-gradient(180deg,rgba(15,29,46,.92),rgba(11,21,35,.82));
  /* Glass: the top bar is a translucent sheet over a blurred backdrop, and the
     Settings tab strip is cut from the same material — inactive tabs and the
     group shells are a tint over their own blur, so page content reads through
     them. (The active tab is the one opaque surface: it is filled with --bg.) */
  --topbar-glass:blur(14px) saturate(1.4);
  --tab-blur:blur(9px) saturate(1.2);
  --tab-glass:rgba(143,163,187,.10);
  --tab-glass-hover:rgba(143,163,187,.18);
  --tabgroup-glass-teal:rgba(63,176,172,.14);
  --tabgroup-hover-teal:rgba(63,176,172,.24);
  --panel-grad:linear-gradient(180deg,rgba(19,42,65,.35),rgba(15,29,46,.5));
  --editsec-grad:linear-gradient(180deg,rgba(19,42,65,.28),rgba(15,29,46,.4));
  --docsheet-grad:linear-gradient(180deg,rgba(19,42,65,.30),rgba(11,21,35,.35));
  --menu-grad:linear-gradient(180deg,rgba(15,29,46,.98),rgba(11,21,35,.98));
  /* Fully opaque menu surface — used where page content must not read through
     the panel (the avatar dropdown sits over dense tables and the map). */
  --menu-solid:linear-gradient(180deg,#0F1D2E,#0B1523);
  --modal-grad:linear-gradient(180deg,rgba(15,29,46,.99),rgba(11,21,35,.99));
  --input-bg:rgba(9,17,28,.7);
  --inset-bg:rgba(9,17,28,.4);
  --terms-bg:rgba(9,17,28,.6);
  --focus-ring:rgba(192,25,43,.4);
  --flash-bg:rgba(143,163,187,.06);
  --flash-ok-bg:rgba(63,157,107,.08);
  --flash-err-bg:rgba(192,25,43,.10);
  --badge-high-ink:#ffd3c2; --badge-high-line:rgba(228,87,46,.6); --badge-high-bg:rgba(228,87,46,.18);
  --badge-watch-ink:#f0d9a6; --badge-watch-line:rgba(217,164,65,.55); --badge-watch-bg:rgba(217,164,65,.16);
  --badge-clear-ink:#bfe6cf; --badge-clear-line:rgba(63,157,107,.5); --badge-clear-bg:rgba(63,157,107,.14);
  --badge-edit-ink:#c9b3e6; --badge-edit-line:rgba(150,110,210,.5);
  --badge-muted-bg:rgba(143,163,187,.08);
  --error-ink:#ffb3ba;
  --callout-amber-bg:rgba(217,164,65,.09); --callout-amber-tag-bg:rgba(217,164,65,.2);
  --callout-info-bg:rgba(143,163,187,.07); --callout-info-tag-bg:rgba(143,163,187,.15);
  /* Severity banner. Two named steps only — critical and elevated — because a
     briefing carries a banner only when a finding warrants one. */
  --severity-critical-ink:#ff4d6a; --severity-critical-line:rgba(255,77,106,.55);
  --severity-critical-bg:rgba(255,77,106,.10); --severity-critical-tag-bg:rgba(255,77,106,.22);
  --severity-elevated-ink:#ff9d4d; --severity-elevated-line:rgba(255,157,77,.55);
  --severity-elevated-bg:rgba(255,157,77,.10); --severity-elevated-tag-bg:rgba(255,157,77,.22);
  --combobox-bg:#0b1422;
  --combobox-line:rgba(255,255,255,.04);
  --combobox-sel-bg:rgba(192,25,43,.22);
  --modal-backdrop:rgba(5,10,17,.78);
  --shadow-pop:0 12px 30px rgba(0,0,0,.6);
  --shadow-tip:0 6px 16px rgba(0,0,0,.5);
  --shadow-list:0 10px 24px rgba(0,0,0,.5);
  --shadow-modal:0 24px 60px rgba(0,0,0,.55);
  --map-bg:#0b1422; --map-attr-bg:rgba(11,20,34,.8);
  --pin-rising-fill:#E11D2E; --pin-rising-stroke:#ff6b78;
  --pin-falling-fill:#3FB0AC; --pin-falling-stroke:#8ad6d3;
  --pin-stable-fill:#5b6670; --pin-stable-stroke:#8FA3BB;
  --pin-nodata-stroke:#6b7f98;
  --radar-line:#8FA3BB;
  --serif:'Libre Baskerville',Georgia,'Times New Roman',serif;
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  /* ---- Design-system type scale (8 steps, the ONLY UI text sizes) ---------
     Every font-size in the app resolves to one of these. Interface floor is
     11px micro / 12px label / 15px body. Serif steps carry headings/prose. */
  --fs-1:11px;   /* micro: legend, counts, tiny meta */
  --fs-2:12px;   /* label: eyebrow, field label, badge, button, helper */
  --fs-3:13px;   /* small: table cells, secondary body, hints */
  --fs-4:15px;   /* body (base) */
  --fs-5:18px;   /* lead: subsection title, docbar title, signal name */
  --fs-6:24px;   /* card / section title */
  --fs-7:34px;   /* page title, stat number */
  --fs-8:48px;   /* display */
  /* Back-compat aliases (older rules reference these) */
  --fs-label:var(--fs-2); --fs-sm:var(--fs-3); --fs-body:var(--fs-4);
  /* ---- Status scale (self-contained; NOT the brand crimson) --------------
     neutral/info, watch=amber, rising=red-orange, ok=green. */
  --status-neutral:var(--slate);
  --status-info:var(--teal);
  --status-watch:var(--amber);
  --status-rising:#E4572E;      /* red-orange — distinct from brand + danger */
  --status-ok:var(--green);
  /* ---- Destructive red (ONLY destructive actions; not brand, not status) - */
  --danger:#E5484D; --danger-bright:#F26D6D; --danger-ink:#ffd9dc;
  --danger-bg:rgba(229,72,77,.12); --danger-line:rgba(229,72,77,.55);
  /* ---- Role chip colour (never brand/destructive red) -------------------- */
  --role-chip:#8f7ad6;          /* muted violet */
  /* ---- Radius: one card, one control, plus pill; true circles use 50% ---- */
  --radius-card:0; --radius-control:0; --radius-pill:999px;
  /* ---- Spacing: single 4px-based scale ----------------------------------- */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:24px; --sp-6:32px; --sp-8:48px;
  --card-pad:20px;      /* one card padding */
  --gap-section:24px;   /* one section gap */
  --gap-field:16px;     /* one form-field gap */
  --gap-label:8px;      /* label-to-control gap */
  /* ---- Breakpoints: exactly three. @media can't read vars, so these are the
     ONLY three max-width values used anywhere: 640 / 900 / 1100. ----------- */
  --focus-w:2px;
  /* ---- Motion: ONE token scale ------------------------------------------
     Every duration, easing, delay and travel distance in the app comes from
     here — there are no literal ms/cubic-bezier values anywhere else, in CSS
     or in JS (JS reads these tokens through js/motion.js).
     Rules that go with the scale:
       · entering uses --ease-out; leaving uses --ease-in AND a shorter
         duration (--dur-fast) than its entrance;
       · nothing lasts longer than --dur-slow except the chart draw-in
         (--dur-chart) and the deliberately slow loader loop (--dur-loop);
       · --ease-emphasis is RESERVED for exactly three delight moments
         app-wide; it is defined here and spent nowhere else.
     Reduced motion (OS setting or the /account preference) is handled by
     flipping these tokens in ONE place — see the single reduced-motion block
     at the very end of this file. ---------------------------------------- */
  --dur-instant:80ms;  /* press dip, tooltip hide: felt, not seen */
  --dur-fast:140ms;    /* hover/focus colour, and every leaving transition */
  --dur-base:200ms;    /* default: menus, dropdowns, small entrances */
  --dur-slow:280ms;    /* largest surfaces: modals, scrim, page settle */
  --dur-chart:600ms;   /* data draw-in — the one duration above --dur-slow */
  --dur-loop:1400ms;   /* loading indicators (spinner / shimmer / pulse) */
  --dur-hold:1100ms;   /* how long a status highlight lingers before fading */
  --dur-sweep:2400ms;  /* brand radar: one revolution (read by radar.js) */
  --delay-0:0s;        /* explicit "no delay" so 0s is never a literal */
  --delay-tip:250ms;   /* tooltip open delay */
  /* Skeleton shell minimum on-screen time (anti-flicker, not an animation) —
     lives here so the loader in base.html has no literals either. */
  --dur-loader-min:250ms; --dur-loader-min-first:600ms;
  --ease-out:cubic-bezier(.25,.6,.3,1);      /* entering */
  --ease-in:cubic-bezier(.4,0,1,1);          /* leaving */
  --ease-in-out:cubic-bezier(.5,0,.5,1);     /* moving in place */
  --ease-emphasis:cubic-bezier(.2,1.5,.4,1); /* RESERVED — see note above */
  --ease-linear:linear;                      /* continuous loops only */
  /* Travel + scale. Reduced motion collapses every one of these to its
     resting value (0px / 1), which is what turns transform-based animation
     into a pure opacity fade without touching a single keyframe. */
  --motion-lift:-2px;    /* hover raise */
  --motion-rise:8px;     /* entrance travel */
  --motion-nudge:1px;    /* icon response travel */
  --motion-press:.96;    /* press scale */
  --motion-scale-in:.985;/* modal entrance scale */
  --motion-pop-from:.5;  /* confirmation pop: start */
  --motion-pop-peak:1.15;/* confirmation pop: overshoot */
  --motion-leave-to:.97; /* exit scale */
  --motion-focus-scale:1.015; /* focused editor block */
  --motion-grow-from:0;  /* chart bar draw-in start */
  --motion-pin-from:.6;  /* map marker / heat glow entrance scale */
  --motion-ring-to:2.4;  /* how far one selection ring pulse expands */
  --motion-stagger:40ms; /* list/step stagger step */
  /* Loader primitives, indirected so reduced motion swaps the keyframe
     (shimmer/spin -> pulse) instead of stopping the indicator dead. */
  --motion-spin:motionSpin;
  --motion-shimmer:motionShimmer;
  --motion-shimmer-x:-100%;
  --motion-loop-count:infinite;
  /* Reduced-motion values, named once here so the two switches at the end of
     the file only ROUTE them (and can't drift apart). */
  --dur-nil:1ms;         /* "already there" — feedback happens, at once */
  /* The slow "still working" pulse: the period of every live-activity
     indicator (so a busy app breathes rather than blinks), and what the spin
     and shimmer loops become under reduced motion. Deliberately >2s. */
  --dur-pulse:2800ms;
  --motion-still:0px;    /* every travel token collapses to this */
  --motion-flat:1;       /* every scale token collapses to this */
}

@media (prefers-color-scheme: light){
  :root{
    color-scheme:light;
    --bg:#F4F1EA; --bg-2:#ECE7DD; --panel:#FFFFFF; --panel-2:#ECE7DD;
    --line:rgba(43,58,74,.16); --line-strong:rgba(43,58,74,.32);
    --ink:#1C2733; --ink-strong:#000; --slate:#51637A; --slate-dim:#75859A;
    --crimson:#A81624; --crimson-bright:#C0192B; --amber:#D9A441; --teal:#2C817E; --green:#2E7D53;
    --amber-ink:#8A6414;
    --grid-line:rgba(43,58,74,.05);
    --bg-glow:rgba(192,25,43,.06);
    --hover-row:rgba(43,58,74,.05);
    --hover-tint:rgba(43,58,74,.07);
    --topbar-grad:linear-gradient(180deg,rgba(255,255,255,.94),rgba(247,244,238,.86));
    /* On paper the bar is the lightest surface, so the tab glass tints the
       other way — a cool wash that keeps inactive tabs, the bar and the warm
       (--bg) active tab three clearly separate surfaces. */
    --topbar-glass:blur(14px) saturate(1.25);
    --tab-blur:blur(9px) saturate(1.1);
    --tab-glass:rgba(43,58,74,.06);
    --tab-glass-hover:rgba(43,58,74,.12);
    --tabgroup-glass-teal:rgba(44,129,126,.12);
    --tabgroup-hover-teal:rgba(44,129,126,.20);
    --panel-grad:linear-gradient(180deg,rgba(255,255,255,.8),rgba(250,248,243,.92));
    --editsec-grad:linear-gradient(180deg,rgba(255,255,255,.7),rgba(248,245,239,.85));
    --docsheet-grad:linear-gradient(180deg,#FFFFFF,#FBF9F4);
    --menu-grad:linear-gradient(180deg,#FFFFFF,#FBF9F4);
    --menu-solid:linear-gradient(180deg,#FFFFFF,#FBF9F4);
    --modal-grad:linear-gradient(180deg,#FFFFFF,#FBF9F4);
    --input-bg:#FFFFFF;
    --inset-bg:rgba(43,58,74,.045);
    --terms-bg:#FCFAF5;
    --focus-ring:rgba(168,22,36,.3);
    --flash-bg:rgba(43,58,74,.06);
    --flash-ok-bg:rgba(46,125,83,.10);
    --flash-err-bg:rgba(168,22,36,.08);
    --badge-high-ink:#A63A17; --badge-high-line:rgba(196,70,31,.5); --badge-high-bg:rgba(196,70,31,.12);
    --badge-watch-ink:#7A5A10; --badge-watch-line:rgba(138,100,20,.5); --badge-watch-bg:rgba(217,164,65,.18);
    --badge-clear-ink:#1F6B45; --badge-clear-line:rgba(46,125,83,.45); --badge-clear-bg:rgba(63,157,107,.12);
    --badge-edit-ink:#5E3D8F; --badge-edit-line:rgba(110,70,180,.45);
    --badge-muted-bg:rgba(43,58,74,.07);
    --error-ink:#A81624;
    --callout-amber-bg:rgba(217,164,65,.14); --callout-amber-tag-bg:rgba(217,164,65,.3);
    --callout-info-bg:rgba(43,58,74,.06); --callout-info-tag-bg:rgba(43,58,74,.12);
    /* Light counterparts of the severity tokens: the dark #ff4d6a / #ff9d4d
       are unreadable on paper-white, so the ink darkens while the wash keeps
       the same hue. Declared here because [data-theme] selectors never match
       in this app — the theme switches on prefers-color-scheme alone. */
    --severity-critical-ink:#B3122B; --severity-critical-line:rgba(179,18,43,.5);
    --severity-critical-bg:rgba(255,77,106,.12); --severity-critical-tag-bg:rgba(255,77,106,.24);
    --severity-elevated-ink:#8A4A05; --severity-elevated-line:rgba(138,74,5,.45);
    --severity-elevated-bg:rgba(255,157,77,.16); --severity-elevated-tag-bg:rgba(255,157,77,.3);
    --combobox-bg:#FFFFFF;
    --combobox-line:rgba(0,0,0,.06);
    --combobox-sel-bg:rgba(168,22,36,.12);
    --modal-backdrop:rgba(28,39,51,.45);
    --shadow-pop:0 12px 30px rgba(30,40,50,.22);
    --shadow-tip:0 6px 16px rgba(30,40,50,.18);
    --shadow-list:0 10px 24px rgba(30,40,50,.18);
    --shadow-modal:0 24px 60px rgba(30,40,50,.25);
    --map-bg:#E8E4DA; --map-attr-bg:rgba(255,255,255,.8);
    --pin-rising-fill:#E11D2E; --pin-rising-stroke:#A81624;
    --pin-falling-fill:#2C817E; --pin-falling-stroke:#1E5D5B;
    --pin-stable-fill:#7B8794; --pin-stable-stroke:#51637A;
    --pin-nodata-stroke:#75859A;
    --radar-line:#5b7089;
    --status-rising:#C4461F;
    --danger:#CE2C31; --danger-bright:#B31E23; --danger-ink:#8E1220;
    --danger-bg:rgba(206,44,49,.09); --danger-line:rgba(206,44,49,.5);
    --role-chip:#6a52b0;
  }
}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
body{
  background:
    linear-gradient(var(--grid-line) 1px, transparent 1px) 0 0/26px 26px,
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px) 0 0/26px 26px,
    radial-gradient(1200px 600px at 80% -10%, var(--bg-glow), transparent 60%),
    var(--bg);
  color:var(--ink); font-family:var(--mono); font-size:var(--fs-4); line-height:1.55;
  display:flex; flex-direction:column; min-height:100vh;
}
a{color:var(--ink); text-decoration:none}
a:hover{color:var(--ink-strong)}
h1,h2,h3{font-family:var(--serif); font-weight:700; line-height:1.15; margin:0}

/* ---- Design-system base -------------------------------------------------- */
/* Native controls otherwise fall back to the browser default 13.333px in a
   system font (Times/Arial/Helvetica/Lucida). Force our fonts + type scale so
   nothing leaks — component classes with higher specificity still override. */
button,input,select,textarea,optgroup,option{font-family:var(--mono); font-size:var(--fs-4); line-height:1.4}
h1,h2,h3,h4,h5,h6{font-family:var(--serif)}

/* One consistent focus treatment everywhere (:where keeps specificity 0 so
   components can still opt into a tighter ring). */
:where(a,button,input,select,textarea,summary,[tabindex],[role="button"],[role="option"]):focus-visible{
  outline:var(--focus-w) solid var(--crimson); outline-offset:2px}

/* Styled checkbox — replaces the native tick so no default font/box leaks. */
input[type="checkbox"].ck,.ck{appearance:none; -webkit-appearance:none; flex:none;
  width:16px; height:16px; margin:0; border:1px solid var(--line-strong); background:var(--input-bg);
  border-radius:var(--radius-control); cursor:pointer; position:relative; display:inline-block;
  vertical-align:middle; transition:border-color var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out)}
/* The base rule above is qualified by `input[type="checkbox"]`, so the state
   rules must carry the same qualifier or they lose on specificity and every
   checkbox stays visually unchecked — a white tick on a white box. Keep the
   pair in lockstep with the base selector. */
input[type="checkbox"].ck:hover,.ck:hover{border-color:var(--slate)}
input[type="checkbox"].ck:checked,.ck:checked{
  background:var(--crimson); border-color:var(--crimson)}
/* The tick is a real SVG stroke (see ui.ck() in _macros.html) so it can draw
   itself in via stroke-dashoffset while the box background crossfades. The
   wrapper is only a positioning context: the tick never takes layout space or
   hit-testing, so the control's box stays exactly 16x16. */
.ck-box{position:relative; display:inline-flex; vertical-align:middle; flex:none}
.ck__tick{--ck-tick-len:14; position:absolute; left:0; top:0; width:16px; height:16px;
  pointer-events:none; fill:none; stroke:#fff; stroke-width:2.4;
  stroke-linecap:round; stroke-linejoin:round;
  stroke-dasharray:var(--ck-tick-len); stroke-dashoffset:var(--ck-tick-len);
  transition:stroke-dashoffset var(--dur-fast) var(--ease-out)}
.ck:checked + .ck__tick{stroke-dashoffset:0}
.ck:disabled{opacity:.5; cursor:default}
.ck:disabled + .ck__tick{opacity:.5}

/* Styled select — appearance stripped, themed arrow, our font on the control. */
select.select,select.input,select.thfilter{appearance:none; -webkit-appearance:none}

/* Truncation primitive: clips to one line but the full value is exposed via a
   title tooltip on hover/focus (paired with the `truncate` macro). */
.truncate{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%; display:inline-block; vertical-align:bottom}
.truncate:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}

/* Casing utilities — one rule per element type, applied via shared components. */
.u-eyebrow,.u-label,.u-badge,.u-btn{text-transform:uppercase; letter-spacing:.13em}
.u-title,.u-helper{text-transform:none; letter-spacing:0}


/* Layout */
.page{flex:1 0 auto; width:100%}
.container{max-width:1080px; margin:0 auto; padding:0 22px}
.mono-label{font-family:var(--mono); text-transform:uppercase; letter-spacing:.16em; font-size:var(--fs-2); color:var(--slate)}
.muted{color:var(--slate)}
.dim{color:var(--slate-dim)}
.mono{font-family:var(--mono)}

/* Topbar */
.topbar{border-bottom:1px solid var(--line); background:var(--topbar-grad); backdrop-filter:var(--topbar-glass); -webkit-backdrop-filter:var(--topbar-glass); position:sticky; top:0; z-index:20}
.topbar__inner{max-width:1180px; margin:0 auto; padding:12px 22px; display:flex; align-items:center; gap:26px}
.brand{display:flex; align-items:center; gap:12px}
.brand__text{display:flex; flex-direction:column; line-height:1}
.wordmark{font-family:var(--serif); font-size:var(--fs-6); font-weight:700; letter-spacing:.01em}
.wordmark__bio{color:var(--ink)}
.wordmark__radar{color:var(--crimson-bright)}
.radar{display:block; flex:0 0 auto}
.radar__sweep{transform-box:view-box; transform-origin:50% 50%}
.radar__blip{transition:opacity var(--dur-base) var(--ease-out)}
/* Bounded: the blip pings twice when the sweep actually starts (hover), then
   rests. Opacity only, so reduced motion needs no special case. */
.is-sweeping .radar__blip{animation:radarBlip var(--dur-slow) var(--ease-in-out) 2}
@keyframes radarBlip{0%,100%{opacity:.88}50%{opacity:.22}}
.nav{display:flex; gap:4px; margin-left:6px}
.nav a{font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate); padding:8px 12px; border:1px solid transparent}
.nav a:hover{color:var(--ink-strong); border-color:var(--line)}
.nav a.is-active{color:var(--ink-strong); border-color:var(--line-strong); background:var(--hover-tint)}
.topbar__right{margin-left:auto; display:flex; align-items:center; gap:12px}
.who{font-family:var(--mono); font-size:var(--fs-3); color:var(--slate); border-bottom:1px dotted var(--line-strong); padding-bottom:2px}
.usermenu{position:relative}
.usermenu__trigger{display:flex; align-items:center; gap:9px; font-family:var(--mono); font-size:var(--fs-3); letter-spacing:.02em; color:var(--slate); background:none; border:1px solid transparent; padding:7px 12px; cursor:pointer}
.usermenu__trigger:hover,.usermenu__trigger[aria-expanded="true"]{color:var(--ink-strong); border-color:var(--line)}
.usermenu__avatar{display:flex; align-items:center; justify-content:center; width:26px; height:26px; border:1px solid var(--line-strong); border-radius:50%; color:inherit; flex:0 0 auto}
/* User badge: avatar + shield role chip. Chip geometry scales off
   --avatar-size; the shield ring picks up --chip-ring so it blends with the
   surface behind it (page bg by default, overridden on panels/cards). */
.ubadge{position:relative; display:inline-flex; flex:0 0 auto; vertical-align:middle}
.ubadge__chip{position:absolute; right:calc(var(--avatar-size,26px) * -.15); bottom:calc(var(--avatar-size,26px) * -.15); width:calc(var(--avatar-size,26px) * .54); height:calc(var(--avatar-size,26px) * .58); user-select:none; pointer-events:auto}
.ubadge__chip svg{display:block; width:100%; height:100%; overflow:visible}
.ubadge__chip path{fill:var(--role-chip); stroke:var(--chip-ring,var(--bg)); stroke-width:1.5}
.ubadge__chip text{fill:#fff; font-family:var(--mono); font-size:var(--fs-2); font-weight:600}
.panel,.modal__panel,.usermenu__panel,.linkcard{--chip-ring:var(--panel)}
.cmt,.doc-sheet,.rail{--chip-ring:var(--bg-2)}
.rtable__idbadge{margin-right:8px}
.usermenu__caret{flex:0 0 auto; opacity:.7}
/* Opaque on purpose: the dropdown opens over tables, the map and the document
   sheet, and a translucent panel let all of that read through the menu. */
.usermenu__panel{position:absolute; right:0; top:calc(100% + 6px); min-width:238px; background:var(--menu-solid); border:1px solid var(--line-strong); box-shadow:var(--shadow-pop); padding:6px; z-index:30}
.avatar{--avatar-size:26px; display:inline-flex; align-items:center; justify-content:center; width:var(--avatar-size); height:var(--avatar-size); border-radius:50%; border:1px solid var(--line-strong); flex:0 0 auto; object-fit:cover; overflow:hidden}
.avatar--initials{font-family:var(--mono); font-size:calc(var(--avatar-size) * .38); letter-spacing:.04em; color:var(--ink-strong); background:var(--hover-tint); user-select:none}
/* Stretch both columns to equal height and let the last card in each column
   fill the leftover space, so the two columns end on the same baseline
   instead of leaving cards with mismatched heights. */
.accountgrid{display:grid; grid-template-columns:1fr 1fr; gap:26px; align-items:stretch; max-width:1020px}
.accountgrid .formwrap{max-width:none}
.accountgrid__col{display:flex; flex-direction:column; gap:26px; min-width:0}
.accountgrid__col>.formwrap:last-child{flex:1 0 auto}
@media (max-width:900px){.accountgrid{grid-template-columns:1fr}}
.input[readonly]{color:var(--slate-dim); background:var(--hover-tint); cursor:default}
.input[readonly]:focus{border-color:var(--line-strong); box-shadow:0 0 0 1px transparent}
.avatarrow{display:flex; align-items:center; gap:16px; margin-top:12px}
.avatarrow__actions{display:flex; align-items:center; gap:10px; flex-wrap:wrap}
.avatarrow__pick{cursor:pointer}
/* A picture staged for removal: the change only lands on save, so show it
   as pending rather than removing it from the page. */
.avatar.is-dimmed{opacity:.35}
.form--inline{display:inline-flex}
.usermenu__hdr{display:flex; align-items:center; gap:10px; padding:9px 12px 7px}
.usermenu__hdrtext{display:flex; flex-direction:column; gap:3px; min-width:0}
.usermenu__name{font-family:var(--mono); font-size:var(--fs-3); color:var(--ink)}
.usermenu__mail{font-family:var(--mono); font-size:var(--fs-2); color:var(--slate-dim)}
.usermenu__role{font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em; font-size:var(--fs-1); color:var(--slate-dim)}
.usermenu__panel a,.usermenu__signout{display:flex; align-items:center; gap:10px; width:100%; text-align:left; font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate); padding:9px 12px; border:1px solid transparent; background:none; cursor:pointer}
.usermenu__panel a .icon,.usermenu__signout .icon{flex:0 0 auto; opacity:.65}
.usermenu__panel a:hover,.usermenu__signout:hover{color:var(--ink-strong); border-color:var(--line)}
.usermenu__panel a:hover .icon,.usermenu__signout:hover .icon{opacity:1}
.usermenu__panel a.is-active{color:var(--ink-strong); border-color:var(--line-strong); background:var(--hover-tint)}
.usermenu__panel a.is-active .icon{opacity:1}
.sr-only{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0}
.usermenu__sep{border-top:1px solid var(--line); margin:6px 0}
/* The menu carries only top-level destinations, labelled in groups so the eye
   lands on an area before an item. Labels are decoration over the role="group"
   they name, so they are aria-hidden. */
.usermenu__grouplabel{font-family:var(--mono); text-transform:uppercase; letter-spacing:.16em; font-size:var(--fs-1); color:var(--slate-dim); padding:4px 12px 5px}

/* Muted padlock badge on user-menu items that need a higher role. Sits at the
   right edge of the item and carries an accessible "Admins only" hint. */
.usermenu__lock{display:inline-flex; align-items:center; margin-left:auto; color:var(--slate-dim); opacity:.65; flex:0 0 auto}
.usermenu__panel a:hover .usermenu__lock,.usermenu__panel a.is-active .usermenu__lock{opacity:.9}

/* ---- Breadcrumbs (nested pages) ---------------------------------------- */
.crumbs{display:flex; align-items:center; flex-wrap:wrap; gap:6px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate-dim); margin:0 0 18px}
.crumbs a{color:var(--slate)}
.crumbs a:hover{color:var(--ink-strong); text-decoration:underline}
.crumbs__sep{opacity:.5; user-select:none}
.crumbs__here{color:var(--ink)}

/* ---- Shared tabs / segmented control -----------------------------------
   The single tab component for the whole app (Data Sources views, Settings
   views, the comments rail, the requests status filter). See tabs.js. */
.tabs{margin:0 0 22px}
.tabs__list{display:flex; align-items:stretch; gap:2px; border-bottom:1px solid var(--line); overflow-x:auto; scrollbar-width:none}
.tabs__list::-webkit-scrollbar{display:none}
.tabs__tab{display:inline-flex; align-items:center; gap:8px; flex:0 0 auto; font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate); background:none; border:0; border-bottom:2px solid transparent; padding:10px 14px; margin-bottom:-1px; cursor:pointer; white-space:nowrap; text-decoration:none}
.tabs__tab .icon{flex:0 0 auto; opacity:.6}
.tabs__tab:hover{color:var(--ink-strong); background:var(--hover-tint)}
.tabs__tab:hover .icon{opacity:1}
.tabs__tab.is-active{color:var(--ink-strong); border-bottom-color:var(--crimson-bright)}
.tabs__tab.is-active .icon{opacity:1; color:var(--crimson-bright)}
.tabs__count{font-size:var(--fs-1); color:var(--slate-dim); border:1px solid var(--line); padding:1px 5px}
.tabs__tab.is-active .tabs__count{color:var(--ink); border-color:var(--line-strong)}
.tabs--rail{margin:0}
.tabs--rail .tabs__list{padding:0 4px}
.tabs--rail .tabs__tab{padding:9px 10px}

/* ---- Chrome-style topbar tabs (Settings views) --------------------------
   Rendered in the shared top bar, as ONE layered piece of glass rather than a
   row of chips pasted onto it. Three surfaces, deliberately distinct in both
   themes:
     · the bar itself — a translucent gradient over --topbar-glass;
     · inactive tabs and the two group shells — cut from that same material: a
       tint (--tab-glass / --tabgroup-glass-*) over their own --tab-blur, so
       page content still reads through them, blurred;
     · the active tab — the one opaque surface, filled with the page background
       (--bg) and flaring into the content below through its concave
       ::before/::after corners.
   Tabs live inline in the topbar row, between the brand and the account menu.
   The inner row switches to align-items:flex-end so the strip sits at the
   bottom edge; brand and topbar__right re-center themselves with align-self.
   The strip is flex:1 so it absorbs all available middle space and scrolls
   horizontally once it fills up, keeping the brand and user icon pinned. */
.topbar--tabbed{border-bottom:none}
.topbar--tabbed .topbar__inner{align-items:flex-end}
.topbar--tabbed .brand,.topbar--tabbed .topbar__right{align-self:center; flex-shrink:0}
/* Partial occupancy: the tabs fill only the LOWER band of the bar
   (--tabstrip-h of its ~62px), so the bar's own glass stays visible above
   them. Heights are explicit rather than padding-derived, because the group
   shells have to end on exactly the same baseline as the ungrouped tabs — the
   shell contributes --tabgroup-inset of itself above its members.
   The scrollbar is hidden — the strip is dragged/swiped, and tabs.js
   keeps the active tab in view. The 2px bottom padding keeps the flares' last
   pixel from being clipped by the overflow; the -15px pull (13 + that 2px)
   still merges the active tab into the content below. */
.topbar__tabs{--tabstrip-h:34px; --tabgroup-inset:3px;
  flex:1; min-width:0; display:flex; align-items:flex-end; gap:3px; margin:0 0 -15px; padding:0 12px 2px 0; overflow-x:auto; overflow-y:hidden; overscroll-behavior-x:contain; scrollbar-width:none; -ms-overflow-style:none}
.topbar__tabs::-webkit-scrollbar{display:none}
.topbar__tab{position:relative; display:inline-flex; align-items:center; gap:8px; height:var(--tabstrip-h); font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate); background:var(--tab-glass); backdrop-filter:var(--tab-blur); -webkit-backdrop-filter:var(--tab-blur); border:1px solid var(--line); border-bottom:none; border-radius:10px 10px 0 0; padding:0 18px; white-space:nowrap; cursor:pointer; transition:color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out), transform var(--dur-instant) var(--ease-out)}
.topbar__tab .icon{opacity:.55; transition:opacity var(--dur-fast) var(--ease-out)}
.topbar__tab:hover{color:var(--ink-strong); background:var(--tab-glass-hover); border-color:var(--line-strong)}
.topbar__tab:hover .icon{opacity:1}
/* Press dip, anchored at the baseline so a held tab never lifts off the bar's
   bottom edge. The open tab is excluded: it is merged into the page below, and
   scaling it would tear that seam open. */
.topbar__tab:not(.is-active):active{transform-origin:50% 100%; transform:scale(var(--motion-press))}
/* The active tab is opaque, so it needs no backdrop of its own — and it is the
   element the route/view transitions travel (see the route-transition block). */
.topbar__tab.is-active{color:var(--ink-strong); background:var(--bg); backdrop-filter:none; -webkit-backdrop-filter:none; border-color:var(--line-strong); z-index:2}
.topbar__tab.is-active .icon{opacity:1}
/* Concave bottom corners that flare the active tab into the content area. */
.topbar__tab.is-active::before,.topbar__tab.is-active::after{content:""; position:absolute; bottom:-1px; width:11px; height:11px; pointer-events:none}
.topbar__tab.is-active::before{left:-11px; background:radial-gradient(circle at top left, transparent 11px, var(--bg) 11px)}
.topbar__tab.is-active::after{right:-11px; background:radial-gradient(circle at top right, transparent 11px, var(--bg) 11px)}
.topbar__tab:focus-visible{outline:1px solid var(--crimson); outline-offset:-3px}

/* Tab groups — styled like Chrome tab groups. A solid colored label chip (the
   group color) sits inside a matching rounded outline together with the grouped
   tabs: teal for Briefing (Briefing settings / Template editor). The label
   collapses/expands the group, and only the active group is expanded, so the
   bar stays short as Settings grows; while collapsed only the chip shows.
   Automations and Data sources stay ungrouped Chrome-style tabs that merge into
   the content. The shell is glass like the tabs it holds — its tint is the
   group colour, so a group reads as a distinct area of Settings. */
.tabgroup{position:relative; display:inline-flex; align-items:stretch; align-self:flex-end; gap:3px; height:var(--tabstrip-h); margin-bottom:0; padding:var(--tabgroup-inset) 3px 0; border:1.5px solid var(--teal); border-bottom:none; border-radius:12px 12px 0 0; background:var(--tabgroup-glass-teal); backdrop-filter:var(--tab-blur); -webkit-backdrop-filter:var(--tab-blur)}
.tabgroup__label{display:inline-flex; align-items:center; gap:7px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; font-size:11.5px; font-weight:600; color:#04211f; background:var(--teal); border:0; border-radius:9px 9px 0 0; padding:0 13px; cursor:pointer; white-space:nowrap; transition:filter var(--dur-fast) var(--ease-out), transform var(--dur-instant) var(--ease-out)}
.tabgroup__label:hover{filter:brightness(1.07)}
.tabgroup__label:active{transform-origin:50% 100%; transform:scale(var(--motion-press))}
.tabgroup__label:focus-visible{outline:2px solid var(--teal); outline-offset:2px}
.tabgroup__caret{flex:none; transition:transform var(--dur-base) var(--ease-out)}
.tabgroup[data-open="false"] .tabgroup__caret{transform:rotate(-90deg)}
/* The reveal eases open and closed rather than snapping, so the tabs to the
   right of a group slide over instead of teleporting. This is the ONE place in
   the app that transitions a layout property: a group reveal is a width
   change, and expressing it as a transform would squash the labels inside it.
   It stays honest about the rest of the contract — bounded (max-width caps the
   travel), one-shot per click, and driven by the tokens, so both reduced-motion
   switches collapse it to --dur-nil like everything else. Entering eases out at
   --dur-base, leaving eases in at --dur-fast; the caret rides the same beat. */
.tabgroup__members{display:inline-flex; align-items:stretch; gap:3px; overflow:hidden; max-width:420px; opacity:1; transition:max-width var(--dur-base) var(--ease-out), margin-left var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out), visibility var(--delay-0) var(--ease-linear)}
.tabgroup[data-open="false"] .tabgroup__members{max-width:0; opacity:0; margin-left:-3px; visibility:hidden; transition:max-width var(--dur-fast) var(--ease-in), margin-left var(--dur-fast) var(--ease-in), opacity var(--dur-fast) var(--ease-in), visibility var(--delay-0) var(--ease-linear) var(--dur-fast)}
/* Grouped view tabs: top-rounded tabs that sit flush with the navbar edge.
   They stretch to the shell's inner height and carry no glass of their own —
   the shell already is the glass they sit in. */
.topbar__tab--grouped{height:auto; background:transparent; backdrop-filter:none; -webkit-backdrop-filter:none; border:1px solid transparent; border-bottom:none; border-radius:8px 8px 0 0; padding:0 13px; white-space:nowrap; flex:none}
.topbar__tab--grouped::before,.topbar__tab--grouped::after{display:none !important}
.topbar__tab--grouped:hover{background:var(--tabgroup-hover-teal); border-color:transparent}
.topbar__tab--grouped.is-active{color:var(--ink-strong); background:var(--bg); border-color:var(--line-strong); z-index:auto}
@media (prefers-color-scheme: light){
  .tabgroup__label{color:#fff}
}
/* With a group plus three peer tabs the bar has to give way before the brand
   and the account menu do: tighten, then drop the tab icons, then the labels of
   the collapsed group's peers stay — never wrap, which would break the flares. */
@media (max-width:1120px){
  .topbar__tabs{gap:2px}
  .topbar__tab{padding:0 12px; letter-spacing:.08em}
  .topbar__tab--grouped{padding:0 10px}
  .tabgroup__label{padding:0 10px; letter-spacing:.06em}
}
/* The Settings strip is wider than the space between the full wordmark and a
   named account trigger. Before hiding or clipping route tabs, reduce those
   two pieces to their already-recognisable icons. This keeps every settings
   destination pointer-reachable on ordinary laptop widths; narrower screens
   can still scroll the strip. */
@media (max-width:1300px){
  .topbar--tabbed .brand__text,
  .topbar--tabbed .usermenu__label,
  .topbar--tabbed .usermenu__caret{display:none}
  .topbar--tabbed .topbar__inner{gap:14px}
  .topbar--tabbed .usermenu__trigger{padding-inline:8px}
  .topbar--tabbed .topbar__tabs{gap:2px}
  .topbar--tabbed .topbar__tab{padding-inline:11px; letter-spacing:.07em}
  .topbar--tabbed .topbar__tab--grouped{padding-inline:9px}
  .topbar--tabbed .tabgroup__label{padding-inline:9px; letter-spacing:.05em}
}
@media (max-width:960px){
  .topbar__tab .icon{display:none}
}

.modal{position:fixed; inset:0; z-index:60; display:flex; padding:20px; overflow-y:auto}
.modal[hidden]{display:none}
.modal__backdrop{position:absolute; inset:0; background:var(--modal-backdrop); backdrop-filter:blur(3px)}
.modal__panel{position:relative; width:440px; max-width:100%; margin:auto; background:var(--modal-grad); border:1px solid var(--line-strong); box-shadow:var(--shadow-modal); padding:24px}
.modal__close{position:absolute; top:8px; right:8px; width:30px; height:30px; display:flex; align-items:center; justify-content:center; font-size:var(--fs-5); line-height:1; color:var(--slate); background:none; border:1px solid transparent; cursor:pointer}
.modal__close:hover{color:var(--ink-strong); border-color:var(--line)}
.inline{display:inline}
.topbar--viewer .topbar__inner{justify-content:space-between}

/* Footer */
.foot{flex-shrink:0; border-top:1px solid var(--line); margin-top:48px}
.foot__inner{max-width:1180px; margin:0 auto; padding:16px 22px; display:flex; justify-content:space-between; gap:12px; flex-wrap:wrap}
.foot__meta{font-family:var(--mono); font-size:var(--fs-2); color:var(--slate-dim)}

/* Eyebrow label with crimson rule */
/* .sec__eyebrow labels are fixed uppercase strings baked into the markup, so
   they keep the transform. .doc__eyebrow carries the *authored* document label
   (editable in the template editor), so it must render exactly as typed —
   forcing caps there made the field non-WYSIWYG.
   Both also double as real section headings (h2/h3) where they are the sole
   label for a landmark, so pin weight + line-height here — the h1/h2/h3 base
   rules would otherwise bold them and swap the mono face for the serif. */
.sec__eyebrow{text-transform:uppercase}
.sec__eyebrow,.doc__eyebrow{display:flex; align-items:center; gap:10px; font-family:var(--mono); font-weight:400; letter-spacing:.18em; font-size:var(--fs-2); color:var(--slate); margin-bottom:12px; line-height:1.3}
.sec__eyebrow .rule,.doc__eyebrow .rule{width:26px; height:2px; background:var(--crimson); display:inline-block}

/* Panels + bracket corners */
.panel{background:var(--panel-grad); border:1px solid var(--line); padding:var(--card-pad); position:relative; border-radius:var(--radius-card)}
/* One bracket component: crimson L-marks inset on ALL FOUR corners, drawn on a
   single non-interactive overlay so popovers/menus are never punched through
   and the marks never escape the card edge. */
.panel--bracket::before{content:""; position:absolute; inset:6px; pointer-events:none; z-index:0;
  --bk:14px; --bw:2px; --bc:var(--crimson);
  background:
    linear-gradient(var(--bc),var(--bc)) left top/var(--bk) var(--bw) no-repeat,
    linear-gradient(var(--bc),var(--bc)) left top/var(--bw) var(--bk) no-repeat,
    linear-gradient(var(--bc),var(--bc)) right top/var(--bk) var(--bw) no-repeat,
    linear-gradient(var(--bc),var(--bc)) right top/var(--bw) var(--bk) no-repeat,
    linear-gradient(var(--bc),var(--bc)) left bottom/var(--bk) var(--bw) no-repeat,
    linear-gradient(var(--bc),var(--bc)) left bottom/var(--bw) var(--bk) no-repeat,
    linear-gradient(var(--bc),var(--bc)) right bottom/var(--bk) var(--bw) no-repeat,
    linear-gradient(var(--bc),var(--bc)) right bottom/var(--bw) var(--bk) no-repeat}

/* Buttons — exactly four variants: (base) secondary, primary, ghost/tertiary,
   danger; plus size (--sm), layout (--block), disabled + loading states. */
.btn{display:inline-flex; align-items:center; justify-content:center; gap:8px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.13em; font-size:var(--fs-2); font-weight:500; padding:11px 18px; border:1px solid var(--line-strong); background:transparent; color:var(--ink); cursor:pointer; border-radius:var(--radius-control)}
.btn:hover{border-color:var(--slate); background:var(--hover-tint)}
/* Primary — the one brand crimson */
.btn--primary{background:var(--crimson); border-color:var(--crimson); color:#fff}
.btn--primary:hover{background:var(--crimson-bright); border-color:var(--crimson-bright)}
/* Secondary — outlined companion to a primary CTA; never a second crimson */
.btn--secondary{background:var(--panel-grad); border-color:var(--line-strong); color:var(--ink-strong)}
.btn--secondary:hover{border-color:var(--slate); background:var(--hover-tint)}
/* Tertiary / ghost — borderless */
.btn--ghost{background:transparent; border-color:transparent}
.btn--ghost:hover{background:var(--hover-tint); border-color:var(--line)}
/* Destructive — distinct danger red, never the brand crimson */
.btn--danger{background:transparent; border-color:var(--danger-line); color:var(--danger)}
.btn--danger:hover{background:var(--danger-bg); border-color:var(--danger); color:var(--danger-bright)}
.btn--danger .icon{opacity:.85}
.btn--sm{padding:7px 12px; font-size:var(--fs-2)}
.btn .icon{flex:0 0 auto; margin-top:-1px}
.btn--ghost .icon{opacity:.65; transition:opacity var(--dur-fast) var(--ease-out)}
.btn--ghost:hover .icon{opacity:1}
.btn--sm .icon{width:12px; height:12px}
.btn--block{width:100%}
/* Disabled */
.btn:disabled,.btn[disabled],.btn.is-disabled{opacity:.5; cursor:default; pointer-events:none}
/* Button loading state: the label crossfades to the app's one spinner IN
   PLACE. The label is never removed — only its colour goes transparent — so
   the button keeps exactly the width it had (no reflow, no jump), pointer
   events stop, and the focus ring is untouched (outline, not border).
   `.btn--busy` is the same state under an older name: one loading treatment,
   not two.
   Ring geometry + the spin itself come from the ONE spinner rule further
   down; here we only place it and pick its colour. */
.btn.is-loading,.btn.btn--busy{position:relative; color:transparent !important; pointer-events:none;
  transition:color var(--dur-base) var(--ease-out)}
.btn.is-loading .icon,.btn.btn--busy .icon{opacity:0; transition:opacity var(--dur-base) var(--ease-out)}
.btn.is-loading::after,.btn.btn--busy::after{content:""; position:absolute; left:50%; top:50%;
  --spin-size:14px; --spin-track:var(--slate); --spin-head:transparent;
  margin:calc(var(--spin-size) / -2) 0 0 calc(var(--spin-size) / -2)}
.btn--primary.is-loading::after,.btn--primary.btn--busy::after{--spin-track:rgba(255,255,255,.85)}
.btn--danger.is-loading::after,.btn--danger.btn--busy::after{--spin-track:var(--danger)}
.btn--sm.is-loading::after,.btn--sm.btn--busy::after{--spin-size:11px}

/* Flash */
.flashes{margin:20px auto 0}
.flash{border:1px solid var(--line-strong); border-left:3px solid var(--slate); padding:11px 14px; font-size:var(--fs-3); margin-bottom:10px; background:var(--flash-bg)}
.flash--success{border-left-color:var(--green); background:var(--flash-ok-bg)}
.flash--error{border-left-color:var(--crimson); background:var(--flash-err-bg)}

/* Page head */
.pagehead{display:flex; align-items:flex-end; justify-content:space-between; gap:16px; padding:34px 0 22px; flex-wrap:wrap}
.pagehead__title{font-size:var(--fs-7)}
.pagehead__actions{display:flex; gap:6px; flex-wrap:wrap; align-items:center}
/* Dashboard greeting header stacked above the relocated registry heading. */
/* When the header carries a description under the title, top-align the CTA so
   it sits beside the title rather than dropping to the description's baseline
   (which reads as a collision). */
.pagehead--desc{align-items:flex-start}
.pagehead--desc>:last-child{margin-top:4px}
.pagehead--greet{padding-bottom:18px}
.pagehead--sub{padding-top:10px; padding-bottom:18px}
.ovr + .pagehead--sub{padding-top:0}   /* overview already supplies the gap above the registry heading */
.pagehead__wave{font-size:.92em}

/* Stat strips */
.statstrip{display:grid; grid-template-columns:repeat(4,1fr); gap:1px; background:var(--line); border:1px solid var(--line); margin-bottom:26px}
.stat{background:var(--panel); padding:18px 20px}
.stat__num{font-family:var(--serif); font-size:var(--fs-7); font-weight:700; line-height:1}
.stat__num--alert{color:var(--crimson-bright)}
.stat__lab{font-family:var(--mono); text-transform:uppercase; letter-spacing:.16em; font-size:var(--fs-2); color:var(--slate); margin-top:8px}

/* Sections */
.sec{margin:30px 0}
.sec--method{opacity:.92}

/* Registry table */
.rtable{border:1px solid var(--line)}
.rtable__head,.rtable__row{display:grid; grid-template-columns:2.4fr .9fr 1fr .7fr 1.2fr 1.4fr; gap:12px; align-items:center; padding:13px 16px}
.rtable__head{background:var(--panel-2); font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em; font-size:var(--fs-2); color:var(--slate)}
.rtable__row{border-top:1px solid var(--line)}
.rtable__row:hover{background:var(--hover-row)}
.rtable__title{display:flex; flex-direction:column; gap:3px; font-family:var(--serif); font-size:var(--fs-4)}
.rtable__title em{font-family:var(--mono); font-style:normal; font-size:var(--fs-2); color:var(--slate); text-transform:uppercase; letter-spacing:.08em}
.rtable__actions{display:flex; gap:6px; justify-content:flex-end}
.rtable--history .rtable__head,.rtable--history .rtable__row{grid-template-columns:1fr .7fr 1.4fr 1.8fr 1.8fr 1.2fr}
.ver-pill--edit{color:var(--badge-edit-ink); border-color:var(--badge-edit-line)}

/* Registry — a real semantic <table> with sortable column headers.
   `table-layout:fixed` + the <colgroup> percentages below bind the table to the
   page column: the browser can no longer widen it past 100% to fit an
   unwrappable cell (author name, action labels, permalink), so its edges line up
   with every other Dashboard section and the page never scrolls sideways. */
.regtable{width:100%; max-width:100%; table-layout:fixed; border-collapse:collapse; border:1px solid var(--line)}
/* Shares of the page column. Sum to 100 with the author column present; for
   viewer accounts (no author column) fixed layout spreads the freed share
   across the rest. Retuned for the narrow desktop band further down. */
.regcol--title{width:18%}
.regcol--week{width:14%}
.regcol--status{width:10.5%}
.regcol--signals{width:9.5%}
.regcol--versions{width:10%}
.regcol--author{width:11%}
.regcol--created{width:9%}
.regcol--actions{width:18%}
.regtable thead th{background:var(--panel-2); text-align:left; padding:0; border-bottom:1px solid var(--line); font-family:var(--serif); font-weight:400; vertical-align:middle}
.regtable thead th:last-child{padding:13px 12px}   /* actions header (label is sr-only) */
.regtable__sort{display:flex; align-items:center; gap:6px; width:100%; padding:13px 12px; background:none; border:0; cursor:pointer;
  font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; font-size:var(--fs-2); color:var(--slate); text-align:left}
.regtable__sort:hover{color:var(--ink)}
/* Last-resort guard: a column label clips rather than pushing the table wider. */
.regtable__label{min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.regtable__arrow{flex:0 0 auto; font-size:var(--fs-2); line-height:1; opacity:.35}
.regtable__arrow::before{content:"\2195"}   /* ↕ */
.regtable th[aria-sort="ascending"] .regtable__sort,
.regtable th[aria-sort="descending"] .regtable__sort{color:var(--ink-strong)}
.regtable th[aria-sort="ascending"] .regtable__arrow,
.regtable th[aria-sort="descending"] .regtable__arrow{opacity:1; color:var(--crimson-bright)}
.regtable th[aria-sort="ascending"] .regtable__arrow::before{content:"\2191"}   /* ↑ */
.regtable th[aria-sort="descending"] .regtable__arrow::before{content:"\2193"}  /* ↓ */
.regtable tbody td{padding:13px 12px; border-top:1px solid var(--line); font-size:var(--fs-3); vertical-align:middle; overflow-wrap:break-word}
.regtable tbody tr:hover{background:var(--hover-row)}
.regtable tbody tr[hidden]{display:none}
.regtable .mono{white-space:nowrap}
/* Status/signal badges wrap onto a second line rather than push the column
   wider — the full label stays visible either way. */
.regtable .badge{letter-spacing:.07em; white-space:normal}
/* Week + readiness verdict. Stacked so "3 of 6 readings" and the READY /
   NOT READY badge sit under the week without widening the column. A not-ready
   row is muted with the existing vocabulary (slate ink + the muted badge), not
   a new colour. */
/* New-briefing readiness gate: the block message shown above the actions when
   the chosen week has not settled yet, plus its provisional escape hatch. */
.wkgate{border:1px solid var(--line-strong); background:var(--callout-info-bg); padding:12px 14px; margin:4px 0 14px}
.wkgate__msg{margin:0; font-size:var(--fs-3); color:var(--ink)}
.wkgate__override{margin-top:8px}
.regtable__note{font-size:var(--fs-2); margin:0 0 10px}
.regcell-week{min-width:0}
.regcell-week__link{display:block; font-family:var(--serif); font-size:var(--fs-4)}
.regcell-week__figures{display:block; font-size:var(--fs-1); letter-spacing:.04em; margin:2px 0 4px; white-space:normal}
.regcell-week.is-muted .regcell-week__link{color:var(--slate)}
.regtable tbody tr:has(.regcell-week.is-muted) td{color:var(--slate)}
.regcell-title{display:flex; flex-direction:column; gap:3px; min-width:0; font-family:var(--serif); font-size:var(--fs-4)}
.regcell-title em{font-family:var(--mono); font-style:normal; font-size:var(--fs-2); color:var(--slate); text-transform:uppercase; letter-spacing:.08em}
.regcell-perma{font-size:var(--fs-1); letter-spacing:.04em; word-break:break-all}
/* The cell itself stays a table-cell (so it centres in the row like the rest);
   the avatar+name row is an inner flex box. */
.regcell-author{min-width:0; white-space:normal}
.regcell-author__inner{display:flex; align-items:center; gap:8px; min-width:0}
/* Name wraps inside the column instead of widening it, and a pathologically
   long one (an email fallback) clamps to two lines; full value is on hover. */
.regcell-author .truncate{flex:0 1 auto; min-width:0; max-width:100%; white-space:normal; overflow-wrap:anywhere;
  display:-webkit-box; -webkit-box-orient:vertical; -webkit-line-clamp:2; line-clamp:2; overflow:hidden}
/* Relative dates are short, but an absolute fallback date is not — let it wrap
   (double class: must outrank `.regtable .mono`'s nowrap above). */
.regtable .regcell-created{white-space:normal}
/* Same table-cell rule as the author cell: the flex row lives in a wrapper so
   the buttons stay centred against rows that wrap to several lines. */
.regcell-actions{text-align:right}
.regcell-actions__inner{display:flex; gap:6px; justify-content:flex-end; flex-wrap:wrap}
.regcell-actions .btn--sm{padding:7px 9px; gap:7px; letter-spacing:.08em}

/* Narrow desktop band (901–1100px): the page column is tighter than the design
   width, so the least important content gives way — permalink line, action
   labels, header letter-spacing — instead of the table growing past the column.
   Placed before the 900px block so the stacked card layout still wins there. */
@media (max-width:1100px){
  .regcol--title{width:21%}
  .regcol--week{width:15%}
  .regcol--status{width:10.5%}
  .regcol--signals{width:10%}
  .regcol--versions{width:10.5%}
  .regcol--author{width:12.5%}
  .regcol--created{width:10%}
  .regcol--actions{width:10.5%}
  .regtable__sort{padding:13px 9px; letter-spacing:.05em; font-size:var(--fs-1)}
  .regtable thead th:last-child{padding:13px 9px}
  .regtable tbody td{padding:13px 9px}
  .regcell-perma{display:none}
  .regcell-actions .btn--sm{padding:7px 9px}
  .regcell-actions .btn__label{display:none}   /* aria-label keeps the action named */
}

/* --- Briefing editor --- */
.editor{display:flex; flex-direction:column; gap:22px; padding-bottom:40px}
.edit-sec{background:var(--editsec-grad); border:1px solid var(--line); padding:18px}
.edit-sec--ro{opacity:.85}
.edit-sec__head{display:flex; align-items:center; gap:10px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em; font-size:var(--fs-2); color:var(--slate); margin-bottom:12px}
.edit-sec__head .rule{display:inline-block; width:22px; height:2px; background:var(--crimson)}
.edit-list{display:flex; flex-direction:column; gap:10px; margin-bottom:12px}
.edit-item{display:flex; align-items:center; gap:10px; border:1px solid var(--line); padding:10px; background:var(--inset-bg)}
.edit-item--card{flex-direction:column; align-items:stretch; gap:10px}
.edit-item__row{display:flex; align-items:center; gap:10px}
.edit-item__row .input{flex:1}
.edit-item__grip{cursor:grab; color:var(--slate-dim); font-size:var(--fs-4); user-select:none; padding:0 4px; letter-spacing:-2px}
.edit-item.is-dragging{opacity:.5; border-color:var(--crimson)}
.edit-grid{display:grid; grid-template-columns:1fr 1fr; gap:12px}
.field--check{flex-direction:row; align-items:center; gap:10px}
.field--check input{width:auto}
.rte{background:var(--input-bg); border:1px solid var(--line-strong); color:var(--ink); font-size:var(--fs-4); padding:11px 13px; min-height:46px; line-height:1.55}
.rte:focus{outline:none; border-color:var(--crimson); box-shadow:0 0 0 1px var(--focus-ring)}
.rte ul,.rte ol{margin:6px 0 6px 20px}
.rte a{color:var(--crimson-bright)}
.rte__bar{display:flex; gap:4px; margin-bottom:6px; flex-wrap:wrap}
.rte__btn{font-family:var(--mono); font-size:var(--fs-2); padding:5px 9px; border:1px solid var(--line-strong); background:transparent; color:var(--slate); cursor:pointer}
.rte__btn:hover{border-color:var(--slate); color:var(--ink)}
.rte__btn.is-bold{font-weight:700} .rte__btn.is-italic{font-style:italic}
@media (max-width:640px){.edit-grid{grid-template-columns:1fr}}
.rtable--users .rtable__head,.rtable--users .rtable__row{grid-template-columns:24px minmax(0,1.6fr) minmax(0,1fr) minmax(0,.9fr) minmax(0,1.4fr) minmax(0,1fr)}
.rtable--users .rtable__head>span,.rtable--users .rtable__row>span{min-width:0; overflow:hidden; white-space:nowrap}
/* Title cell holds avatar + full email + "you" marker. Lay it out as a
   wrapping flex row so the email is never clipped to a bare "…" and the
   avatar stays vertically centred with the text. Higher specificity than the
   generic nowrap/overflow rule above so it wins regardless of order. */
.rtable--users .rtable__row>.rtable__title{display:flex; flex-direction:row; align-items:center; flex-wrap:wrap; gap:4px 8px; white-space:normal; overflow:visible; text-overflow:clip; position:relative}
.rtable--users .rtable__title em{margin-left:0}
.copy-email{background:none; border:0; padding:0; margin:0; font:inherit; color:inherit; cursor:pointer; text-align:left; overflow-wrap:anywhere; min-width:0}
.copy-email:hover{color:var(--crimson-bright); text-decoration:underline dotted}
.copy-email:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
.copyfb{position:absolute; right:6px; top:50%; transform:translateY(-50%); background:var(--combobox-bg); border:1px solid var(--badge-clear-line); color:var(--badge-clear-ink); font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.14em; padding:2px 6px; opacity:0; pointer-events:none; transition:opacity var(--dur-fast) var(--ease-out)}
.rtable__title.is-copied .copyfb{opacity:1}
.rtable--users .rtable__row>.rtable__actions{overflow:visible}
/* Per-row actions dropdown (Users page) */
.rowmenu{position:relative; display:inline-block}
.rowmenu__trigger{padding:6px 8px}
.rowmenu__panel{position:absolute; right:0; top:calc(100% + 4px); min-width:196px; background:var(--menu-grad); border:1px solid var(--line-strong); box-shadow:var(--shadow-pop); padding:6px; z-index:40; text-align:left}
.rowmenu__panel[hidden]{display:none}
.menu__item--danger{color:var(--error-ink)}
.menu__item--danger:hover{color:var(--crimson-bright); border-color:var(--badge-high-line); background:var(--flash-err-bg)}
.thfilter{appearance:none; background:transparent; border:0; color:inherit; font-family:inherit; font-size:inherit; text-transform:inherit; letter-spacing:inherit; cursor:pointer; padding:0 13px 0 0; max-width:100%; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 24 24' fill='none' stroke='%238FA3BB' stroke-width='3'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right center}
.thfilter:hover{color:var(--ink)}
.thfilter:focus-visible{color:var(--ink); outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
.thfilter.is-set{color:var(--crimson-bright)}
.thfilter option{background:var(--panel); color:var(--ink); text-transform:none; letter-spacing:normal; font-size:var(--fs-3)}
.bulkbar{display:flex; align-items:center; gap:12px; border:1px solid var(--line-strong); background:var(--flash-bg); padding:10px 14px; margin-bottom:12px}
.bulkbar__count{font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em; font-size:var(--fs-2); color:var(--slate); margin-right:auto}
.filterbar{display:flex; align-items:center; gap:10px; margin-bottom:12px; flex-wrap:wrap}
/* Double-class selector: must outrank the later `.input` background shorthand
   (which resets image/repeat/position) and `.input--sm` padding, so the icon
   and its inset survive regardless of rule order. */
.input.filterbar__search{flex:1 1 220px; padding-left:36px; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 24 24' fill='none' stroke='%238FA3BB' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='M21 21l-4.35-4.35'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:12px center}
.filterbar__meta{font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.14em; color:var(--slate-dim); margin-left:auto}
.input--sm{padding:8px 11px; font-size:var(--fs-3)}
select.input--sm{padding-right:34px}
.rtable__row[hidden]{display:none}
.rtable__empty{padding:22px 16px; font-family:var(--mono); font-size:var(--fs-3); color:var(--slate); border-top:1px solid var(--line)}
.modal__panel--sm{width:400px}

/* Share modal (people with access + share links) */
.modal__panel--share{width:600px; display:flex; flex-direction:column; gap:18px}
.sharebox{display:flex; flex-direction:column; gap:10px}
.sharebox__head{font-family:var(--serif); font-size:var(--fs-4); color:var(--ink-strong); border-bottom:1px solid var(--line); padding-bottom:6px}
.sharebox--reveal{border:1px solid var(--line-strong); padding:14px; gap:12px}
.sharepicker{display:flex; gap:8px; align-items:flex-start}
.sharepicker__box{flex:1}
.peoplelist{display:flex; flex-direction:column; max-height:264px; overflow-y:auto}
.peoplerow{display:flex; align-items:center; gap:10px; padding:8px 2px; border-bottom:1px solid var(--combobox-line)}
.peoplerow:last-child{border-bottom:none}
.peoplerow__who{flex:1; min-width:0; display:flex; flex-direction:column; line-height:1.3}
.peoplerow__who b{font-size:var(--fs-4); color:var(--ink-strong); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.peoplerow__who em{font-style:normal; font-family:var(--mono); font-size:var(--fs-2); color:var(--slate); overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.peoplerow__when{font-size:var(--fs-2); white-space:nowrap}
.sharecreate{display:flex; gap:8px; flex-wrap:wrap}
.sharecreate .input[name=label]{flex:1; min-width:160px}
.sharecreate .input[type=date]{width:150px}
.linklist--modal{max-height:320px; overflow-y:auto; display:flex; flex-direction:column; gap:10px; padding-right:2px}
.confirm__msg{margin:14px 0 0; font-size:var(--fs-4); color:var(--ink); line-height:1.55}
.confirm__actions{display:flex; gap:10px; justify-content:flex-end; margin-top:18px}
/* The shared region picker (templates/_region_select.html): the .mselect it
   wraps stays the positioning context for the dropdown, so the chips it
   renders underneath never push the panel down. */
.regionselect{min-width:0}
.mselect{position:relative}
.mselect__trigger{text-align:left; cursor:pointer; color:var(--slate)}
.mselect__trigger.has-value{color:var(--ink)}
.mselect__panel{position:absolute; top:100%; left:0; right:0; z-index:60; background:var(--combobox-bg); border:1px solid var(--line-strong); box-shadow:var(--shadow-list); padding:8px}
.mselect__panel[hidden]{display:none}
.mselect__list{max-height:210px; overflow-y:auto; margin-top:8px}
.mselect__opt{display:flex; gap:8px; align-items:center; padding:7px 8px; font-family:var(--mono); font-size:var(--fs-3); color:var(--ink); cursor:pointer}
.mselect__opt:hover{background:var(--combobox-sel-bg)}
.mselect__opt input{accent-color:var(--crimson); flex:0 0 auto}
.mselect__more{padding:7px 8px; font-family:var(--mono); font-size:var(--fs-2); color:var(--slate-dim)}
.mselect__chips{display:flex; flex-wrap:wrap; gap:6px; margin-top:8px}
.chip{display:inline-flex; align-items:center; gap:6px; border:1px solid var(--line-strong); background:var(--hover-tint); font-family:var(--mono); font-size:var(--fs-2); padding:4px 8px; color:var(--ink)}
.chip button{background:none; border:0; color:var(--slate); cursor:pointer; font-size:var(--fs-3); line-height:1; padding:0}
.chip button:hover{color:var(--crimson-bright)}

/* Badges + tags */
.badge{display:inline-block; font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; font-size:var(--fs-2); padding:4px 9px; border:1px solid var(--line-strong)}
.badge--high{color:var(--badge-high-ink); border-color:var(--badge-high-line); background:var(--badge-high-bg)}
.badge--watch{color:var(--badge-watch-ink); border-color:var(--badge-watch-line); background:var(--badge-watch-bg)}
.badge--clear{color:var(--badge-clear-ink); border-color:var(--badge-clear-line); background:var(--badge-clear-bg)}
.badge--muted{color:var(--slate); background:var(--badge-muted-bg)}
/* Role badge — a distinct role colour, never brand crimson or destructive red */
.badge--role{color:var(--role-chip); border-color:var(--role-chip); background:transparent}
.badge--status{white-space:nowrap}
.badge--status-draft{color:var(--slate); background:var(--badge-muted-bg)}
.badge--status-review{color:var(--badge-watch-ink); border-color:var(--badge-watch-line); background:var(--badge-watch-bg)}
.badge--status-approved{color:var(--badge-edit-ink); border-color:var(--badge-edit-line)}
.badge--status-published{color:var(--badge-clear-ink); border-color:var(--badge-clear-line); background:var(--badge-clear-bg)}

/* ---- Docs-style document workspace: docbar ------------------------------ */
/* Merged app header on briefing pages: logo + title row + Docs-style
   toolbar in one full-width sticky bar (replaces the standard topbar). */
.docbar{position:sticky; top:0; z-index:60; background:var(--topbar-grad); backdrop-filter:blur(12px); -webkit-backdrop-filter:blur(12px); border-bottom:1px solid var(--line)}
.docbar__inner{max-width:1180px; margin:0 auto; padding:8px 22px; display:flex; align-items:center; gap:16px}
.brand--doc{gap:9px; flex:none}
.brand--doc .wordmark{font-size:var(--fs-4)}
.brand__sub{font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.14em; text-transform:uppercase; color:var(--slate-dim); margin-top:2px; white-space:nowrap}
.docbar__titlewrap{min-width:0; flex:1}
.docbar__titlerow{display:flex; align-items:center; gap:10px; min-width:0}
.docbar__title{font-family:var(--serif); font-size:var(--fs-5); font-weight:400; color:var(--ink-strong); margin:0; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.docbar__meta{display:flex; align-items:center; gap:7px; font-size:var(--fs-2); color:var(--slate); letter-spacing:.05em; text-transform:uppercase; margin-left:4px; flex:0 1 auto; min-width:0; overflow:hidden; white-space:nowrap}
.docbar__tools .docbar__meta{margin-left:9px}
.docbar__dot{opacity:.6}
.docbar__pub{color:var(--green); display:inline-flex; align-items:center; gap:4px}
.docbar__right{display:flex; align-items:center; gap:8px; flex:none}
.docbar__tools{display:flex; align-items:center; gap:2px; margin:3px 0 0 -9px; flex-wrap:wrap}
.docbar__saved{font-size:var(--fs-1); color:var(--slate-dim); letter-spacing:.06em; text-transform:uppercase}
.docbar__tools .docbar__saved{margin-left:12px}
.toolbtn{display:inline-flex; align-items:center; gap:6px; font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.09em; text-transform:uppercase; color:var(--slate); padding:4px 9px; border:1px solid transparent; background:none; cursor:pointer; text-decoration:none; white-space:nowrap; transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out)}
.toolbtn:hover{color:var(--ink-strong); background:var(--hover-tint); border-color:var(--line)}
.toolbtn .icon{opacity:.65}
.toolbtn:hover .icon{opacity:1}

.iconbtn{position:relative; display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; border:1px solid var(--line); border-radius:50%; background:transparent; color:var(--slate); cursor:pointer; text-decoration:none; transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out)}
.iconbtn:hover{background:var(--hover-tint); color:var(--ink)}
.iconbtn.is-active{color:var(--crimson-bright); border-color:var(--line-strong); background:var(--hover-tint)}
.iconbtn__count{position:absolute; top:-5px; right:-6px; min-width:15px; height:15px; padding:0 4px; border-radius:8px; background:var(--crimson); color:#fff; font-family:var(--mono); font-size:var(--fs-1); line-height:15px; text-align:center}

/* Dropdown menu (review workflow) */
.menu{position:relative}
.menu__btn .icon{margin-left:5px}
.menu__pop{position:absolute; right:0; top:calc(100% + 6px); width:284px; background:var(--menu-grad); border:1px solid var(--line-strong); box-shadow:var(--shadow-pop); padding:13px; display:none; z-index:80}
/* .menu--closing keeps the panel painted for the length of its exit animation
   (docbar.js removes the class when the exit ends) — the panel is display:none
   at rest, so there is no invisible overlay hanging around. */
.menu--open .menu__pop,.menu--closing .menu__pop{display:block}
.menu--closing .menu__pop{pointer-events:none}
.menu__label{font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.16em; color:var(--slate-dim)}
.menu__hint{font-size:var(--fs-2); color:var(--slate); margin:6px 0 10px; line-height:1.45}
.menu__form{display:flex; flex-direction:column; gap:8px}
.menu__pop--items{width:224px; padding:8px}
.menu__pop--items .menu__label{padding:4px 10px 7px}
.menu__item{display:flex; align-items:center; gap:9px; width:100%; text-align:left; font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.09em; text-transform:uppercase; color:var(--slate); padding:8px 10px; border:1px solid transparent; background:none; cursor:pointer; text-decoration:none; white-space:nowrap; transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out)}
.menu__item:hover{color:var(--ink-strong); background:var(--hover-tint); border-color:var(--line)}
.menu__item .icon{flex:0 0 auto; opacity:.65}
.menu__item:hover .icon{opacity:1}
.menu--actions .menu__btn[aria-expanded="true"]{color:var(--ink-strong); background:var(--hover-tint); border-color:var(--line)}
.menu--actions .menu__pop{left:0; right:auto}
.btn--block{width:100%; justify-content:center}
.input--sm{padding:7px 9px; font-size:var(--fs-3)}

/* ---- Two-row Docs-style docbar (briefing view) --------------------------- */
.docbar--2row .docbar__row--info{border-bottom:1px solid var(--line)}
.docbar--2row .docbar__rowinner{max-width:1180px; margin:0 auto; padding:0 22px; display:flex; align-items:center; gap:10px; min-width:0}
.docbar__row--info .docbar__rowinner{padding-top:5px; padding-bottom:5px}
.docbar__row--actions .docbar__rowinner{padding-top:4px; padding-bottom:4px}
.docbar--2row .brand--doc{gap:7px; margin-right:14px}
/* Shrink-to-fit: the title ellipsizes (see .docbar__title) instead of pushing
   the saved indicator and user menu off the end of the row. */
.docbar--2row .docbar__title{flex:0 1 340px; min-width:96px; font-size:var(--fs-4); width:auto; max-width:340px}
.docbar--2row .docbar__right{margin-left:auto}
/* Editable title reads as a heading, not a search box: no visible box until
   the user hovers (subtle underline) or focuses to edit it. */
.docbar__title--edit{cursor:text; border:1px solid transparent; border-radius:0; padding:1px 6px; height:25px; line-height:21px; margin-left:-6px; transition:background var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out)}
.docbar__title--edit:hover{background:var(--hover-tint); border-bottom-color:var(--line-strong)}
.docbar__title--edit:focus-visible{background:var(--hover-tint); border-color:var(--line-strong)}
.docbar__titleinput{font-family:var(--serif); font-size:var(--fs-4); font-weight:400; color:var(--ink-strong); background:var(--hover-tint); border:1px solid var(--line-strong); border-radius:0; padding:1px 6px; height:25px; line-height:21px; margin-left:-6px; outline:none; width:340px; max-width:340px}
.docbar__titleinput:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
.verchip{display:inline-flex; align-items:center; gap:5px; font-size:var(--fs-2); color:var(--slate); letter-spacing:.05em; text-transform:uppercase; border:1px solid var(--line); border-radius:0; padding:4px 9px; white-space:nowrap; flex:none; cursor:default}
.verchip .icon{opacity:.6}
.docbar__row--actions{background:var(--hover-tint); border-bottom:1px solid var(--line)}
.strip{display:flex; align-items:center; gap:2px; padding:2px 0; height:40px; box-sizing:border-box}
.strip--bar{flex:1; min-width:0}
.strip__sep{width:1px; height:20px; background:var(--line-strong); margin:0 6px; flex:none}
.stripbtn{position:relative; display:inline-flex; align-items:center; justify-content:center; width:32px; height:32px; border:1px solid transparent; border-radius:0; background:none; color:var(--slate); cursor:pointer; text-decoration:none; flex:none; transition:background var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out)}
.stripbtn:hover{background:var(--line); color:var(--ink-strong)}
.stripbtn.is-active{color:var(--crimson-bright); background:var(--line); border-color:var(--line-strong)}
.stripbtn .iconbtn__count{top:-3px; right:-4px}
.strip__more{display:none}
.strip__transitions{margin-left:auto; display:flex; align-items:center; gap:7px; flex:none; padding-left:10px}
.strip__inlineform{display:flex; align-items:center; margin:0}
.strip__transitions .btn--sm{padding:6px 11px}
/* Legacy alias → single destructive treatment */
.btn--outline-danger{background:transparent; border-color:var(--danger-line); color:var(--danger)}
.btn--outline-danger:hover{background:var(--danger-bg); border-color:var(--danger); color:var(--danger-bright)}
.btn--outline-danger .icon{opacity:.85}

/* Danger zone card (account page) */
/* Danger zone uses the destructive red (distinct from brand crimson) so it
   reads as "careful" rather than "primary action". */
.panel--danger{border-color:var(--danger-line)}
.panel--danger .sec__eyebrow{color:var(--danger-bright)}
.panel--danger .sec__eyebrow .rule{background:var(--danger-bright)}

/* Tooltips: dark rounded bubble below the control, on hover and focus */
.tip{position:relative}
.tip::after{content:attr(data-tip); position:absolute; top:calc(100% + 7px); left:50%; transform:translateX(-50%); background:#0d1826; color:#f4f0e8; border:1px solid rgba(143,163,187,.25); border-radius:6px; padding:4px 9px; font-family:var(--mono); font-size:var(--fs-2); font-weight:400; letter-spacing:.05em; text-transform:none; white-space:nowrap; opacity:0; visibility:hidden; pointer-events:none; z-index:130}
/* Hover-intent (and the "no delay for the next one" grace window) is timed in
   micro.js, which adds .is-tip-open — so the tip fades in with no transition
   delay of its own, and dropping the class hides it instantly. Keyboard focus
   never waits. No movement: opacity only. */
.tip.is-tip-open::after,.tip:focus-visible::after{opacity:1; visibility:visible;
  transition:opacity var(--dur-instant) var(--ease-out)}
.tip--start::after{left:0; transform:none}
.tip--wide::after{white-space:normal; width:max-content; max-width:340px; line-height:1.5}

@media (max-width:900px){
  .strip .strip__collapsible{display:none}
  .strip__more{display:block}
  .docbar--2row .docbar__title{font-size:var(--fs-4); max-width:26vw}
  .docbar__titleinput{font-size:var(--fs-4); max-width:26vw}
  .strip__transitions .btn--sm{padding:5px 8px}
}
/* Document + comments rail layout.
   The sheet is a single centered, width-constrained column so a wide viewport
   no longer leaves a dead gutter. The comments rail is a right-side drawer
   (fixed overlay on wide screens, a stacked panel below the doc otherwise), so
   opening it never re-wraps the article or forces a scroll jump. */
.docwrap{display:flex; justify-content:center; gap:24px; align-items:flex-start; margin-top:18px}
.docmain{flex:1 1 auto; width:100%; max-width:960px; min-width:0}
.rail{display:none; flex-direction:column; background:var(--panel-grad); border:1px solid var(--line); overflow:hidden}
.docwrap--rail .rail{display:flex}
@media (min-width:1100px){
  /* Fixed right-side drawer: it overlays the page edge instead of taking flow
     space, so the article keeps its width (no reflow, no scroll jump). */
  .rail{position:fixed; top:110px; right:0; bottom:0; width:min(384px,40vw); z-index:70; border:0; border-left:1px solid var(--line-strong); box-shadow:var(--shadow-modal); transform:translateX(100%); transition:transform var(--dur-slow) var(--ease-out)}
  .docwrap--rail .rail{transform:none}
}
@media (max-width:1099px){
  .docwrap{flex-direction:column; align-items:center}
  .rail{width:100%; max-width:960px; max-height:520px}
}
.rail__tabs{display:flex; align-items:center; gap:2px; border-bottom:1px solid var(--line); padding:0 8px; flex:none}
/* The rail header owns the divider — the shared tabs list must not double it. */
.rail__tabs .tabs__list{border-bottom:0; flex:0 1 auto; min-width:0}
.rail__tab{background:none; border:none; border-bottom:2px solid transparent; margin-bottom:-1px; color:var(--slate); font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.12em; text-transform:uppercase; padding:11px 8px 9px; cursor:pointer}
.rail__tab.is-active{color:var(--ink-strong); border-bottom-color:var(--crimson)}
.rail__count{display:inline-block; min-width:16px; padding:1px 5px; border-radius:9px; background:var(--crimson); color:#fff; font-size:var(--fs-1); text-align:center}
.rail__count--dim{background:var(--badge-muted-bg); color:var(--slate)}
.rail__x{margin-left:auto; background:none; border:none; color:var(--slate-dim); cursor:pointer; padding:6px; display:inline-flex}
.rail__x:hover{color:var(--ink)}
.rail__panel{overflow-y:auto; padding:12px; display:flex; flex-direction:column; gap:10px}
.rail__hint,.rail__empty{font-size:var(--fs-2); color:var(--slate); line-height:1.55}
.rail__resolved summary{cursor:pointer; font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.12em; text-transform:uppercase; color:var(--slate-dim); padding:4px 0}
.rail__resolved .cmt{margin-top:8px; opacity:.8}

/* Comment composer */
.composer{display:flex; flex-direction:column; gap:7px; padding-bottom:11px; border-bottom:1px solid var(--line)}
.composer textarea{resize:vertical}
.composer__row{display:flex; gap:7px}
.composer__row select{flex:1; min-width:0}

/* Comment thread cards */
.cmt{border:1px solid var(--line); background:var(--inset-bg); padding:10px 11px; transition:border-color var(--dur-slow) var(--ease-out)}
.cmt--flash{border-color:var(--crimson-bright)}
/* Rail cards that can jump to their place in the document */
.cmt--jumpable{cursor:pointer}
.cmt--jumpable:hover{border-color:var(--line-strong); background:var(--hover-tint)}
.cmt--jumpable:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
/* Brief flash on the jump target (mark highlight or block) */
.cmt-flash{outline:2px solid var(--crimson-bright) !important; outline-offset:4px; transition:outline-color var(--dur-slow) var(--ease-out)}
.cmt__head{display:flex; align-items:center; gap:8px; min-width:0}
.cmt__who{display:flex; flex-direction:column; min-width:0; flex:1}
.cmt__name{font-size:var(--fs-3); font-weight:600; color:var(--ink-strong); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.cmt__time{font-size:var(--fs-1); color:var(--slate-dim); letter-spacing:.05em; text-transform:uppercase}
.cmt__chip{flex:none; border:1px solid var(--line-strong); background:var(--badge-muted-bg); color:var(--slate); font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.1em; text-transform:uppercase; padding:2px 7px; cursor:pointer}
.cmt__chip:hover{color:var(--ink)}
.cmt__body{font-size:var(--fs-3); line-height:1.55; color:var(--ink); margin-top:7px; white-space:pre-wrap; overflow-wrap:anywhere}
.cmt--resolved .cmt__body{color:var(--slate)}
.cmt__reply{margin-top:9px; padding:8px 0 0 10px; border-left:2px solid var(--line)}
.cmt__actions{display:flex; align-items:center; gap:12px; margin-top:9px; flex-wrap:wrap}
.cmt__inlineform{display:inline-flex; margin:0}
.cmt__link{display:inline-flex; align-items:center; gap:4px; background:none; border:none; padding:0; color:var(--slate); font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.1em; text-transform:uppercase; cursor:pointer}
.cmt__link:hover{color:var(--ink)}
.cmt__link--ok:hover{color:var(--green)}
.cmt__link--danger:hover{color:var(--crimson-bright)}
.cmt__resolvedby{display:inline-flex; align-items:center; gap:4px; font-size:var(--fs-1); color:var(--green); letter-spacing:.08em; text-transform:uppercase}
.cmt__replyform{display:flex; flex-direction:column; gap:6px; margin-top:8px}
.cmt__replyform .btn{align-self:flex-end}

/* Activity timeline (review trail) */
.tl{display:flex; flex-direction:column}
.tl__row{display:flex; gap:10px; padding:8px 0; border-bottom:1px dashed var(--line)}
.tl__row:last-child{border-bottom:none}
.tl__dot{flex:none; width:8px; height:8px; border-radius:50%; margin-top:5px; background:var(--slate-dim)}
.tl__dot--review{background:var(--amber)}
.tl__dot--approved{background:var(--teal)}
.tl__dot--published{background:var(--green)}
.tl__main{min-width:0}
.tl__act{font-size:var(--fs-3); color:var(--ink-strong)}
.tl__meta{font-size:var(--fs-1); color:var(--slate-dim); letter-spacing:.06em; margin-top:2px; text-transform:uppercase}
.tl__note{font-size:var(--fs-2); color:var(--slate); font-style:italic; margin-top:3px}

/* Per-section comment bubbles inside the document */
.cs-btn{display:none}
.docwrap--commentable .cs-btn{display:inline-flex; align-items:center; justify-content:center; width:22px; height:22px; margin-left:auto; border:1px solid var(--line); border-radius:50%; background:transparent; color:var(--slate-dim); cursor:pointer; opacity:0; transition:opacity var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out)}
.docwrap--commentable .sec:hover .cs-btn,.docwrap--commentable .callout:hover .cs-btn,.docwrap--commentable .cs-btn:focus-visible{opacity:1}
.cs-btn:hover{color:var(--crimson-bright); border-color:var(--line-strong)}
.callout{position:relative}
.callout .cs-btn{position:absolute; top:8px; right:8px}
.cs-flash{outline:2px solid var(--focus-ring); outline-offset:4px}

@media (max-width:900px){
  .docbar{position:static}
  .docbar__inner{flex-wrap:wrap; padding:10px 12px}
  .docbar__title{white-space:normal}
  .docbar__titlerow{flex-wrap:wrap}
  .docbar__meta{white-space:normal}
  .docbar__right{margin-left:auto}
  .brand--doc .brand__text{display:none}
}

/* Empty */
.empty{text-align:center; padding:40px 22px; display:flex; flex-direction:column; align-items:center; gap:16px; color:var(--slate)}
.empty__text{margin:0; font-size:var(--fs-4); line-height:1.5; max-width:46ch; color:var(--slate)}
.empty .icon{color:var(--slate-dim)}

/* Run list */
.runlist{display:flex; flex-direction:column; border:1px solid var(--line)}
.runrow{display:grid; grid-template-columns:.8fr 2fr 1.1fr 1.2fr auto; gap:12px; padding:12px 16px; border-top:1px solid var(--line); align-items:center}
.runlist .runrow:first-child{border-top:0}
.runrow:hover{background:var(--hover-row)}
.runrow--head{background:var(--panel-2); font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em; font-size:var(--fs-2); color:var(--slate)}
.runrow--head:hover{background:var(--panel-2)}
.runrow__status{font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); padding:3px 8px; border:1px solid var(--line-strong); justify-self:start}
.runrow--success .runrow__status{color:var(--badge-clear-ink); border-color:var(--badge-clear-line)}
.runrow--error .runrow__status{color:var(--badge-high-ink); border-color:var(--badge-high-line)}
.runrow--running .runrow__status,.runrow--pending .runrow__status{color:var(--badge-watch-ink); border-color:var(--badge-watch-line)}
.runrow__actions{justify-self:end}
.runlist__hint{font-size:var(--fs-2); color:var(--slate-dim); margin:-4px 0 12px}
.filterbar__select{flex:0 1 220px; min-width:160px}
.filterbar__select.is-set{color:var(--crimson-bright); border-color:var(--crimson)}
/* Sort control: on desktop the column headers sort; this select is the
   equivalent affordance once the header row collapses on small screens. */
.filterbar__sort{display:none}
@media (max-width:900px){.filterbar__sort{display:block; flex:1 1 100%}}
.rtable__empty .btn{margin-left:12px}

/* Forms */
.form{display:flex; flex-direction:column; gap:16px; margin-top:8px}
[hidden]{display:none !important} /* hidden attr must beat any display:flex/grid rule */
.field{display:flex; flex-direction:column; gap:7px}
.field__label{font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate)}
.field__hint,.hint{color:var(--slate-dim); font-size:var(--fs-2); text-transform:none; letter-spacing:0}
.fieldset{border:0; padding:0; margin:0; display:flex; flex-direction:column; gap:var(--gap-label)}
.radiorow{display:flex; gap:9px; align-items:flex-start; font-size:var(--fs-3); line-height:1.5; cursor:pointer}
/* Password field with a show/hide toggle */
.pwfield{position:relative; display:flex; align-items:center}
.pwfield .input{flex:1; min-width:0; padding-right:42px}
.pwtoggle{position:absolute; right:4px; top:50%; transform:translateY(-50%); background:none; border:0; padding:7px; color:var(--slate); cursor:pointer; display:inline-flex; align-items:center}
.pwtoggle:hover{color:var(--ink)}
.pwstrength{display:flex; flex-direction:column; gap:5px}
.pwstrength__bar{height:4px; background:var(--line); overflow:hidden}
/* Fill grows by scaleX, never by width: transform + colour only. */
.pwstrength__fill{display:block; height:100%; width:100%; background:var(--danger);
  transform:scaleX(0); transform-origin:left center;
  transition:transform var(--dur-base) var(--ease-out), background-color var(--dur-base) var(--ease-out)}
.pwstrength__fill.is-weak{transform:scaleX(.34); background:var(--danger)}
.pwstrength__fill.is-medium{transform:scaleX(.67); background:var(--amber)}
.pwstrength__fill.is-strong{transform:scaleX(1); background:var(--badge-clear-ink)}
.pwstrength__label{font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; font-size:var(--fs-1); color:var(--slate)}
/* The focus ring is declared transparent at rest so focusing only changes its
   COLOUR: the ring's offset and width never animate (and never shift layout). */
.input{background:var(--input-bg); border:1px solid var(--line-strong); color:var(--ink); font-family:var(--mono); font-size:var(--fs-4); padding:11px 13px; border-radius:0; width:100%; box-shadow:0 0 0 1px transparent}
/* Inline field validation. The message quotes the value actually in the field,
   so the feedback can never describe a different week than the one typed. */
.input[aria-invalid="true"]{border-color:var(--crimson-bright)}
.field__error{display:block; font-family:var(--mono); font-size:var(--fs-2); line-height:1.5;
  color:var(--crimson-bright); margin-top:6px}
.field__error[hidden]{display:none}
.input:focus{outline:none; border-color:var(--crimson); box-shadow:0 0 0 1px var(--focus-ring)}
.input--mono{font-size:var(--fs-3); color:var(--slate)}
select.input{appearance:none; background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none' stroke='%238FA3BB' stroke-width='2.4'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:right 13px center; padding-right:38px; cursor:pointer}
select.input option{background:var(--panel); color:var(--ink)}
.combobox{position:relative}
.combobox__list{display:none; position:absolute; top:100%; left:0; right:0; z-index:40; margin:0; padding:0; list-style:none; max-height:264px; overflow-y:auto; background:var(--combobox-bg); border:1px solid var(--crimson); border-top:none; box-shadow:var(--shadow-list)}
.combobox.is-open .combobox__list{display:block}
.combobox__option{font-family:var(--mono); font-size:var(--fs-3); color:var(--ink); padding:9px 13px; cursor:pointer; border-bottom:1px solid var(--combobox-line)}
.combobox__option:last-child{border-bottom:none}
.combobox__option:hover,.combobox__option.is-active{background:var(--combobox-sel-bg); color:var(--ink-strong)}
/* Week calendar picker */
/* In-flow (not absolute): the calendar is tall enough that an overlay escaped
   the form card and covered the reload button, the note field and the page
   footer. Opening it now grows the card instead. */
.wkcal__pop{display:none; position:static; margin-top:-1px; background:var(--combobox-bg); border:1px solid var(--crimson); border-top:none; box-shadow:var(--shadow-list); padding:10px 12px}
.combobox.is-open .wkcal__pop{display:block}
.wkcal__head{display:flex; align-items:center; justify-content:space-between; gap:6px; margin-bottom:8px}
.wkcal__title{font-family:var(--mono); font-size:var(--fs-3); letter-spacing:.12em; text-transform:uppercase; color:var(--ink); text-align:center; flex:1}
.wkcal__nav{display:flex; gap:3px}
.wkcal__btn{font-family:var(--mono); font-size:var(--fs-3); line-height:1; color:var(--slate); background:none; border:1px solid var(--line-strong); width:26px; height:24px; cursor:pointer; padding:0}
.wkcal__btn:hover{border-color:var(--slate); color:var(--ink); background:var(--hover-tint)}
.wkcal__msg{font-family:var(--mono); font-size:var(--fs-2); color:var(--amber-ink); border:1px solid var(--badge-watch-line); background:var(--badge-watch-bg); padding:7px 9px; margin-bottom:8px}
.wkcal__dow{display:grid; grid-template-columns:46px repeat(7,1fr); font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.12em; text-transform:uppercase; color:var(--slate-dim); padding:0 0 5px; border-bottom:1px solid var(--line)}
.wkcal__dow span{text-align:center}
.wkcal__dow span:first-child{text-align:left; padding-left:6px}
.wkcal__row{display:grid; grid-template-columns:46px repeat(7,1fr); align-items:center; border-bottom:1px solid var(--combobox-line)}
.wkcal__wk{font-family:var(--mono); font-size:var(--fs-2); padding:8px 0 8px 6px; color:var(--slate-dim)}
.wkcal__day{font-family:var(--mono); font-size:var(--fs-2); text-align:center; padding:8px 0; color:var(--ink)}
.wkcal__day--out{color:var(--slate-dim); opacity:.45}
.wkcal__row--ready{cursor:pointer}
.wkcal__row--ready .wkcal__wk{color:var(--badge-clear-ink)}
/* Partial: selectable (opt-in only) but still filling in — teal, plus a
   half-filled glyph so the state doesn't rest on colour alone. */
.wkcal__row--partial{cursor:pointer}
.wkcal__row--partial .wkcal__wk{color:var(--teal)}
.wkcal__row--partial .wkcal__wk::after{content:"\25D0"; font-size:8px; vertical-align:1px; margin-left:4px}
.wkcal__row--no .wkcal__wk{color:var(--amber-ink)}
.wkcal__row--no .wkcal__day,.wkcal__row--empty .wkcal__day{color:var(--slate-dim)}
.wkcal__row--empty .wkcal__wk{opacity:.5}
.wkcal__row--ready:hover,.wkcal__row--partial:hover,.wkcal__row.is-active{background:var(--combobox-sel-bg)}
.wkcal__row.is-selected{background:var(--combobox-sel-bg); box-shadow:inset 2px 0 0 var(--crimson)}
.wkcal__row--latest .wkcal__wk::after{content:"●"; font-size:6px; vertical-align:2px; margin-left:4px; color:var(--badge-clear-ink)}
.wkcal__info{font-family:var(--mono); font-size:var(--fs-2); color:var(--slate); padding:8px 2px 0; min-height:24px}
.wkcal__actions{display:flex; justify-content:space-between; align-items:center; gap:10px; border-top:1px solid var(--line); margin-top:8px; padding-top:9px; flex-wrap:wrap}
.wkcal__default{font-family:var(--mono); font-size:var(--fs-2); text-transform:uppercase; letter-spacing:.1em; color:var(--slate); background:none; border:1px solid var(--line-strong); padding:6px 10px; cursor:pointer}
.wkcal__default:hover{border-color:var(--slate); color:var(--ink); background:var(--hover-tint)}
.wkcal__legend{display:flex; gap:10px; font-family:var(--mono); font-size:var(--fs-1); text-transform:uppercase; letter-spacing:.08em; color:var(--slate-dim); align-items:center}
.wkcal__legend span{display:inline-flex; align-items:center; gap:5px}
.wkcal__legend-dot{color:var(--badge-clear-ink)}
.wkcal__sq{width:8px; height:8px; display:inline-block}
.wkcal__sq--ready{background:var(--green)}
.wkcal__sq--partial{background:linear-gradient(90deg,var(--teal) 50%,transparent 50%); box-shadow:inset 0 0 0 1px var(--teal)}
.wkcal__sq--no{background:var(--amber)}
.wkcal__sq--empty{background:var(--slate-dim)}
.wkcal__skelrow{padding:9px 6px; border-bottom:1px solid var(--combobox-line)}
/* Force-reload week data from the warehouse */
.wkreload{display:flex; align-items:center; gap:12px; flex-wrap:wrap}
/* Hidden for sources with no warehouse behind them (see week_picker.js). */
.wkreload[hidden]{display:none}
.wkreload__btn{display:inline-flex; align-items:center; gap:7px; font-family:var(--mono); font-size:var(--fs-1); text-transform:uppercase; letter-spacing:.1em; color:var(--slate); background:none; border:1px solid var(--line-strong); padding:6px 11px; cursor:pointer; border-radius:0;
  transition:color var(--dur-fast) var(--ease-out), background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out)}
.wkreload__btn:hover{border-color:var(--slate); color:var(--ink); background:var(--hover-tint)}
.wkreload__btn:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
.wkreload__btn .icon{flex:0 0 auto; opacity:.7}
.wkreload__btn:hover .icon{opacity:1}
.wkreload__btn:disabled{cursor:default; opacity:.6; color:var(--slate-dim)}
.wkreload__btn.is-loading .icon{animation:var(--motion-spin) var(--dur-loop) var(--ease-linear) var(--motion-loop-count)}
.wkreload__progress{flex:1 1 140px; min-width:120px; height:5px; background:var(--hover-tint); border:1px solid var(--combobox-line); overflow:hidden}
/* Indeterminate, not a fake 60s countdown: the warehouse pull reports no
   percentage, so the bar sweeps (transform only) while it runs. */
.wkreload__bar{position:relative; height:100%; width:100%; background:transparent; overflow:hidden}
.wkreload__bar.is-running::after{content:""; position:absolute; inset:0;
  background:linear-gradient(90deg,transparent,var(--crimson),transparent);
  transform:translateX(var(--motion-shimmer-x));
  animation:var(--motion-shimmer) var(--dur-loop) var(--ease-in-out) var(--motion-loop-count)}
.check{display:flex; align-items:center; gap:9px; font-size:var(--fs-3); color:var(--slate)}
.formwrap{max-width:640px}
.formwrap--narrow{max-width:460px}
.cols{display:grid; grid-template-columns:1fr 1.2fr; gap:26px; align-items:start}
.col{min-width:0}

/* Console (live generation) */
.console{padding:0; overflow:hidden}
.console__bar{background:var(--panel-2); border-bottom:1px solid var(--line); padding:11px 18px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em; font-size:var(--fs-2); color:var(--slate); display:flex; align-items:center; gap:10px}
/* Static "live" dot: the glow carries the meaning, so nothing blinks here. */
.blink{width:8px; height:8px; background:var(--crimson-bright); border-radius:50%; box-shadow:0 0 8px var(--crimson-bright)}
.steps{padding:8px 0}
.step{display:flex; gap:14px; padding:14px 20px; border-bottom:1px solid var(--line)}
.step:last-child{border-bottom:0}
.step__icon{flex:0 0 auto; width:18px; height:18px; margin-top:2px; border:2px solid var(--slate-dim); border-radius:50%; position:relative}
/* Running: the step's own ring becomes the shared spinner (size/colour only). */
.step--running .step__icon{--spin-size:18px; --spin-track:var(--amber); --spin-head:transparent}
.step--ok .step__icon{border-color:var(--green); background:var(--flash-ok-bg)}
.step--ok .step__icon::after{content:""; position:absolute; left:4px; top:0px; width:5px; height:10px; border:solid var(--green); border-width:0 2px 2px 0; transform:rotate(45deg)}
.step--error .step__icon{border-color:var(--crimson); background:var(--flash-err-bg)}
.step--error .step__icon::after{content:"!"; position:absolute; left:4px; top:-3px; color:var(--crimson-bright); font-weight:700}
.step__name{font-family:var(--serif); font-size:var(--fs-4); margin-bottom:3px}
.step--running .step__name{color:var(--ink)}
.step__lines{display:flex; flex-direction:column; gap:2px}
.step__line{font-family:var(--mono); font-size:var(--fs-3); color:var(--slate)}
.step--error .step__line{color:var(--error-ink)}
.final{padding:0 20px}
.final--ok,.final--error{padding:20px; border-top:1px solid var(--line)}
.final__title{font-family:var(--serif); font-size:var(--fs-5); margin-bottom:14px}
.final--error .final__title{color:var(--crimson-bright)}
.final__msg{font-family:var(--mono); font-size:var(--fs-3); color:var(--error-ink); margin-bottom:14px; white-space:pre-wrap}
/* Live sub-step lines (streamed narrative progress) */
.step__line--live{color:var(--ink)}
.step__line--live::before{content:"› "; color:var(--amber)}

/* AI narrative provenance (run console) + shipped-prompt disclosure (settings) */
.prov{margin-top:18px}
.prov__summary{font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate); cursor:pointer; display:flex; align-items:center; gap:10px; flex-wrap:wrap}
.prov__summary:hover{color:var(--ink-strong)}
.prov__badge{font-size:var(--fs-1); letter-spacing:.1em; padding:2px 8px; border:1px solid var(--line-strong)}
.prov__badge--llm{color:var(--green); border-color:var(--green)}
.prov__badge--det{color:var(--amber); border-color:var(--amber)}
.prov__body{margin-top:16px; display:flex; flex-direction:column; gap:6px}
.prov__h{font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-2); color:var(--slate); margin:14px 0 4px}
.prov__label{font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.1em; color:var(--slate-dim); text-transform:uppercase}
.prov__row{display:flex; gap:10px; font-size:var(--fs-3)}
.prov__k{font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.08em; text-transform:uppercase; color:var(--slate)}
.prov__pre,.prov__default .prov__pre{font-family:var(--mono); font-size:var(--fs-2); line-height:1.5; color:var(--ink); background:var(--panel-2); border:1px solid var(--line); padding:12px 14px; margin:0; white-space:pre-wrap; word-break:break-word; max-height:340px; overflow:auto}
.prov__default{margin-top:10px}
.prov__default summary{cursor:pointer}
.prov__ctx{margin:2px 0 0; padding-left:18px; display:flex; flex-direction:column; gap:4px; font-size:var(--fs-3); color:var(--ink)}
.prov__ctx li{list-style:square}
.input--mono{font-family:var(--mono); font-size:var(--fs-3); line-height:1.5}

/* Document */
.doc-toolbar{display:flex; align-items:center; justify-content:space-between; gap:14px; padding:26px 0 16px; flex-wrap:wrap}
.doc-toolbar__left{display:flex; align-items:center; gap:14px}
.doc-toolbar__actions{display:flex; gap:8px; flex-wrap:wrap}
.ver-pill{font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; font-size:var(--fs-2); padding:4px 10px; border:1px solid var(--line-strong); white-space:nowrap}
.ver-pill--current{color:var(--badge-clear-ink); border-color:var(--badge-clear-line)}
.ver-pill--old{color:var(--badge-watch-ink); border-color:var(--badge-watch-line)}
.doc-sheet{background:var(--docsheet-grad); border:1px solid var(--line); position:relative; padding:0}
.doc{padding:38px 44px 30px}
.doc__head{border-bottom:2px solid var(--crimson); padding-bottom:20px; margin-bottom:24px}
.doc__title{font-size:var(--fs-7); margin:6px 0 12px}
.doc__meta{display:flex; flex-wrap:wrap; align-items:center; gap:10px; font-family:var(--mono); font-size:var(--fs-2); color:var(--slate)}
.doc__meta .dot{width:3px; height:3px; background:var(--slate-dim); border-radius:50%; display:inline-block}
.statstrip--doc{margin:0 0 26px}
.lede{font-family:var(--serif); font-size:var(--fs-5); line-height:1.55; margin:0}
.lede b{color:var(--ink-strong)}
.disclaimer{font-family:var(--serif); font-style:italic; color:var(--slate); font-size:var(--fs-4); line-height:1.5; margin:0 0 14px}

/* Reference-format document chrome: masthead banner (theme-matched), metadata grid, footer */
.doc-banner{display:flex; align-items:center; justify-content:space-between; gap:20px;
  background:var(--panel-2); color:var(--ink); padding:22px 44px; margin:-38px -44px 26px;
  border-bottom:1px solid var(--line-strong)}
.doc-banner__mark{font-size:var(--fs-5); line-height:1}
/* Both lines are authored in the template editor (masthead tagline +
   confidential-use line), so they render as typed rather than force-capped. */
.doc-banner__sub{font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.14em;
  color:var(--slate); margin-top:8px}
.doc-banner__conf{font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.16em;
  color:var(--crimson-bright); margin-top:6px}
.doc-banner__radar{flex:0 0 auto}
.doc-grid{display:grid; grid-template-columns:1fr 1fr; gap:1px; margin:18px 0 2px;
  border:1px solid var(--line); background:var(--line)}
.doc-grid__cell{background:var(--panel); padding:10px 14px; display:flex; flex-direction:column; gap:3px}
.doc-grid__cell dt{font-family:var(--mono); font-size:var(--fs-1); letter-spacing:.16em;
  text-transform:uppercase; color:var(--slate-dim)}
.doc-grid__cell dd{margin:0; font-size:var(--fs-3); color:var(--ink); line-height:1.4}
.doc-caveat{margin:20px 0 4px}
.doc-foot{margin-top:34px; padding-top:16px; border-top:1px solid var(--line);
  font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.06em; color:var(--slate-dim);
  text-transform:uppercase; line-height:1.6}

/* Callouts */
.callout{display:flex; gap:14px; padding:14px 16px; border:1px solid var(--line-strong); margin:18px 0; align-items:flex-start}
.callout__tag{font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-1); padding:4px 8px; flex:0 0 auto}
.callout__body{font-size:var(--fs-3)}
.callout--amber{border-color:var(--badge-watch-line); background:var(--callout-amber-bg)}
.callout--amber .callout__tag{background:var(--callout-amber-tag-bg); color:var(--badge-watch-ink)}
.callout--info{border-color:var(--line-strong); background:var(--callout-info-bg)}
.callout--info .callout__tag{background:var(--callout-info-tag-bg); color:var(--slate)}
/* Severity banner — the same callout primitive, two named severities. */
.callout--critical{border-color:var(--severity-critical-line); background:var(--severity-critical-bg)}
.callout--critical .callout__tag{background:var(--severity-critical-tag-bg); color:var(--severity-critical-ink)}
.callout--elevated{border-color:var(--severity-elevated-line); background:var(--severity-elevated-bg)}
.callout--elevated .callout__tag{background:var(--severity-elevated-tag-bg); color:var(--severity-elevated-ink)}
.doc-severity{margin:20px 0 4px}

/* Unify narrative body prose to one serif treatment across every section
   (eyebrows, labels, meta, badges and the method thresholds keep their own
   explicit mono rules). */
.doc p,.doc .actions li,.doc .bullets li,.doc-table td{font-family:var(--serif)}

/* Signals */
.signals{display:flex; flex-direction:column; border:1px solid var(--line)}
.signal{display:flex; flex-direction:column; gap:12px; padding:16px 18px; border-top:1px solid var(--line); border-left:3px solid var(--slate-dim)}
.signals .signal:first-child{border-top:0}
.signal--high{border-left-color:var(--crimson)}
.signal--watch{border-left-color:var(--amber)}
.signal__row{display:flex; align-items:flex-start; justify-content:space-between; gap:18px}
.signal__name{font-family:var(--serif); font-size:var(--fs-5)}
.signal__sheds{font-family:var(--mono); font-size:var(--fs-2); color:var(--slate); margin-top:4px; text-transform:uppercase; letter-spacing:.06em}
/* Consistent card layout: a top row of severity/confidence badges, with the
   metric on its own line beneath — so every card's badges line up. */
.signal__tags{display:flex; flex-direction:column; align-items:flex-end; gap:6px; flex:none; text-align:right}
.signal__badges{display:flex; align-items:center; gap:10px}
.tag{font-family:var(--mono); font-size:var(--fs-2); text-transform:uppercase; letter-spacing:.1em; padding:3px 8px; border:1px dashed var(--line-strong); color:var(--slate)}
.tag--solid{border-style:solid; color:var(--ink)}
.metric{font-family:var(--mono); font-size:var(--fs-3); color:var(--ink)}

/* ---- Task 441: signal-first presentation ------------------------------- */
/* First-appearance acronym expansion chip — reuses the shared .tip primitive
   (hover intent + keyboard focus), rendered as a dotted-underlined term so a
   reader can tell an expansion is available without changing the prose. */
.acr{border-bottom:1px dotted var(--line-strong); cursor:help}
.acr:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
/* Threat-state cell colouring maps the five display states onto the existing
   status scale (no new hues): Risk/Alert = rising, Rising/Watch = watch,
   Easing/Watch = teal, Stable = neutral, No data = dim. */
.threat-state{font-family:var(--mono); font-size:var(--fs-2); text-transform:uppercase; letter-spacing:.08em; white-space:nowrap}
.threat-state--risk_alert{color:var(--status-rising)}
.threat-state--rising_watch{color:var(--status-watch)}
.threat-state--easing_watch{color:var(--status-info)}
.threat-state--stable{color:var(--slate)}
.threat-state--no_data{color:var(--slate-dim)}
/* A no-data pathogen row is visually de-emphasized (Task 441). */
.threat-row--nodata{opacity:.55}
.threat-panel td,.threat-cmp td{vertical-align:top}
/* Source-analysis subsections: one honest block per fixed category. A
   no-feed category is dimmed so a reader can see at a glance which of the five
   sources are wired up. */
.src-analysis{padding:12px 0; border-top:1px solid var(--line)}
.src-analysis:first-of-type{border-top:0}
.src-analysis__title{font-size:var(--fs-5); margin:0 0 4px}
.src-analysis__avail{margin:0 0 6px}
.src-analysis--no_feed{opacity:.6}
.feed-meta{margin-top:8px}

/* Task 446 — organism-coverage matrix. Every stored row is rendered; the
   trailing stable (non-priority) rows are hidden until the shared disclosure is
   opened, keeping priority findings scannable on screen without dropping any
   data. `is-cov-expanded` is toggled by micro.js in step with the disclosure. */
.org-cov__row--stable{display:none}
.is-cov-expanded .org-cov__row--stable{display:table-row}
.org-cov__more{margin:8px 0 4px}
.org-cov__more > summary{font-family:var(--mono); font-size:var(--fs-2);
  text-transform:uppercase; letter-spacing:.06em; color:var(--slate)}
.org-cov__more-note{margin:6px 0 0; font-size:var(--fs-2)}
.org-cov__assay{margin-top:10px}
.org-cov td .tag--solid{margin-left:6px; vertical-align:middle}
/* Numeric current-week value column: mono for legible number alignment. */
.org-cov__value{font-family:var(--mono); font-size:var(--fs-2); white-space:nowrap}
/* NOT DETECTED / NOT IN PANEL rows are de-emphasized (same treatment the
   no-data projection row uses) so the reader's eye stays on measured findings. */
.org-cov__row--muted{opacity:.55}
/* Wastewater-incompatible priorities carry an intended-coverage explanation
   (public datasets) so an incompatible organism is caveated, never dropped. */
.org-cov__incompat{margin-left:6px; vertical-align:middle}
.org-cov__intended{margin-top:3px; font-size:var(--fs-2); font-style:italic}
/* Print / PDF (browser Ctrl-P of the web view): reveal the whole panel — the
   stable rows are shown and the disclosure is neutralised so nothing is
   truncated on paper. The server-side reportlab PDF renders all rows directly. */
@media print{
  .org-cov__row--stable{display:table-row !important}
  .org-cov__more{display:none !important}
}

/* Per-pathogen trend sparkline (see signal_trend macro / editor.js signalTrendEl) */
.sig-trend{margin-top:2px; --sig-area-op:.15}
.sig-trend--high{--sig-line:var(--crimson-bright); --sig-fill:var(--crimson)}
.sig-trend--watch{--sig-line:var(--amber); --sig-fill:var(--amber)}
/* No load animation here: the sparkline draws itself in when its card first
   scrolls into view (see dataviz.js / the draw-in rules further down). */
.sig-trend__svg{width:100%; height:auto; display:block; overflow:visible}
.sig-trend__area{fill:var(--sig-fill); opacity:var(--sig-area-op); stroke:none}
.sig-trend__line{fill:none; stroke:var(--sig-line); stroke-width:2.5; stroke-linejoin:round; stroke-linecap:round}
.sig-trend__base{stroke:var(--grid-line); stroke-width:1; stroke-dasharray:3 4}
.sig-trend__grid{stroke:var(--grid-line); stroke-width:1; opacity:.55}
.sig-trend__dot{fill:var(--sig-line); stroke:var(--bg); stroke-width:2.5}
/* Invisible per-week hit targets that reveal a value tooltip on hover. */
.sig-trend__pt{fill:transparent}
.sig-trend__pt:hover{fill:var(--sig-line); fill-opacity:.22}
.sig-trend__ylab{fill:var(--slate-dim); font-family:var(--mono); font-size:var(--fs-1)}
.sig-trend__vlab{fill:var(--sig-line); font-family:var(--mono); font-size:var(--fs-2); font-weight:600}
.sig-trend__xlab{fill:var(--slate); font-family:var(--mono); font-size:var(--fs-2)}
.sig-trend__cap{font-family:var(--mono); font-size:var(--fs-1); text-transform:uppercase; letter-spacing:.08em; color:var(--slate-dim); margin-top:4px}

/* Bullets / actions */
.bullets,.actions{margin:0; padding-left:0; list-style:none; counter-reset:a}
.bullets li{position:relative; padding:8px 0 8px 22px; font-size:var(--fs-4); line-height:1.5; border-bottom:1px solid var(--line)}
.bullets li:last-child{border-bottom:0}
.bullets li::before{content:""; position:absolute; left:2px; top:15px; width:7px; height:7px; background:var(--crimson); }
.actions li{position:relative; padding:12px 0 12px 40px; counter-increment:a; border-bottom:1px solid var(--line); line-height:1.55; font-size:var(--fs-4)}
.actions li:last-child{border-bottom:0}
.actions li::before{content:counter(a,decimal-leading-zero); position:absolute; left:0; top:12px; font-family:var(--mono); color:var(--crimson-bright); font-size:var(--fs-3); letter-spacing:.05em}
.actions b,.bullets b{color:var(--ink-strong)}
.method{font-size:var(--fs-3); color:var(--slate); line-height:1.6; margin:0}
.method b{color:var(--ink)}

/* Provenance */
.provenance{border-top:1px solid var(--line); background:var(--inset-bg); padding:16px 44px; display:flex; flex-wrap:wrap; gap:8px 28px; font-family:var(--mono); font-size:var(--fs-2); color:var(--slate)}
.provenance .k{color:var(--slate-dim); text-transform:uppercase; letter-spacing:.12em; margin-right:8px}
.provenance__note{flex-basis:100%}
.provenance--viewer{justify-content:flex-start}

/* Auth cards */
.auth .page{display:flex; align-items:center; justify-content:center; padding:40px 20px}
.authcard{width:100%; max-width:430px; margin:40px auto}
.authcard__brand{display:flex; align-items:center; gap:14px; margin-bottom:22px}
.authcard__title{font-size:var(--fs-6); margin:4px 0 16px}
.errorcard{text-align:center}
.errorcard__code{font-family:var(--serif); font-size:var(--fs-8); color:var(--crimson-bright); line-height:1; margin:10px 0}
.errorcard__msg{color:var(--slate); margin-bottom:20px}
/* Error/404 page: rendered inside the app shell, so it is a centered card in
   the normal content column rather than a standalone auth screen. */
.errorpage{max-width:520px; margin:40px auto; padding:34px 30px}
.errorpage__brand{justify-content:center}
.errorpage__actions{display:flex; justify-content:center; gap:12px; flex-wrap:wrap}

/* Share links */
.linklist{display:flex; flex-direction:column; gap:14px}
.linkcard{border:1px solid var(--line); padding:16px; display:flex; flex-direction:column; gap:10px}
.linkcard--revoked{opacity:.55}
.linkcard__top{display:flex; align-items:center; justify-content:space-between; gap:10px}
.linkcard__label{font-family:var(--serif); font-size:var(--fs-4)}
.linkcard__actions{display:flex; gap:8px; flex-wrap:wrap; align-items:center}

/* One-time credential reveal modal */
.modal-backdrop{position:fixed; inset:0; z-index:100; background:var(--modal-backdrop); backdrop-filter:blur(3px);
  display:flex; align-items:center; justify-content:center; padding:20px}
.reveal-box{width:100%; max-width:520px; background:var(--panel); display:flex; flex-direction:column; gap:16px}
.reveal-box__title{font-size:var(--fs-6)}
.reveal-box__warn{margin:0}
.copyrow{display:flex; gap:8px}
.copyrow .input{flex:1; min-width:0}
.reveal-pw{font-size:var(--fs-4); color:var(--ink); letter-spacing:.04em}

/* Audit scope banner */
.auditscope a{border-bottom:1px dotted var(--line-strong); color:var(--ink)}
.auditscope a:hover{color:var(--ink-strong)}

/* Filter chips + audit */
.filterbar{display:flex; flex-wrap:wrap; gap:8px; margin-bottom:20px}
.chip{font-family:var(--mono); text-transform:uppercase; letter-spacing:.1em; font-size:var(--fs-2); padding:6px 11px; border:1px solid var(--line); color:var(--slate)}
.chip:hover{border-color:var(--line-strong); color:var(--ink-strong)}
.chip.is-active{background:var(--crimson); border-color:var(--crimson); color:#fff}
/* Segmented filter (shared across admin status filters) */
.auditfilters{display:flex; flex-wrap:wrap; gap:14px; align-items:flex-end; margin-bottom:14px; padding:14px 16px; border:1px solid var(--line); background:var(--panel-2)}
.auditfilters__field{display:flex; flex-direction:column; gap:5px; flex:1 1 180px; min-width:160px}
.auditfilters__field label{font-family:var(--mono); text-transform:uppercase; letter-spacing:.13em; font-size:var(--fs-2); color:var(--slate)}
.auditfilters__actions{flex:0 0 auto}
.auditapplied{display:flex; flex-wrap:wrap; gap:8px; align-items:center; margin-bottom:16px}
.auditapplied__label{font-family:var(--mono); text-transform:uppercase; letter-spacing:.13em; font-size:var(--fs-2); color:var(--slate)}
.auditapplied .chip{display:inline-flex; align-items:center; gap:7px; text-transform:none; letter-spacing:.04em; font-size:var(--fs-2)}
.chip__x{color:inherit; font-size:var(--fs-3); line-height:1; text-decoration:none; opacity:.8}
.chip__x:hover{opacity:1}
.auditapplied__clearall{text-transform:uppercase}
/* Quick-filter links: clickable, but not styled as navigation links (no
   persistent underline). The underline only appears on hover to signal the
   affordance, so IPs/emails/action names read as plain data at rest. */
.quickfilter{color:inherit; text-decoration:none; cursor:pointer}
.quickfilter:hover,.quickfilter:focus-visible{color:var(--ink-strong); text-decoration:underline; text-decoration-color:var(--crimson); text-underline-offset:2px}
.auditlist__cellabel{display:none}
.auditlist{border:1px solid var(--line)}
/* Long, endlessly-scrolled lists: skip rendering off-screen rows. The
   intrinsic size keeps the scrollbar honest while they are skipped. */
.auditlist__row,
.rtable--dsrcobjs .rtable__row,
.rtable--dsrcmanage .rtable__row{content-visibility:auto; contain-intrinsic-size:auto 46px}
.auditlist__head span,.auditlist__row>span{min-width:0; overflow-wrap:anywhere}
.auditapplied .chip{max-width:100%; overflow-wrap:anywhere}
.auditlist__sentinel{border-top:1px solid var(--line); padding:12px 16px; display:flex; align-items:center; justify-content:center; gap:8px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.13em; font-size:var(--fs-2); color:var(--slate)}
.auditlist__sentinel a{color:var(--slate)}
.auditlist__sentinel .icon{display:none; flex:none}
.auditlist__sentinel.is-loading .icon{display:inline-block; animation:var(--motion-spin) var(--dur-loop) var(--ease-linear) var(--motion-loop-count)}
.auditlist__head,.auditlist__row{display:grid; grid-template-columns:1.5fr 1.6fr 1.4fr 1.1fr 2.6fr; gap:14px; padding:11px 16px; align-items:start}
.auditlist__head{background:var(--panel-2); font-family:var(--mono); text-transform:uppercase; letter-spacing:.13em; font-size:var(--fs-2); color:var(--slate)}
.auditlist__row{border-top:1px solid var(--line); font-size:var(--fs-3)}
/* ACTOR cell stays on one line: type chip + badge + name in a nowrap row,
   the name truncating rather than pushing the row to two lines. */
.auditlist__actor{display:flex; align-items:center; gap:7px; flex-wrap:nowrap}
.auditlist__actorname{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; min-width:0}
.actor{flex:none; font-family:var(--mono); text-transform:uppercase; letter-spacing:.08em; font-size:var(--fs-1); padding:2px 6px; border:1px solid var(--line-strong)}
.actor--admin{color:var(--badge-clear-ink); border-color:var(--badge-clear-line)}
.actor--viewer{color:var(--badge-watch-ink); border-color:var(--badge-watch-line)}
.actor--system{color:var(--slate)}
/* DETAIL cell: readable key/value pairs, not raw JSON. */
.audit-detail{overflow-wrap:anywhere}
.audit-detail__k{font-family:var(--mono); text-transform:uppercase; letter-spacing:.07em; font-size:var(--fs-1); color:var(--slate)}
.audit-detail__v{color:var(--ink)}
.audit-detail__sep{color:var(--line-strong); margin:0 5px}

@media (max-width:900px){
  .cols{grid-template-columns:1fr}
  .rtable__head{display:none}
  .rtable__row,
  .rtable--history .rtable__row,.rtable--users .rtable__row,
  .rtable--automations .rtable__row,.rtable--dsrc .rtable__row,.rtable--dsrcweeks .rtable__row,
  .rtable--dsrcobjs .rtable__row,.rtable--dsrcman .rtable__row{grid-template-columns:1fr 1fr; gap:8px}
  .rtable__actions{grid-column:1 / -1; justify-content:flex-start}
  /* Registry table -> stacked cards, each value keeping its column label. */
  .regtable{border:0}
  .regtable thead{position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap}
  .regtable, .regtable tbody, .regtable tr, .regtable td{display:block; width:auto}
  .regtable tbody tr{border:1px solid var(--line); margin-bottom:10px}
  .regtable tbody td{border-top:0; padding:7px 16px}
  .regtable tbody td:first-child{padding-top:13px}
  .regtable tbody td:last-child{padding-bottom:13px}
  .regtable tbody td::before{content:attr(data-label); display:block; font-family:var(--mono); text-transform:uppercase; letter-spacing:.13em; font-size:var(--fs-1); color:var(--slate); margin-bottom:3px}
  .regcell-actions{text-align:left}
  .regcell-actions__inner{justify-content:flex-start}
  .regcell-actions .btn__label{display:inline}   /* room again in card layout */
  .regcell-perma{display:block}
  .regcell-author .truncate{max-width:100%}
  .auditlist__head{display:none}
  .auditlist__row{grid-template-columns:1fr; gap:4px}
  .auditlist__cellabel{display:inline-block; font-family:var(--mono); text-transform:uppercase; letter-spacing:.13em; font-size:var(--fs-1); color:var(--slate); min-width:74px; margin-right:6px}
  .auditfilters{flex-direction:column; align-items:stretch}
  .doc{padding:26px 20px}
  .doc-banner{padding:18px 20px; margin:-26px -20px 22px; flex-wrap:wrap}
  .doc-grid{grid-template-columns:1fr}
  .provenance{padding:16px 20px}
  .statstrip,.statstrip--doc{grid-template-columns:repeat(2,1fr)}
  .signal__row{flex-direction:column; align-items:flex-start; gap:10px}
  .signal__tags{justify-content:flex-start}
  .runrow--head{display:none}
  .runrow{grid-template-columns:1fr 1fr}
  .runrow__actions{grid-column:1 / -1; justify-self:start}
}

/* --- Single sign-on additions (login/pending) --- */
.authsplit{display:flex;align-items:center;gap:12px;margin:16px 0 14px}
.authsplit span{flex:1;height:1px;background:var(--line-strong)}
.authsplit em{font-style:normal;font-family:var(--mono,ui-monospace,monospace);font-size:var(--fs-2);
  letter-spacing:.28em;color:var(--slate,#8FA3BB)}
.authcard__ssohint{margin-top:10px;font-family:var(--mono,ui-monospace,monospace);font-size:var(--fs-1);
  letter-spacing:.18em;color:var(--slate,#8FA3BB);opacity:.75;text-align:center}
.authcard__note{color:var(--slate,#8FA3BB);font-size:var(--fs-4);line-height:1.65;margin:0 0 16px}
.btn--sso{display:flex;align-items:center;justify-content:center;gap:10px}
/* Google mark: transparent background — the colored "G" sits directly on the button surface (no white tile) */
.gmark{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;
  background:transparent;flex:none}
.gmark svg{display:block}

/* --- First-login account setup --- */
.authcard--wide{max-width:560px}
.terms{max-height:300px;overflow-y:auto;border:1px solid var(--line-strong);background:var(--terms-bg);
  padding:18px 20px;margin:6px 0 4px;font-size:var(--fs-3);line-height:1.6;color:var(--slate);
  box-shadow:0 0 0 1px transparent}
.terms:focus{outline:none;border-color:var(--crimson);box-shadow:0 0 0 1px var(--focus-ring)}
.terms__h{font-family:var(--serif);font-size:var(--fs-4);color:var(--ink);margin:0 0 12px}
.terms p{margin:0 0 12px}
.terms b{color:var(--ink)}
.authcard__alt{margin-top:14px;text-align:center}
.linkbtn{background:none;border:0;padding:0;cursor:pointer;font-family:var(--mono);font-size:var(--fs-2);
  text-transform:uppercase;letter-spacing:.14em;color:var(--slate);border-bottom:1px dotted var(--line-strong)}
.linkbtn:hover{color:var(--ink-strong)}

/* --- Data source map --- */
.sec--map{margin-top:36px}
.map__intro{max-width:70ch; margin:0 0 16px; font-size:var(--fs-3); line-height:1.6}
.mapwrap{padding:16px}
.map__controls{display:flex; gap:16px; flex-wrap:wrap; margin-bottom:14px}
.map__combo{flex:1 1 240px; min-width:200px}
.map__control-lab{display:block; font-family:var(--mono); text-transform:uppercase; letter-spacing:.16em;
  font-size:var(--fs-2); color:var(--slate); margin-bottom:6px}
.map__canvas{height:460px; width:100%; background:var(--map-bg); border:1px solid var(--line-strong);
  position:relative; z-index:0; isolation:isolate}
.map__controls{position:relative; z-index:1}
.map__canvas:focus{outline:2px solid var(--crimson); outline-offset:2px}
/* Map key: pathogens flagged this week (colour swatches) + a low->high scale */
.map__key{display:flex; flex-wrap:wrap; align-items:center; gap:12px 26px; margin-top:14px;
  padding-top:12px; border-top:1px solid var(--line)}
.map__key-block{display:flex; align-items:center; flex-wrap:wrap; gap:9px 16px; min-width:0}
.map__key-title{font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em;
  font-size:var(--fs-1); color:var(--slate-dim)}
.map__key-list{list-style:none; margin:0; padding:0; display:flex; flex-wrap:wrap; gap:9px 16px}
.map__key-item{display:inline-flex; align-items:center; gap:8px; font-family:var(--mono);
  font-size:var(--fs-2); letter-spacing:.04em; color:var(--slate)}
.map__key-item.is-active{color:var(--ink-strong)}
.map__key-item.is-active .map__swatch{box-shadow:0 0 0 2px var(--panel),0 0 0 3px currentColor}
.map__swatch{width:13px; height:13px; border-radius:50%; display:inline-block; flex:none;
  box-shadow:0 0 0 1px rgba(0,0,0,.28) inset}
.map__key-empty{margin:0; font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.04em; color:var(--slate)}
.map__scale{display:inline-flex; align-items:center; gap:9px; margin-left:auto; font-family:var(--mono);
  font-size:var(--fs-1); letter-spacing:.08em; color:var(--slate-dim)}
.map__scale-grad{width:104px; height:9px; border-radius:5px; display:inline-block;
  border:1px solid var(--line-strong); background:linear-gradient(90deg, var(--map-bg), var(--slate))}

/* Week scrubber (overview map only): a play/pause control, a range slider and a
   week label, styled to match the map controls. Colours come from theme tokens
   so light and dark both work with no light-mode literals. */
.map__scrub{display:flex; align-items:center; gap:12px; margin-top:14px; padding-top:12px;
  border-top:1px solid var(--line)}
.map__scrub-play{appearance:none; cursor:pointer; flex:none; width:34px; height:34px;
  display:flex; align-items:center; justify-content:center; background:var(--panel);
  border:1px solid var(--line-strong); color:var(--ink); font-size:var(--fs-3); line-height:1}
.map__scrub-play:hover{background:var(--panel-2); color:var(--ink-strong)}
.map__scrub-play:focus-visible{outline:2px solid var(--crimson); outline-offset:2px}
.map__scrub-range{flex:1 1 auto; min-width:120px; height:24px; cursor:pointer;
  accent-color:var(--crimson); background:transparent}
.map__scrub-range:focus-visible{outline:2px solid var(--crimson); outline-offset:2px}
.map__scrub-label{flex:none; font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.06em;
  color:var(--slate); white-space:nowrap; min-width:0}
@media (max-width:640px){
  .map__scrub{flex-wrap:wrap}
  .map__scrub-label{flex:1 0 100%; order:3}
}

/* Heat glow markers: soft radial colour glows, one per sewershed. Reset the
   Leaflet div-icon defaults (white box + border) so only the glow shows. */
.map__canvas .map-glow{background:transparent; border:0; pointer-events:none}
/* The glow box is always the largest a glow can get; colour, opacity and
   intensity-scale ride on custom properties so a week or pathogen switch
   crossfades the same element instead of tearing it down and rebuilding it.
   The falloff is a mask (not a gradient background) precisely so that
   background-color — and therefore the colour change — is transitionable. */
.map-glow__i{display:block; width:100%; height:100%; border-radius:50%; mix-blend-mode:screen;
  background-color:var(--glow-c,transparent); opacity:var(--glow-op,0);
  transform:scale(var(--glow-s,1));
  -webkit-mask-image:radial-gradient(circle closest-side, rgba(0,0,0,.85) 0%, rgba(0,0,0,.42) 42%, rgba(0,0,0,0) 72%);
  mask-image:radial-gradient(circle closest-side, rgba(0,0,0,.85) 0%, rgba(0,0,0,.42) 42%, rgba(0,0,0,0) 72%)}
@media (prefers-color-scheme:light){.map-glow__i{mix-blend-mode:multiply}}

/* Anchor markers: crisp round locators — every site draws the same circle, and
   only the fill colour says what was detected — with a two-tone drop-shadow so
   the edge reads on both dark and light basemaps. Reset the Leaflet div-icon
   defaults. */
.map__canvas .map-anchor-ic{background:transparent; border:0}
/* Like the glow: one fixed box per site, with fill colour, dimming and the
   hot/cold size difference all expressed as custom properties so they can
   crossfade in place. position:relative carries the selection ring. */
.map-anchor{display:block; width:100%; height:100%; border-radius:50%; position:relative;
  background-color:var(--anchor-c,var(--slate-dim)); opacity:var(--anchor-op,1);
  transform:scale(var(--anchor-s,1));
  filter:drop-shadow(0 0 1px rgba(0,0,0,.65)) drop-shadow(0 0 1px rgba(255,255,255,.7))}
.map-anchor:not(.is-hot){--anchor-op:.55}
.map__unplaced{margin-top:14px; font-size:var(--fs-3); line-height:1.6}
.map__unplaced .mono-label{color:var(--amber-ink); margin-right:6px}

/* Leaflet theming + popups (follows light/dark tokens). Fonts are forced on
   every control so no browser-default (Helvetica/Arial) leaks in. */
.leaflet-container,.leaflet-container .leaflet-control{font-family:var(--mono)}
/* Zoom +/- lifted to a >=32px tap target (Leaflet's default is 30x30). */
.leaflet-control-zoom a{font-family:var(--mono); font-size:var(--fs-5); font-weight:400;
  width:32px; height:32px; line-height:32px}
/* Attribution: bumped off the 11px floor and given hit padding on its links so
   the OSM/CARTO credits are legible and tappable rather than hairline text. */
.leaflet-control-attribution,.leaflet-control-attribution a{font-family:var(--mono); font-size:var(--fs-2)}
.leaflet-control-attribution{line-height:1.7}
.leaflet-control-attribution a{display:inline-block; padding:1px 4px}
.map__canvas .leaflet-container{background:var(--map-bg); font-family:var(--mono)}
.map__canvas .leaflet-control-zoom a{background:var(--panel); color:var(--ink); border-color:var(--line-strong); border-radius:var(--radius-control)}
.map__canvas .leaflet-control-zoom a:hover{background:var(--panel-2)}
.map__canvas .leaflet-bar{border:1px solid var(--line-strong); border-radius:var(--radius-control)}
.map__canvas .leaflet-control-attribution{background:var(--map-attr-bg); color:var(--slate-dim)}
.map__canvas .leaflet-control-attribution a{color:var(--slate)}
.map-tip{background:var(--panel); border:1px solid var(--line-strong); color:var(--ink); font-family:var(--mono);
  font-size:var(--fs-2); box-shadow:var(--shadow-tip)}
.map-tip::before{border-top-color:var(--line-strong)}
.mappop-wrap .leaflet-popup-content-wrapper{background:var(--panel); color:var(--ink); border:1px solid var(--line-strong);
  border-radius:0; box-shadow:var(--shadow-pop)}
.mappop-wrap .leaflet-popup-tip{background:var(--panel); border:1px solid var(--line-strong)}
.mappop-wrap .leaflet-popup-content{margin:12px 14px; font-family:var(--mono)}
.mappop-wrap a.leaflet-popup-close-button{color:var(--slate)}
.mappop__name{font-family:var(--serif); font-size:var(--fs-4); color:var(--ink); margin-bottom:8px;
  border-bottom:1px solid var(--line); padding-bottom:6px}
.mappop__tbl{border-collapse:collapse; width:100%; font-size:var(--fs-2)}
.mappop__tbl th{text-align:left; font-weight:500; color:var(--slate); text-transform:uppercase;
  letter-spacing:.1em; font-size:var(--fs-1); padding:3px 8px 4px 0}
.mappop__tbl td{padding:3px 8px 3px 0; color:var(--ink); white-space:nowrap}
.mappop__tbl tr.is-sel td{color:var(--ink-strong); background:rgba(192,25,43,.16)}
.mappop__tbl .mp-status{color:var(--slate)}
.mappop__tbl .mp-level{text-align:right; color:var(--slate)}
.mappop .mp-dot{width:9px; height:9px; border-radius:50%; display:inline-block; border:2px solid; margin-right:7px;
  vertical-align:middle}

/* Watch-signals card: a dismissible plain-language summary of the week's flagged
   pathogens, floating in the map's top-right corner (clear of the top-left zoom
   control). It lives inside .map__canvas — an isolated z-index:0 stacking
   context — so the control dropdowns (z-index:1 on .map__controls) always layer
   above it, while it sits above the heat glow. All colours come from theme
   tokens, so both light and dark work with no light-mode literals. */
.map__signals{position:absolute; top:12px; right:12px; z-index:680;
  width:min(300px,calc(100% - 24px)); max-height:calc(100% - 24px);
  display:flex; flex-direction:column; align-items:flex-end; gap:8px; pointer-events:none}
.map__signals>*{pointer-events:auto}
.mapsig{width:100%; min-height:0; display:flex; flex-direction:column; overflow:hidden;
  background:var(--panel); border:1px solid var(--line-strong); box-shadow:var(--shadow-pop)}
.mapsig[hidden]{display:none}
.mapsig__head{flex:none; display:flex; align-items:center; justify-content:space-between; gap:10px;
  padding:7px 7px 7px 12px; border-bottom:1px solid var(--line)}
.mapsig__title{font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em; font-size:var(--fs-1);
  color:var(--slate-dim)}
.mapsig__close{appearance:none; background:transparent; border:0; cursor:pointer; color:var(--slate);
  font-size:var(--fs-5); line-height:1; width:24px; height:24px; display:flex; align-items:center; justify-content:center}
.mapsig__close:hover{color:var(--ink-strong)}
.mapsig__close:focus-visible{outline:2px solid var(--crimson); outline-offset:2px}
.mapsig__list{flex:1 1 auto; min-height:0; overflow-y:auto; list-style:none; margin:0; padding:6px;
  display:flex; flex-direction:column; gap:3px}
.mapsig__item{margin:0}
.mapsig__sig{display:flex; gap:9px; width:100%; text-align:left; appearance:none; cursor:pointer;
  background:transparent; border:0; padding:6px 7px; color:inherit; font-family:var(--mono)}
.mapsig__sig:hover{background:var(--hover-tint)}
.mapsig__sig:focus-visible{outline:2px solid var(--crimson); outline-offset:-2px}
.mapsig__sig.is-active{background:var(--combobox-sel-bg)}
.mapsig__chip{width:11px; height:11px; border-radius:50%; flex:none; margin-top:3px;
  box-shadow:0 0 0 1px rgba(0,0,0,.28) inset}
.mapsig__body{display:flex; flex-direction:column; gap:2px; min-width:0}
.mapsig__row{display:flex; align-items:center; gap:8px; flex-wrap:nowrap}
.mapsig__name{font-size:var(--fs-2); color:var(--ink-strong); letter-spacing:.02em; min-width:0; flex:1 1 auto; overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.mapsig__badge{font-family:var(--mono); text-transform:uppercase; letter-spacing:.09em; font-size:var(--fs-1);
  padding:1px 5px; border:1px solid var(--line-strong); flex:0 0 auto; margin-left:auto}
.mapsig__badge--high{color:var(--badge-high-ink); border-color:var(--badge-high-line); background:var(--badge-high-bg)}
.mapsig__badge--watch{color:var(--badge-watch-ink); border-color:var(--badge-watch-line); background:var(--badge-watch-bg)}
.mapsig__status{font-size:var(--fs-2); color:var(--slate); line-height:1.45}
.mapsig__sites{font-size:var(--fs-1); color:var(--slate-dim); line-height:1.4}
.mapsig__reopen{flex:none; appearance:none; cursor:pointer; display:inline-flex; align-items:center; gap:7px;
  font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-1); color:var(--ink);
  background:var(--panel); border:1px solid var(--line-strong); box-shadow:var(--shadow-pop); padding:6px 10px}
.mapsig__reopen[hidden]{display:none}
.mapsig__reopen:hover{background:var(--panel-2)}
.mapsig__reopen:focus-visible{outline:2px solid var(--crimson); outline-offset:2px}
.mapsig__reopen-dot{width:8px; height:8px; border-radius:50%; flex:none; background:var(--crimson-bright);
  box-shadow:0 0 0 3px var(--focus-ring)}

@media (max-width:640px){
  .map__canvas{height:360px}
  .map__controls{flex-direction:column}
  .map__signals{top:8px; right:8px; gap:6px; width:min(260px,calc(100% - 68px))}
  /* Keep the attribution inside the card on narrow screens: let it wrap and cap
     its width so the OSM/CARTO credits are never clipped off the right edge. */
  .map__canvas .leaflet-control-attribution{max-width:calc(100% - 12px);
    white-space:normal; line-height:1.5}
}

/* --- New briefing page: form + county preview card --- */
.newgrid{display:grid; grid-template-columns:minmax(0,640px) minmax(280px,1fr); gap:26px; align-items:start}
.newgrid .formwrap{max-width:none; min-width:0}
.countycard{padding:16px; min-width:0; position:sticky; top:76px}
.countycard__canvas{height:340px; width:100%; background:var(--map-bg); border:1px solid var(--line-strong);
  position:relative; z-index:0; isolation:isolate; display:none}
.countycard__canvas.is-active{display:block}
.countycard__canvas .leaflet-container{background:var(--map-bg); font-family:var(--mono)}
.countycard__canvas .leaflet-control-zoom a{background:var(--panel); color:var(--ink); border-color:var(--line-strong)}
.countycard__canvas .leaflet-control-zoom a:hover{background:var(--panel-2)}
.countycard__canvas .leaflet-bar{border:1px solid var(--line-strong)}
.countycard__canvas .leaflet-control-attribution{background:var(--map-attr-bg); color:var(--slate-dim)}
.countycard__canvas .leaflet-control-attribution a{color:var(--slate)}
.countycard__empty{height:340px; border:1px dashed var(--line-strong); background:var(--inset-bg);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:12px; text-align:center;
  padding:20px; font-family:var(--mono); font-size:var(--fs-3); letter-spacing:.04em; color:var(--slate)}
.countycard__empty[hidden]{display:none}
.countycard__icon{color:var(--slate-dim)}
.countycard__caption{margin:12px 0 0; font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.1em;
  text-transform:uppercase; color:var(--slate)}
.countycard__caption[hidden]{display:none}
@media (max-width:900px){
  .newgrid{grid-template-columns:1fr}
  .countycard{position:static}
  .countycard__canvas,.countycard__empty{height:280px}
}

/* --- Skeleton placeholders (async content while it fetches) --- */
/* ONE shimmer in the app: this keyframe (motionShimmer) is shared by every
   skeleton, including the page-shell loader in base.html. */
.skel{display:block; position:relative; overflow:hidden; background:var(--hover-tint);
  contain:paint; --skel-shine:rgba(230,237,245,.07)}
.skel::after{content:""; position:absolute; inset:0; transform:translateX(var(--motion-shimmer-x));
  background:linear-gradient(90deg,transparent,var(--skel-shine),transparent);
  animation:var(--motion-shimmer) var(--dur-loop) var(--ease-in-out) var(--motion-loop-count)}
.skel--bar{height:12px; width:100%}
.skel--bar-sm{height:9px}
.skel--block{height:120px}
.skel--avatar{width:26px; height:26px; border-radius:50%}
.skel-row{display:flex; align-items:center; gap:12px; padding:12px 16px; border-top:1px solid var(--line)}
@media (prefers-color-scheme:light){.skel{--skel-shine:rgba(255,255,255,.65)}}

/* Combobox / multi-select option rows while their data loads */
.combobox__option--skel{pointer-events:none; padding:12px 13px; border-bottom:1px solid var(--combobox-line)}
.combobox__option--skel .skel--bar{width:62%}
.combobox__option--skel:nth-child(2n) .skel--bar{width:44%}
.combobox__option--skel:nth-child(3n) .skel--bar{width:74%}
.mselect__opt--skel{pointer-events:none; padding:9px 8px}
.mselect__opt--skel .skel--bar{width:58%}
.mselect__opt--skel:nth-child(2n) .skel--bar{width:42%}
.mselect__opt--skel:nth-child(3n) .skel--bar{width:70%}

/* Map skeleton overlay: covers the canvas until tiles are ready */
/* Crossfade, not a cut: the skeleton fades out at --dur-base over the map that
   is already drawn underneath (the same beat as every other skeleton swap —
   see the crossfade note in the ROWS, CARDS & LISTS block). */
.map__skel{position:absolute; inset:0; z-index:1100; background:var(--map-bg); padding:14px;
  display:flex; flex-direction:column; gap:12px; transition:opacity var(--dur-base) var(--ease-in)}
.map__skel.is-hidden{opacity:0; pointer-events:none}
.map__skel .skel--fill{flex:1}
.map__skel .skel--bar{width:32%}

/* --- Motion: hover/focus transitions (kept late so they win the cascade) --- */
a,.btn,.nav a,.back,.linkbtn,.copy-email,.chip,.chip button,
.usermenu__trigger,.usermenu__panel a,.usermenu__signout,.usermenu__panel a .icon,.usermenu__signout .icon,
/* (List rows are deliberately absent here: they crossfade faster than the rest
   of the app — see the ROWS, CARDS & LISTS block near the end of this file.) */
.modal__close,.rte__btn,.thfilter,
.combobox__option,.mselect__opt,.mselect__trigger,.auditscope a,
.map__canvas .leaflet-control-zoom a{
  transition:color var(--dur-fast) var(--ease-out),
             background-color var(--dur-fast) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out),
             opacity var(--dur-fast) var(--ease-out);
}
.input,.rte,.terms{
  transition:border-color var(--dur-fast) var(--ease-out),box-shadow var(--dur-fast) var(--ease-out);
}

/* --- Motion: the kept entrance primitives (closing stays instant via
   [hidden]) ---------------------------------------------------------------
   Travel comes from the distance tokens, never from literals: that is what
   lets the single reduced-motion block turn every one of these into a pure
   opacity fade by collapsing the tokens to their resting values. Each one
   resolves to the resting state at 100% so a stilled animation never freezes
   mid-pose. */
@keyframes motionFadeIn{from{opacity:0}to{opacity:1}}
@keyframes motionDropIn{from{opacity:0; transform:translateY(calc(var(--motion-rise) * -1))}to{opacity:1; transform:none}}
@keyframes motionRiseIn{from{opacity:0; transform:translateY(var(--motion-rise))}to{opacity:1; transform:none}}
@keyframes motionModalIn{from{opacity:0; transform:translateY(var(--motion-rise)) scale(var(--motion-scale-in))}to{opacity:1; transform:none}}
/* The two loop primitives: ONE spinner, ONE shimmer, app-wide. */
@keyframes motionSpin{to{transform:rotate(360deg)}}
@keyframes motionShimmer{to{transform:translateX(100%)}}
/* Reduced motion swaps both loops for this: still "busy", but no movement. */
@keyframes motionPulse{0%,100%{opacity:1}50%{opacity:.35}}

/* ONE spinner, part 1 — the ring itself is declared exactly once. Hosts only
   choose size, stroke and colour through the three custom properties, so no
   component can grow a second spinner shape. `.spinner` is the standalone
   primitive for markup that needs a bare loader; button pseudo-elements and
   the existing async hosts join the same rule. */
.spinner,
.btn.is-loading::after,.btn.btn--busy::after,
.step--running .step__icon,
.ovr-load__spin,
.rtoast__spin{--spin-size:16px; --spin-stroke:2px; --spin-track:var(--line-strong); --spin-head:var(--amber);
  box-sizing:border-box; width:var(--spin-size); height:var(--spin-size); border-radius:50%;
  border:var(--spin-stroke) solid var(--spin-track); border-top-color:var(--spin-head)}
.spinner{display:inline-block; flex:none; vertical-align:-2px}
/* ONE spinner, part 2 — and everything that spins spins on this one keyframe,
   fading in at the base duration so a loader never pops into place. Three
   hosts rotate a glyph they already show (the reload button's refresh icon,
   the save state's sync icon, the audit list's sentinel) instead of drawing a
   ring: same keyframe, same duration — still one spinner.
   (.ldr__ lives in base.html markup.) */
.spinner,
.btn.is-loading::after,.btn.btn--busy::after,
.wkreload__btn.is-loading .icon,
.step--running .step__icon,
.auditlist__sentinel.is-loading .icon,
.docbar__saved--saving .docbar__saved-icon--sync .icon,
.ovr-load__spin,
.rtoast__spin{animation:var(--motion-spin) var(--dur-loop) var(--ease-linear) var(--motion-loop-count),
  motionFadeIn var(--dur-base) var(--ease-out) !important}
/* ...and everything that shimmers is this one. */
.skel::after,
.ldr::after,
.wkreload__bar.is-running::after{animation:var(--motion-shimmer) var(--dur-loop) var(--ease-in-out) var(--motion-loop-count) !important}

/* ---- Route transitions (cross-document) ---------------------------------
   This is a server-rendered app: every route change is a full document load,
   which used to blank the window between pages. `navigation: auto` lets the
   browser keep the old page on screen and crossfade it into the new one, so no
   navigation flashes. Everything rides the same tokens, which is also how
   reduced motion neutralises it (the durations collapse to --dur-nil); a
   browser without cross-document view transitions just navigates as before,
   and js/routemotion.js only names elements when it detects support.
   Snapshots are inert overlays — a click during a transition lands on the new
   page, it is never blocked.
   Shared names let the eye follow an element across the load:
     app-header/app-footer — the persistent chrome stays put instead of
       cross-fading with itself; doc-title — a registry row's title becomes the
       document title (the row link is named at click time by routemotion.js,
       because only ONE element per document may carry a given name);
     doc-sheet — the card announcing a finished briefing expands into the
       document sheet.
   Below-the-fold content is not animated on load: only these named elements
   and the viewport-sized root snapshot take part. */
@view-transition{navigation:auto}
::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){
  animation-duration:var(--dur-base); animation-timing-function:var(--ease-out)}
.topbar,.docbar--app{view-transition-name:app-header}
.foot{view-transition-name:app-footer}
.docbar__title{view-transition-name:doc-title}
.doc-sheet{view-transition-name:doc-sheet}
/* settings-tab — the Settings strip's open tab. Naming it in CSS is legal
   because exactly one tab in a document carries .is-active (the server marks
   one per endpoint, and tabs.js enforces the invariant before the
   first navigation, since a duplicate name makes the browser skip the whole
   transition). One name, two jobs: across a navigation between route-backed
   tabs the opaque active surface travels to its new tab instead of the shape
   jumping on load, and inside /settings the same morph runs same-document when
   the Briefing views switch (tabs.js wraps that DOM update). It is
   extracted out of the app-header snapshot it lives in, which is exactly what
   lets it move independently of the bar.
   Keep in lockstep with CSS_NAMED in js/routemotion.js. */
.topbar__tab.is-active{view-transition-name:settings-tab}
/* An in-page tab switch is NOT a page change: only the tab may travel. Every
   other snapshot — the root, the header the strip sits in — swaps at once, so
   no ghost of the old bar crossfades underneath the moving tab, and the panel
   below plays its own crossfade as it always has. Naming the exception after
   the blanket rule keeps it winning whatever specificity the browser gives a
   named pseudo-element argument. */
html.is-tabswitch::view-transition-group(*),
html.is-tabswitch::view-transition-old(*),
html.is-tabswitch::view-transition-new(*){animation-duration:var(--dur-nil)}
html.is-tabswitch::view-transition-group(settings-tab),
html.is-tabswitch::view-transition-old(settings-tab),
html.is-tabswitch::view-transition-new(settings-tab){
  animation-duration:var(--dur-base); animation-timing-function:var(--ease-out)}
/* The group reveal is a layout transition (see .tabgroup__members). During a
   same-document tab switch the browser measures the tab's destination right
   after the DOM update, so a reveal still easing open would hand it the wrong
   geometry and the surface would land misaligned — inside a switch the group
   opens at once and the travelling tab carries the motion. */
html.is-tabswitch .tabgroup__members{transition-duration:var(--dur-nil)}
/* While a transition runs, the transition IS the page's entrance — don't fade
   the incoming document in underneath it as well. */
:root:active-view-transition .page{animation-duration:var(--dur-nil)}
/* A view transition replaces the page-shell skeleton: the outgoing page stays
   visible until the new one is ready, so the skeleton would only flash. The
   rule that hides it lives with the loader's own styles in base.html — that
   block is inline, so it would win over this file anyway. */

/* Dropdown entrances all share motionMenuIn (scale + drop + fade, growing from
   the corner nearest its trigger) — see the micro-interaction section below. */
.usermenu__panel:not([hidden]){animation:motionMenuIn var(--dur-base) var(--ease-out)}
.combobox.is-open .combobox__list{animation:motionMenuIn var(--dur-base) var(--ease-out)}
.mselect__panel:not([hidden]){animation:motionMenuIn var(--dur-base) var(--ease-out)}
.modal:not([hidden]) .modal__backdrop{animation:motionFadeIn var(--dur-base) var(--ease-out)}
.modal:not([hidden]) .modal__panel{animation:motionModalIn var(--dur-slow) var(--ease-out)}
.modal-backdrop{animation:motionFadeIn var(--dur-base) var(--ease-out)}
.modal-backdrop .reveal-box{animation:motionModalIn var(--dur-slow) var(--ease-out)}

/* Page settle + flash entrance: faint, felt rather than noticed */
.page{animation:motionFadeIn var(--dur-slow) var(--ease-out)}
.flash{animation:motionRiseIn var(--dur-base) var(--ease-out)}

/* Dynamic content: console steps/lines, bulk bar, run finale */
.step,.step__line{animation:motionFadeIn var(--dur-base) var(--ease-out)}
.bulkbar:not([hidden]){animation:motionRiseIn var(--dur-base) var(--ease-out)}
.final--ok,.final--error{animation:motionFadeIn var(--dur-base) var(--ease-out)}

/* will-change is never permanent: JS adds this class for the length of an
   animation and removes it on animationend/transitionend (see motion.js). */
.is-animating{will-change:opacity,transform}

/* --- Nav/page icon response ---------------------------------------------
   ONE response for every nav icon: it brightens and lifts by --motion-nudge
   when its item is hovered/focused. No per-icon signature loops — a menu full
   of icons animating forever was noise, and it never stopped while the pointer
   rested. Nothing loops, so an idle screen is completely still; reduced motion
   collapses --motion-nudge to 0 and keeps the colour change.
   In a tab strip the lift is hover/focus ONLY, never because a tab is the open
   one: that tab stays on screen for as long as you are on the page, so a
   permanent lift just reads as a misaligned icon. The account menu is a
   transient dropdown, so there the current page's entry keeps the lift. */
:is(.usermenu__panel a, .topbar__tab, .tabs__tab) .icon{
  transform-origin:50% 50%;
  transition:color var(--dur-fast) var(--ease-out),
             opacity var(--dur-fast) var(--ease-out),
             transform var(--dur-fast) var(--ease-out)}
:is(.usermenu__panel a:is(:hover, :focus-visible, .is-active),
    .topbar__tab:is(:hover, :focus-visible),
    .tabs__tab:is(:hover, :focus-visible)) .icon{
  transform:translateY(calc(var(--motion-nudge) * -1))}

/* --- Light-mode fixups (kept last so they win the cascade) --- */
@media (prefers-color-scheme: light){
  /* Decorative radar marks: darken the slate strokes so they stay visible on paper */
  .radar [stroke="#8FA3BB"]{stroke:var(--radar-line)}
  /* Selected popup row: softer crimson tint reads better with dark ink on light */
  .mappop__tbl tr.is-sel td{background:rgba(168,22,36,.10)}
  /* Data-URI glyphs (filter chevron, search magnifier): darker stroke for paper */
  .thfilter{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 24 24' fill='none' stroke='%2351637A' stroke-width='3'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E")}
  .input.filterbar__search{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='13' height='13' viewBox='0 0 24 24' fill='none' stroke='%2351637A' stroke-width='2'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='M21 21l-4.35-4.35'/%3E%3C/svg%3E"); background-repeat:no-repeat; background-position:12px center}
}
/* --------------------- Block editor --------------------- */
.docbar--editor .docbar__saved{font-size:var(--fs-2); color:var(--slate); margin-left:10px; white-space:nowrap; display:inline-flex; align-items:center; gap:5px}
.docbar__saved-icon{display:none; line-height:0}
.docbar__saved-icon .icon{display:block}
.docbar__saved--ok .docbar__saved-icon--check{display:inline-flex}
.docbar__saved--saving .docbar__saved-icon--sync{display:inline-flex}
.ver-pill--edit{background:var(--teal-050, #e6f4f4); color:var(--teal, #0d7a7a)}
.docbar__title--edit{cursor:default}

/* Formatting toolbar (nested in the same strip toolbar the briefing view uses) */
.fmtbar{display:flex; align-items:center; gap:2px; min-width:0}
.fmtbar .stripbtn{color:var(--ink); transition:opacity var(--dur-fast) var(--ease-out), color var(--dur-fast) var(--ease-out)}
/* Disabled state is carried by the controls themselves (not a blanket fade), so
   the "why" hint stays fully legible while B/I/U clearly read as unavailable.
   pointer-events on the buttons hands hover to .fmtbar, so its not-allowed
   cursor is what the admin sees over a dead control. */
.fmtbar.is-disabled{cursor:not-allowed}
.fmtbar.is-disabled .stripbtn{opacity:.3; color:var(--slate-dim); pointer-events:none}
.fmtbar.is-disabled .strip__sep{opacity:.35}
.fmtbar__hint{font-size:var(--fs-2); color:var(--slate); margin-left:10px; white-space:nowrap}
.fmtbar:not(.is-disabled) .fmtbar__hint{display:none}
.docbar--editor .strip{flex-wrap:wrap; height:auto; min-height:40px}
.docbar--editor .strip__transitions .btn--sm .icon{margin-right:4px}

/* Editor hint */
/* Keyboard affordances. These used to be muted fine print under the canvas, so
   the insert/reorder/exit shortcuts went unnoticed; now a scannable panel with
   real key caps. */
.editor-hint{font-size:var(--fs-2); margin:18px 0 6px; color:var(--ink);
  display:flex; flex-wrap:wrap; align-items:center; justify-content:center;
  gap:7px 16px; padding:9px 12px; border:1px solid var(--line); border-radius:8px;
  background:var(--panel)}
.editor-hint__label{font-family:var(--mono); text-transform:uppercase; letter-spacing:.14em;
  font-size:var(--fs-1); color:var(--slate); flex:0 0 auto}
.editor-hint__item{display:inline-flex; align-items:center; gap:5px; white-space:nowrap}
kbd{display:inline-block; font-family:var(--mono); font-size:var(--fs-1); line-height:1.45;
  padding:0 5px; border:1px solid var(--line-strong); border-bottom-width:2px;
  border-radius:4px; background:var(--bg); color:var(--ink-strong);
  min-width:1.15em; text-align:center}

/* Blocks: chrome layered over the document's own look ------------------- */
#blocks-root{min-height:200px}
.blk{position:relative; border-radius:8px}
.blk:hover{background:rgba(13,122,122,.03)}
.blk:focus-within{background:rgba(13,122,122,.045)}
.blk.is-dragging{opacity:.4}
.blk__ctrls{position:absolute; left:-32px; top:2px; display:none; flex-direction:column; gap:1px; z-index:5}
.blk:hover .blk__ctrls, .blk:focus-within .blk__ctrls{display:flex}
.blk__ctrl{width:22px; height:20px; border:0; background:transparent; border-radius:4px; color:var(--slate);
  font-size:var(--fs-2); line-height:1; cursor:pointer; display:flex; align-items:center; justify-content:center}
.blk__ctrl:hover{background:var(--paper-2, #eef3f6); color:var(--ink)}
.blk__grip{cursor:grab}

/* Editable regions inherit the document typography; chrome is minimal. */
.blk [contenteditable="true"]{outline:none; min-height:1.2em; border-radius:3px}
.blk [contenteditable="true"]:focus{box-shadow:0 0 0 2px rgba(13,122,122,.16)}
.blk [contenteditable="true"]:empty::before{content:attr(data-placeholder); color:var(--slate); opacity:.55; pointer-events:none}
.blk .sec__eyebrow [contenteditable="true"]{min-width:90px; display:inline-block; text-transform:uppercase}
.blk .callout{position:relative}
.blk .callout__tag[contenteditable="true"]{min-width:120px; display:inline-block}
.blk .signal{position:relative}
.blk .signal__name[contenteditable="true"]{min-width:140px}
.blk .signal__sheds[contenteditable="true"]{min-width:180px}
.blk .doc-table th, .blk .doc-table td{min-width:56px}
.blk .doc-stat__num[contenteditable="true"]{min-width:70px}
.blk .doc-stat__lab[contenteditable="true"]{min-width:160px}

/* Live-data placeholder blocks (template editor) ----------------------- */
/* Continuation block: a later block of a section whose label was already drawn
   on the first one (see refreshEyebrows). The tie-rule + tightened gap keep it
   reading as part of that section rather than as an unlabelled orphan. */
.blk--cont > .sec{margin-top:14px; border-left:2px solid var(--line); padding-left:16px}
.blk--placeholder{outline:1px dashed rgba(13,122,122,.35); outline-offset:2px; border-radius:8px}
.blk--placeholder:hover{background:rgba(13,122,122,.05)}
/* Read-only detector-derived blocks (Task 441): reorderable/deletable but not
   editable. A faint left rule marks them as generated content. */
.blk--readonly{border-left:2px solid var(--line-strong); padding-left:10px; margin-left:-12px}
.blk--readonly:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
.ed-ph{display:flex; align-items:flex-start; gap:10px; padding:10px 12px;
  background:rgba(13,122,122,.06); border-radius:6px; margin-top:4px}
.ed-ph__tag{flex:none; font-size:var(--fs-1); font-weight:700; letter-spacing:.08em;
  text-transform:uppercase; color:#fff; background:var(--teal, #0d7a7a);
  padding:3px 7px; border-radius:4px}
.ed-ph__desc{margin:0; font-size:var(--fs-2); color:var(--slate)}

/* Editable + auto-filled header chrome (template editor) --------------------
   Authored masthead/label fields are contenteditable (.hdr-edit); per-week
   values shown alongside are non-editable "filled at generation" samples
   (.hdr-auto / .hdr-token) mirroring the LIVE DATA placeholder treatment. */
.hdr-edit{outline:none; border-radius:3px; cursor:text;
  transition:background-color var(--dur-fast) var(--ease-out)}
.hdr-edit:hover{background:rgba(13,122,122,.07)}
.hdr-edit:focus{background:rgba(13,122,122,.07); box-shadow:0 0 0 2px rgba(13,122,122,.32)}
.doc-banner__sub.hdr-edit, .doc-banner__conf.hdr-edit{display:inline-block; min-width:140px}
.hdr-edit--eyebrow{display:inline-block; min-width:90px}
.hdr-edit:empty::before{content:attr(aria-label); color:var(--slate); opacity:.5}
.hdr-auto{color:var(--slate); background:rgba(13,122,122,.07);
  border-bottom:1px dashed rgba(13,122,122,.5); border-radius:3px 3px 0 0;
  padding:0 4px; cursor:help}
.hdr-auto--block{border-radius:3px; line-height:1.7}
.hdr-token{background:rgba(13,122,122,.12); border:1px dashed rgba(13,122,122,.5);
  border-radius:999px; padding:0 8px; margin:0 2px; cursor:help;
  -webkit-user-select:none; user-select:none}

/* Small editor-only chrome */
.ed-add{margin:4px 0 2px}
.ed-tools{display:flex; gap:6px; margin:6px 0 2px}
.ed-fields{display:flex; gap:6px; margin-top:6px}
.ed-fields .input{flex:1}
.ed-chip{border:1px solid var(--line, #d6dee4); background:#fff; border-radius:999px; font-size:var(--fs-1);
  font-weight:700; letter-spacing:.08em; padding:2px 8px; color:var(--slate); cursor:pointer}
.ed-chip:hover{color:var(--ink); border-color:var(--slate)}
.ed-chip.is-on{background:var(--teal, #0d7a7a); border-color:var(--teal, #0d7a7a); color:#fff}
.ed-x{border:0; background:transparent; color:var(--slate); font-size:var(--fs-4); cursor:pointer;
  border-radius:4px; width:22px; height:22px; line-height:1; padding:0}
.ed-x:hover{background:var(--paper-2, #eef3f6); color:var(--red, #c0392b)}
.ed-corner{position:absolute; top:6px; right:8px; opacity:0; transition:opacity var(--dur-fast) var(--ease-out)}
.blk .callout:hover .ed-corner, .blk .callout:focus-within .ed-corner{opacity:1}
.sig-tools{position:absolute; top:6px; right:6px; display:flex; gap:5px; align-items:center;
  background:rgba(255,255,255,.92); border-radius:8px; padding:2px 4px; opacity:0; transition:opacity var(--dur-fast) var(--ease-out)}
.blk .signal:hover .sig-tools, .blk .signal:focus-within .sig-tools{opacity:1}
.ed-imgph{min-height:70px; border:1px dashed var(--line, #d6dee4); border-radius:8px; display:flex;
  align-items:center; justify-content:center; color:var(--slate); font-size:var(--fs-3)}
.blk .bullets li[data-easing-item]{position:relative; padding-right:26px}
.blk .bullets li[data-easing-item] .ed-x{position:absolute; right:0; top:0}
.ed-none{margin:4px 0}

/* Insert palette */
.palette{position:absolute; z-index:300; width:260px; background:#fff; border:1px solid var(--line, #d6dee4);
  border-radius:10px; box-shadow:0 10px 30px rgba(11,46,79,.18); padding:8px}
.palette__search{width:100%; margin-bottom:6px}
.palette__list{max-height:280px; overflow:auto; display:grid; gap:2px}
.palette__item{display:flex; justify-content:space-between; align-items:baseline; gap:8px; width:100%;
  padding:7px 9px; border:0; border-radius:7px; background:transparent; cursor:pointer; text-align:left}
.palette__item:hover{background:var(--paper-2, #eef3f6)}
.palette__label{font-size:var(--fs-3); font-weight:600; color:var(--ink)}
.palette__hint{font-size:var(--fs-2); color:var(--slate)}

/* Read-only view additions for new block types */
.doc-h2{font-size:var(--fs-5); color:var(--navy, #0b2e4f); margin:18px 0 6px}
.doc-h3{font-size:var(--fs-4); color:var(--navy, #0b2e4f); margin:12px 0 4px}
.doc-table-wrap{overflow-x:auto; margin:10px 0}
.doc-table{border-collapse:collapse; width:100%; font-size:var(--fs-3)}
.doc-table th,.doc-table td{border:1px solid var(--line, #d6dee4); padding:6px 9px; text-align:left}
.doc-table th{background:var(--navy, #0b2e4f); color:#fff}
.doc-figcaption{font-size:var(--fs-2); color:var(--slate); margin-top:4px}
.doc-figure{border:1px dashed var(--line, #d6dee4); border-radius:8px; padding:12px; margin:10px 0}
.doc-figure__tag{font-size:var(--fs-2); font-weight:700; letter-spacing:.14em; color:var(--teal, #0d7a7a); display:flex; gap:6px; align-items:center}
.doc-stat{display:inline-block; margin:10px 18px 10px 0}
.doc-stat__num{font-size:var(--fs-7); font-weight:800; color:var(--navy, #0b2e4f); line-height:1}
.doc-stat__lab{font-size:var(--fs-2); letter-spacing:.08em; text-transform:uppercase; color:var(--slate)}
.doc-citation{font-size:var(--fs-3); color:var(--slate); border-left:2px solid var(--line, #d6dee4); padding-left:10px; margin:8px 0}
.doc-image{margin:12px 0}
.doc-image img{max-width:100%; border-radius:8px}
.doc-quote{border-left:3px solid var(--teal, #0d7a7a); margin:12px 0; padding:2px 0 2px 14px}
.doc-quote__body{font-size:var(--fs-4); font-style:italic}
.doc-quote__cite{display:block; font-size:var(--fs-3); color:var(--slate); margin-top:4px}
.doc-divider{border:0; border-top:1px solid var(--line, #d6dee4); margin:16px 0}
.doc-divider--dashed{border-top-style:dashed}

/* ---- Focus mode: scrim + emphasized block + element settings panel ---- */
/* Scrim dims (never hides) the rest of the document. It sits under the sticky
   docbar (z-60) and the palette (z-300); the focused block is raised above. */
.edfocus-scrim{position:fixed; inset:0; z-index:30; background:var(--modal-backdrop); opacity:0; pointer-events:none; transition:opacity var(--dur-slow) var(--ease-out)}
body.edfocus-on .edfocus-scrim{opacity:.55; pointer-events:auto}
/* The raised look is carried by a shadow pseudo-element whose opacity fades
   in — box-shadow itself is never animated. */
.blk.is-focus{z-index:40; background:var(--panel); transform:scale(var(--motion-focus-scale)); transition:transform var(--dur-slow) var(--ease-out)}
.blk.is-focus::before{content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  box-shadow:0 0 0 14px var(--panel), 0 0 0 15px var(--line-strong), var(--shadow-pop);
  animation:edfocus-fade-in var(--dur-slow) var(--ease-out) both}
.blk.is-focus:hover{background:var(--panel)}
.blk--divider.is-focus{outline:none}
/* Entrance animations when focus mode opens */
@keyframes edfocus-panel-in{from{opacity:0; transform:translateY(var(--motion-rise))}}
@keyframes edfocus-fade-in{from{opacity:0}}

/* Add-element affordances on the focused block */
.blk__insert{position:absolute; left:50%; transform:translateX(-50%); z-index:8; display:none; align-items:center; gap:6px; font-family:var(--mono); text-transform:uppercase; letter-spacing:.12em; font-size:var(--fs-1); color:var(--slate); background:var(--panel); border:1px solid var(--line-strong); border-radius:0; padding:4px 10px; cursor:pointer; white-space:nowrap; transition:color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out)}
.blk__insert:hover,.blk__insert:focus-visible{color:var(--ink-strong); border-color:var(--slate)}
.blk__insert:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
.blk.is-focus>.blk__insert{display:inline-flex; animation:edfocus-fade-in var(--dur-slow) var(--ease-out) both}
.blk__insert--above{top:-40px}
.blk__insert--below{bottom:-40px}

/* Element settings panel: docbar/menu surface language — square corners,
   strong border, pop shadow. Anchored beside the focused block. */
.blkpanel{position:absolute; left:calc(100% + 30px); top:0; width:232px; background:var(--menu-grad); border:1px solid var(--line-strong); border-radius:0; box-shadow:var(--shadow-pop); padding:14px; z-index:8; font-family:var(--mono); animation:edfocus-panel-in var(--dur-slow) var(--ease-out) both}
.blkpanel__title{display:flex; align-items:center; gap:8px; font-size:var(--fs-1); letter-spacing:.16em; text-transform:uppercase; color:var(--slate); margin-bottom:12px}
.blkpanel__cog{display:inline-flex; flex:none; color:var(--crimson)}
.blkpanel__cog svg{display:block}
.blkpanel__row{display:flex; flex-wrap:wrap; align-items:center; gap:6px; margin-bottom:10px}
.blkpanel__row:last-child{margin-bottom:0}
.blkpanel__lab{flex:1 0 100%; font-size:var(--fs-1); letter-spacing:.14em; text-transform:uppercase; color:var(--slate-dim)}
.blkpanel__opt.is-on{color:var(--ink-strong); border-color:var(--crimson); background:var(--hover-tint)}
.blkpanel__check{display:flex; align-items:center; gap:8px; font-size:var(--fs-2); letter-spacing:.06em; text-transform:uppercase; color:var(--ink); cursor:pointer}
.blkpanel__check input{accent-color:var(--crimson); width:14px; height:14px; cursor:pointer}
.blkpanel__note{margin:0; font-size:var(--fs-2); line-height:1.5; font-family:var(--mono)}
.blkpanel .input{width:100%}

/* AI: regenerate a single narrative section, from the settings panel */
.blkpanel__regen{margin-top:12px; padding-top:12px; border-top:1px solid var(--line)}
.blkpanel__regen .blkpanel__lab{margin-bottom:7px}
.regen__guidance{width:100%; min-height:52px; resize:vertical; line-height:1.45; margin-bottom:8px}
.regen__go{width:100%}
.regen__status{margin:9px 0 0; font-size:var(--fs-2); line-height:1.45; color:var(--slate)}
.regen__status:empty{display:none}
.regen--ok .regen__status{color:var(--green)}
.regen--error .regen__status{color:var(--red)}

/* Narrow viewports: focused sheet — panel drops below the block, full width,
   with the add-above/below buttons still reachable. */
@media (max-width:1100px){
  .blkpanel{position:static; width:100%; margin-top:16px}
  .blk.is-focus{box-shadow:0 0 0 10px var(--panel), 0 0 0 11px var(--line-strong), var(--shadow-pop); transform:none}
  .blk__insert--above{top:-34px}
  .blk__insert--below{bottom:-34px}
}
.docbar__saved--error{color:var(--red, #c0392b); font-weight:600}
/* .btn--busy is the loading state under an older name — its treatment lives
   with .btn.is-loading (label crossfade + the one spinner), not here. */

/* Automations page */
.rtable--automations .rtable__head,.rtable--automations .rtable__row{grid-template-columns:1.6fr 1.1fr 1.3fr .7fr 1.2fr 1fr 1.6fr}
.rtable--automations .rtable__row.is-paused>span:not(.rtable__actions){opacity:.55}
.rtable--automations .rtable__actions form{display:inline}
.autoerr{display:block; font-family:var(--mono); font-style:normal; font-size:var(--fs-2); color:var(--crimson); margin-top:3px; max-width:220px; white-space:normal}
.form__row{display:grid; grid-template-columns:1fr 1fr; gap:16px}
.form__section{border:none; margin:0; padding:0; display:flex; flex-direction:column; gap:16px}
.form__section + .form__section{margin-top:22px; padding-top:22px; border-top:1px solid var(--hair)}
.form__legend{font-size:var(--fs-3); font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--slate); padding:0}
.form__aux{margin-top:14px; padding-top:14px; border-top:1px solid var(--hair)}
@media (max-width:900px){.form__row{grid-template-columns:1fr}}

/* Settings control center */
.settings-source__head{display:flex; justify-content:space-between; align-items:flex-start; gap:20px; margin-bottom:14px}
.settings-source__actions,.settings-source__links{display:flex; flex-wrap:wrap; gap:8px}
.settings-source__notes{display:flex; flex-direction:column; gap:6px; margin:0 0 12px}
.settings-source__notes p{display:flex; gap:8px; margin:0; color:var(--slate); font-size:var(--fs-3)}
.settings-source__notes svg{flex:none; margin-top:3px}
.rtable--settings-source .rtable__head,.rtable--settings-source .rtable__row{
  grid-template-columns:minmax(0,1.05fr) minmax(0,.8fr) minmax(0,1.55fr) minmax(0,1.1fr) minmax(0,1.05fr) minmax(0,.75fr)}
.rtable--settings-source .rtable__head>span,.rtable--settings-source .rtable__row>span{min-width:0}
.rtable--settings-source .rtable__row>span{overflow-wrap:anywhere}
.rtable--settings-source .rtable__title{display:block}
.rtable--settings-source .rtable__title em{display:block; font-style:normal; color:var(--slate); font-size:var(--fs-2)}
.settings-source__links{margin-top:10px; font-size:var(--fs-2)}
.settings-source__links a{color:var(--teal)}
.settings-attribution{margin:8px 0 14px}
.settings-config{max-width:none}
.policy-placeholder{display:flex; flex-direction:column; align-items:flex-start; gap:7px; padding:14px 16px; border:1px dashed var(--amber); background:var(--inset-bg)}
.policy-placeholder p{margin:0; color:var(--slate); max-width:78ch}
@media (max-width:900px){
  .settings-source__head{flex-direction:column}
  .rtable--settings-source .rtable__head{display:none}
  .rtable--settings-source .rtable__row{grid-template-columns:1fr 1fr; gap:8px}
}

/* ---- Data Sources page ---- */
.dsrc__picker{display:flex; flex-direction:column; gap:4px; min-width:220px}
.dsrc__head-actions{display:flex; align-items:flex-end; gap:16px; flex-wrap:wrap}
.dsrc__refresh{display:flex; flex-direction:column; gap:4px; align-items:flex-start}
.dsrc__refresh-hint{font-size:.8rem}
.dsrc__summary{padding:18px 20px}
.dsrc__sumgrid{display:grid; grid-template-columns:repeat(auto-fit, minmax(200px, 1fr)); gap:18px}
.dsrc__sumgrid>div{display:flex; flex-direction:column; gap:5px}
.dsrc__tally{display:flex; gap:6px; flex-wrap:wrap}
/* Constrained tracks (minmax(0,…)) + shrinkable cells, mirroring the Admins
   table fix, so long keys / s3:// URIs / timestamps can't blow out a column
   and headers stay aligned with their rows. */
/* Lambda inventory. The environment block is a full-width strip under its
   row rather than a seventh column: variable names are long and would squeeze
   every other column to nothing. */
.rtable--lambdas .rtable__head,.rtable--lambdas .rtable__row{
  grid-template-columns:minmax(0,1.5fr) minmax(0,.9fr) minmax(0,.5fr) minmax(0,1.2fr) minmax(0,.6fr) minmax(0,.9fr) minmax(0,2.4fr)}
/* Handlers, ARN fragments and role names are long unbroken tokens: without an
   anywhere-break they punch straight out of their track into the next column. */
.rtable--lambdas .rtable__head>span,.rtable--lambdas .rtable__row>span{min-width:0; overflow-wrap:anywhere}
.rtable--lambdas .rtable__row.is-paused>span:not(.rtable__actions){opacity:.55}
.rtable--lambdas .rtable__actions{flex-wrap:wrap}
.rtable--lambdas .rtable__actions form{display:inline}
.lambda__caveat{margin-bottom:18px}
.lambda__rule{display:block; font-style:normal}
.lambda__env{display:flex; flex-wrap:wrap; align-items:baseline; gap:6px 10px;
  padding:0 16px 12px; font-family:var(--mono); font-size:var(--fs-2); color:var(--slate)}
.lambda__envlabel{text-transform:uppercase; letter-spacing:.12em;
  font-size:var(--fs-1); color:var(--slate-dim)}
.lambda__envvar{border:1px solid var(--hair); padding:2px 7px; overflow-wrap:anywhere}
.lambda__envvar b{color:var(--ink-strong); font-weight:600}
/* Re-assert the stacked layout: the generic mobile block sits earlier in this
   file, so the desktop grid above would otherwise win the cascade. */
@media (max-width:900px){
  .rtable--lambdas .rtable__row{grid-template-columns:1fr 1fr; gap:8px}
  .rtable--lambdas .rtable__title{white-space:normal}
}

.rtable--dsrc .rtable__head,.rtable--dsrc .rtable__row{grid-template-columns:minmax(0,1.4fr) minmax(0,.7fr) minmax(0,.7fr) minmax(0,.6fr) minmax(0,1.1fr) minmax(0,1.8fr)}
.rtable--dsrcweeks .rtable__head,.rtable--dsrcweeks .rtable__row{grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr) minmax(0,.9fr) minmax(0,2.4fr)}
.rtable--dsrcobjs .rtable__head,.rtable--dsrcobjs .rtable__row{grid-template-columns:minmax(0,2.4fr) minmax(0,1.1fr) minmax(0,.65fr) minmax(0,1.45fr) minmax(0,.75fr) minmax(0,1fr)}
.rtable--dsrcman .rtable__head,.rtable--dsrcman .rtable__row{grid-template-columns:minmax(0,1.6fr) minmax(0,1fr) minmax(0,.8fr) minmax(0,.5fr) minmax(0,1.4fr)}
.rtable--dsrc .rtable__head>span,.rtable--dsrcweeks .rtable__head>span,
.rtable--dsrcobjs .rtable__head>span,.rtable--dsrcman .rtable__head>span{min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.rtable--dsrc .rtable__row>span,.rtable--dsrcweeks .rtable__row>span,
.rtable--dsrcobjs .rtable__row>span,.rtable--dsrcman .rtable__row>span{min-width:0}
/* Dense mono cells truncate on one line; trailing note/status cells wrap. */
.rtable--dsrc .rtable__row>span:not(:last-child),
.rtable--dsrcweeks .rtable__row>span:not(:last-child),
.rtable--dsrcobjs .rtable__row>span{overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.rtable--dsrc .rtable__title,.rtable--dsrcweeks .rtable__title,.rtable--dsrcman .rtable__title{display:block}
.rtable--dsrc .rtable__row>span:last-child,
.rtable--dsrcweeks .rtable__row>span:last-child{overflow-wrap:anywhere}
/* Manifest rows hold inputs: let them shrink with the track (no overflow
   clipping on the cell, so focus rings stay visible). */
.rtable--dsrcman .rtable__row .input{width:100%}
.rtable--dsrcman .rtable__title,.rtable--dsrcman .rtable__row>span.mono{overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.dsrc__key{min-width:0}
.dsrc__key .dsrc__key-name,.dsrc__key em{display:block; max-width:100%; overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.dsrc__key em{font-style:normal; color:var(--slate); font-size:var(--fs-2); text-transform:none; letter-spacing:0}
/* Stacked (mobile) override for the four Data Sources tables. Must live AFTER
   the desktop track rules above: both have equal specificity, so the general
   860px block earlier in the file loses the cascade to them (the pre-existing
   reason these tables never actually stacked). */
@media (max-width:900px){
  .rtable--dsrc .rtable__row,.rtable--dsrcweeks .rtable__row,
  .rtable--dsrcobjs .rtable__row,.rtable--dsrcman .rtable__row,
  .rtable--dsrcmanage .rtable__row{grid-template-columns:1fr 1fr; gap:8px}
  /* Stacked cells get their width back — wrap instead of truncating. */
  .rtable--dsrc .rtable__row>span:not(:last-child),
  .rtable--dsrcweeks .rtable__row>span:not(:last-child),
  .rtable--dsrcobjs .rtable__row>span,
  .rtable--dsrcman .rtable__title,.rtable--dsrcman .rtable__row>span.mono,
  .rtable--dsrcmanage .rtable__title{white-space:normal; overflow-wrap:anywhere}
}
/* Source identity cell: human-readable label on top (may clip via .truncate),
   raw ID as a quiet mono subline (identity stays recoverable via tooltip). */
.dsrc__src{display:block; min-width:0}
.dsrc__src-name{display:block; max-width:100%; font-weight:600; text-transform:none; letter-spacing:0}
.dsrc__src-id{display:block; max-width:100%; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;
  color:var(--slate); font-size:var(--fs-2); text-transform:none; letter-spacing:0}
/* Selects must never clip their chosen option off-screen. */
.rtable--dsrcmanage select.src-type{width:100%; text-overflow:ellipsis}
/* Weekly-readiness status: badge pinned to the top so a wrapping reason can't
   knock it out of alignment; reason flows on its own line beneath. */
.dsrc__wkstatus{display:flex; flex-direction:column; align-items:flex-start; gap:4px; min-width:0}
.dsrc__wkstatus .badge{flex:none}
.dsrc__wkreason{overflow-wrap:anywhere}
/* Manifest save bar: sticky within the form so the control stays reachable
   while the table scrolls, with a clear dirty/unsaved affordance. */
.dsrc__savebar{position:sticky; bottom:0; z-index:1; display:flex; flex-wrap:wrap; align-items:center;
  justify-content:space-between; gap:12px; width:100%; margin:4px -18px -16px; padding:12px 18px;
  border-top:1px solid var(--line); background:var(--panel-bg)}
.dsrc__savestate{display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-2); color:var(--slate)}
.dsrc__savestate svg{width:14px; height:14px}
.dsrc__savestate-dirty{display:none; align-items:center; gap:6px; color:var(--ink); font-weight:600}
.dsrc__savedot{width:8px; height:8px; border-radius:50%; background:var(--crimson)}
.dsrc__savebar[data-dirty="true"] .dsrc__savestate-clean{display:none}
.dsrc__savebar[data-dirty="true"] .dsrc__savestate-dirty{display:inline-flex}
.dsrc__savebar[data-dirty="false"] .btn--primary{opacity:.55}
/* Provenance strip: header chrome inside the summary panel. */
.dsrc__prov{display:flex; flex-wrap:wrap; align-items:center; gap:8px 12px; margin:-18px -20px 16px; padding:12px 20px; border-bottom:1px solid var(--line); background:var(--inset-bg); color:var(--slate); font-size:var(--fs-3)}
.dsrc__prov .badge{flex:none}
.dsrc__prov strong{color:var(--ink); font-weight:600}
.dsrc__autoflag{margin-bottom:16px}
.dsrc__none{padding:16px 20px}
.dsrc__none p{margin:0}
.dsrc__flags{padding:14px 18px; display:flex; flex-direction:column; gap:10px}
.dsrc__flag{display:flex; gap:10px; align-items:flex-start}
.dsrc__flag .badge{flex:none; margin-top:1px}
.dsrc__manifest{padding:16px 18px; display:flex; flex-direction:column; gap:14px; align-items:flex-start}
.dsrc__manifest .rtable{width:100%}
.dsrc__intake{padding:16px 18px}
.dsrc__intake .form{margin-top:12px}

/* ---- Week data detail (/w/<slug>): one week across every source ---- */
.wkd__perma{margin:6px 0 0; font-size:var(--fs-1); letter-spacing:.04em; word-break:break-all}
.wkd__head-actions{display:flex; align-items:flex-start; gap:8px}
.wkd__ready{display:flex; flex-direction:column; gap:8px; margin-bottom:16px}
.wkd__ready-head{display:flex; flex-wrap:wrap; align-items:center; gap:10px}
.wkd__ready-head .badge{flex:none}
.wkd__ready-figures{font-family:var(--serif); font-size:var(--fs-5); color:var(--ink-strong)}
.wkd__ready-note{margin:0; color:var(--slate); max-width:78ch}
.wkd__ready .field__hint{margin:0}
.wkd__notes{display:flex; flex-direction:column; gap:8px; margin-bottom:16px}
.wkd__note{display:flex; gap:8px; align-items:flex-start; margin:0; color:var(--slate); font-size:var(--fs-3)}
.wkd__note svg{flex:none; margin-top:3px}
.wkd__cats{display:flex; flex-direction:column; gap:12px}
.wkd__cat{padding:0}
/* The summary IS the category row; the same track list drives the
   non-interactive "no feed connected" rows so all five line up. The two-class
   selector is deliberate: the shared disclosure primitive further down the
   file sets `details[data-acc] > summary{display:flex}`, which would otherwise
   win the cascade and leave only the non-summary rows on the grid. */
.wkd__cat > .wkd__cat-sum,
.wkd__cat--none > .wkd__cat-sum{display:grid;
  grid-template-columns:minmax(0,2.4fr) minmax(0,.95fr) minmax(0,.85fr) minmax(0,1.1fr) minmax(0,.55fr);
  gap:12px; align-items:center; padding:14px 18px 14px 36px; position:relative}
/* The primitive's own chevron, lifted out of the grid flow (it would otherwise
   claim the first track). Left as a plain offset so the [open] rotation the
   primitive applies still lands. */
.wkd__cat > .wkd__cat-sum::before{position:absolute; left:16px; top:22px}
.wkd__cat-name{display:flex; flex-direction:column; gap:3px; min-width:0; font-family:var(--serif); font-size:var(--fs-4); color:var(--ink-strong)}
.wkd__cat-name em{font-family:var(--sans); font-style:normal; font-size:var(--fs-2); color:var(--slate)}
.wkd__cat-count{font-size:var(--fs-3); color:var(--ink)}
.wkd__cat-sum .badge{justify-self:start}
.wkd__cat--none{opacity:.75}
.wkd__feeds{border:0; border-top:1px solid var(--line)}
.rtable--wkfeeds .rtable__head,.rtable--wkfeeds .rtable__row{grid-template-columns:minmax(0,1.5fr) minmax(0,1fr) minmax(0,.8fr) minmax(0,1.1fr) minmax(0,.6fr) minmax(0,2fr)}
.rtable--wkfeeds .rtable__head>span{min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.rtable--wkfeeds .rtable__row>span{min-width:0}
.rtable--wkfeeds .rtable__title{display:block; font-size:var(--fs-3)}
.rtable--wkfeeds .rtable__title em{display:block; overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.wkd__feed-note{color:var(--slate); font-size:var(--fs-2); overflow-wrap:anywhere}
/* Stacked (mobile) override. Same cascade caveat as the Data Sources tables:
   it must sit AFTER this file's own track rules to win. */
@media (max-width:900px){
  .wkd__cat > .wkd__cat-sum,
  .wkd__cat--none > .wkd__cat-sum{grid-template-columns:1fr; gap:6px}
  .rtable--wkfeeds .rtable__head{display:none}
  .rtable--wkfeeds .rtable__row{grid-template-columns:1fr 1fr; gap:8px}
  .rtable--wkfeeds .rtable__title{white-space:normal; overflow-wrap:anywhere}
  .rtable--wkfeeds .rtable__title em{white-space:normal}
}

/* Panels driven by the shared tab component (static/js/tabs.js). The tab
   controls themselves live with the .tabs component near the topbar rules. */
.tabpanel[hidden]{display:none}
.subpanel[hidden]{display:none}

/* Manage-sources table shares the dsrc column plumbing above. */
/* Type needs room for its longest option ("S3 landing pad") so the collapsed
   select never clips mid-word; "Last updated" is short ("5 days ago"). */
.rtable--dsrcmanage .rtable__head,.rtable--dsrcmanage .rtable__row{grid-template-columns:minmax(0,1.7fr) minmax(0,1.5fr) minmax(0,.7fr) minmax(0,1fr) minmax(0,1.4fr)}
.rtable--dsrcmanage .rtable__head>span{min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.rtable--dsrcmanage .rtable__row>span{min-width:0}
.rtable--dsrcmanage .rtable__title{display:block; overflow:hidden; white-space:nowrap; text-overflow:ellipsis}
.rtable--dsrcmanage .input{width:100%}

/* ---- Inline anchored comments (admin-only; stripped for viewers) ---- */
.docwrap.cmt-on .docmain{position:relative}
.docwrap.cmt-on.cmt-has .docmain{padding-right:200px}
.cmt-gutter{position:absolute; top:0; right:0; bottom:0; width:188px; pointer-events:none}
.cmt-gutter__toggle{pointer-events:auto; position:absolute; top:24px; right:0; width:170px; background:transparent; border:1px solid var(--line); color:var(--slate); font-size:var(--fs-1); letter-spacing:.12em; text-transform:uppercase; padding:6px 8px; cursor:pointer; border-radius:0}
.cmt-gutter__toggle:hover,.cmt-gutter__toggle.is-on{color:var(--ink-strong); border-color:var(--line-strong)}

/* highlights + element outlines */
mark[data-cmt],.cmt-hl{background:rgba(240,196,80,.42); color:inherit; padding:0 1px; border-radius:2px; box-shadow:inset 0 -2px 0 rgba(240,196,80,.9); cursor:pointer; transition:background-color var(--dur-fast) var(--ease-out)}
mark[data-cmt].is-hot,.cmt-hl.is-hot{background:rgba(240,196,80,.62); box-shadow:inset 0 -2px 0 rgba(240,196,80,1); outline:1px solid rgba(240,196,80,.9)}
mark[data-cmt].cmt-hl--dim,.cmt-hl.cmt-hl--dim{background:transparent; outline:none; box-shadow:none; cursor:inherit}
mark[data-cmt].cmt-hl--resolved:not(.cmt-hl--dim),.cmt-hl.cmt-hl--resolved:not(.cmt-hl--dim){background:rgba(240,196,80,.16); box-shadow:none}
@media (prefers-color-scheme: light){
  mark[data-cmt],.cmt-hl{background:rgba(214,158,20,.30); box-shadow:inset 0 -2px 0 rgba(163,117,9,.85)}
  mark[data-cmt].is-hot,.cmt-hl.is-hot{background:rgba(214,158,20,.5); box-shadow:inset 0 -2px 0 rgba(163,117,9,1); outline-color:rgba(163,117,9,.7)}
  mark[data-cmt].cmt-hl--resolved:not(.cmt-hl--dim),.cmt-hl.cmt-hl--resolved:not(.cmt-hl--dim){background:rgba(214,158,20,.16)}
}
.cmt-outline{outline:2px dashed rgba(240,196,80,.7); outline-offset:4px}
.cmt-outline--hot,.cmt-outline--pending{outline:2px solid rgba(240,196,80,.85); outline-offset:4px}
.cmt-outline--resolved{outline-color:rgba(240,196,80,.25)}

/* gutter bubbles — chat-style speech bubbles with a left tail pointing at the anchored text */
.cmt-bubble{pointer-events:auto; position:absolute; right:0; width:170px; display:flex; align-items:flex-start; gap:8px; text-align:left; background:var(--panel-2); border:1px solid var(--line); border-radius:12px; border-top-left-radius:3px; padding:8px 9px; cursor:pointer; transition:border-color var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out); z-index:5}
/* tail: rotated square sharing the bubble's background + border (inherits state colors/styles) */
.cmt-bubble::before{content:""; position:absolute; left:-5px; top:12px; width:9px; height:9px; background:inherit; border-left:inherit; border-bottom:inherit; border-top:none; border-right:none; transform:rotate(45deg); border-bottom-left-radius:2px}
.cmt-bubble:hover,.cmt-bubble.is-hot,.cmt-bubble:focus-visible{border-color:var(--slate); z-index:6; transform:translateX(var(--motion-lift)); box-shadow:var(--shadow-modal)}
.cmt-bubble:focus-visible{outline:var(--focus-w) solid var(--crimson); outline-offset:2px}
.cmt-bubble .avatar{--avatar-size:26px}
.cmt-bubble__body{min-width:0; flex:1}
.cmt-bubble__name{display:block; font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.08em; text-transform:uppercase; color:var(--ink-strong); white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.cmt-bubble__preview{display:block; font-size:var(--fs-2); color:var(--slate); line-height:1.4; white-space:nowrap; overflow:hidden; text-overflow:ellipsis}
.cmt-bubble__count{flex:0 0 auto; min-width:16px; height:16px; line-height:16px; text-align:center; font-size:var(--fs-1); background:var(--hover-tint); border:1px solid var(--line); color:var(--slate); padding:0 3px; border-radius:8px}
.cmt-bubble--resolved{opacity:.55}
.cmt-bubble--orphan{border-style:dashed}
.cmt-orphan-flag,.cmt-m__flag--orphan{color:var(--crimson-bright)}
.cmt-m__flag{font-size:var(--fs-1); letter-spacing:.14em; border:1px solid var(--line); padding:1px 5px; margin-left:8px; color:var(--slate)}

/* narrow viewports: avatar-only bubbles so content is never covered */
@media (max-width:1100px){
  .docwrap.cmt-on.cmt-has .docmain{padding-right:56px}
  .cmt-gutter{width:48px}
  .cmt-gutter__toggle{width:44px; overflow:hidden; white-space:nowrap; text-indent:-999px}
  .cmt-gutter__toggle::after{content:"✓"; text-indent:0; float:left; width:100%; text-align:center}
  .cmt-bubble{width:42px; justify-content:center; border-radius:50%; border-top-left-radius:8px; padding:7px}
  .cmt-bubble::before{top:10px}
  .cmt-bubble__body,.cmt-bubble__count{display:none}
}

/* floating + Comment button, composer popover, toast */
.cmt-fab{position:absolute; z-index:80}
.cmt-pop{position:absolute; z-index:90; width:300px; background:var(--modal-grad, var(--panel-grad)); border:1px solid var(--line-strong); box-shadow:var(--shadow-modal); padding:12px; display:flex; flex-direction:column; gap:8px}
.cmt-pop__quote{font-size:var(--fs-2); color:var(--slate); border-left:2px solid rgba(240,196,80,.7); padding:2px 0 2px 8px; font-style:italic}
.cmt-pop__quote--el{font-style:normal; font-size:var(--fs-2); letter-spacing:.1em; text-transform:uppercase}
.cmt-pop__row{display:flex; justify-content:flex-end; gap:8px}
.cmt-toast{position:absolute; z-index:120; background:#0d1826; color:#f4f0e8; border:1px solid rgba(143,163,187,.25); padding:6px 10px; font-size:var(--fs-2); letter-spacing:.06em; opacity:1; transition:opacity var(--dur-fast) var(--ease-in)}
.cmt-toast.is-out{opacity:0}

/* thread modal */
.cmt-m{width:520px}
.cmt-m__list{display:flex; flex-direction:column; gap:14px; margin:14px 0; max-height:50vh; overflow-y:auto}
.cmt-m__item{border:1px solid var(--line); padding:10px 12px}
.cmt-m__item--root{border-color:var(--line-strong)}
.cmt-m__head{display:flex; align-items:center; gap:8px}
.cmt-m__who{min-width:0; flex:1; display:flex; flex-direction:column}
.cmt-m__name{font-family:var(--mono); font-size:var(--fs-2); letter-spacing:.08em; text-transform:uppercase; color:var(--ink-strong)}
.cmt-m__time{font-size:var(--fs-1); color:var(--slate-dim)}
.cmt-m__body{margin-top:6px; font-size:var(--fs-3); line-height:1.5; white-space:pre-wrap}
.cmt-m__reply{display:flex; gap:8px; align-items:flex-start; margin-bottom:12px}
.cmt-m__reply textarea{flex:1}
.cmt-m__actions{display:flex; justify-content:flex-end; gap:8px}
.cmt-m__orphannote{font-size:var(--fs-2); color:var(--slate); margin:8px 0 0}
.cmt__orphan{margin-left:auto; font-size:var(--fs-1); letter-spacing:.14em; border:1px dashed var(--line-strong); color:var(--crimson-bright); padding:1px 5px}

/* ---- Reviewer diff view (Show changes) — admin-only ---------------------- */
.diffblk{position:relative; border-left:3px solid var(--line-strong); padding:6px 0 6px 14px; margin:4px 0 4px -17px}
.diffblk--added{border-left-color:#3FB950; background:rgba(63,185,80,.07)}
.diffblk--modified{border-left-color:#D9A441; background:rgba(217,164,65,.07)}
.diffblk--moved{border-left-color:#58A6FF; background:rgba(88,166,255,.06)}
.diffblk--removed{border-left-color:#F85149; background:rgba(248,81,73,.06); opacity:.8}
.diffblk--removed .sec, .diffblk--removed p, .diffblk--removed li,
.diffblk--removed td, .diffblk--removed .callout__body,
.diffblk--removed .signal__name, .diffblk--removed .signal__sheds{text-decoration:line-through; text-decoration-color:rgba(248,81,73,.7)}
.diffchip{display:inline-flex; align-items:center; gap:5px; font-size:var(--fs-2); letter-spacing:.08em; text-transform:uppercase; font-weight:600; padding:1px 7px; border:1px solid var(--line-strong); border-radius:999px; margin-bottom:4px; color:var(--slate); background:var(--panel)}
.diffchip--added{color:#3FB950; border-color:rgba(63,185,80,.5)}
.diffchip--modified{color:#D9A441; border-color:rgba(217,164,65,.5)}
.diffchip--moved{color:#58A6FF; border-color:rgba(88,166,255,.5)}
.diffchip--removed{color:#F85149; border-color:rgba(248,81,73,.5)}
ins.diff-ins{background:rgba(63,185,80,.22); color:inherit; text-decoration:none; border-radius:2px; padding:0 1px}
del.diff-del{background:rgba(248,81,73,.20); color:inherit; text-decoration:line-through; text-decoration-color:rgba(248,81,73,.8); border-radius:2px; padding:0 1px}
.stripbtn--active{background:var(--panel-2); box-shadow:inset 0 0 0 1px var(--line-strong)}
.diffbanner{margin-bottom:14px}
@media (prefers-color-scheme: light){
  .diffblk--added{border-left-color:#2E7D53; background:rgba(46,125,83,.08)}
  .diffblk--modified{border-left-color:#B07E1F; background:rgba(176,126,31,.08)}
  .diffblk--moved{border-left-color:#2563AB; background:rgba(37,99,171,.07)}
  .diffblk--removed{border-left-color:#A81624; background:rgba(168,22,36,.06)}
  .diffchip--added{color:#2E7D53; border-color:rgba(46,125,83,.5)}
  .diffchip--modified{color:#B07E1F; border-color:rgba(176,126,31,.5)}
  .diffchip--moved{color:#2563AB; border-color:rgba(37,99,171,.5)}
  .diffchip--removed{color:#A81624; border-color:rgba(168,22,36,.5)}
  ins.diff-ins{background:rgba(46,125,83,.18)}
  del.diff-del{background:rgba(168,22,36,.14); text-decoration-color:rgba(168,22,36,.8)}
}

/* Per-viewer permissions panel (Users page) */
.permaddform{display:flex; gap:8px; align-items:flex-start}
.permaddform .regionselect{flex:1; min-width:0}
.permaddform select.input{flex:1; min-width:0}
.permintro{font-size:var(--fs-3); margin:0 0 4px}
.chip--perm form{display:inline-flex}
.permempty{font-size:var(--fs-3); margin:0}
.permhist{display:flex; flex-direction:column}
.permhist__row{display:flex; gap:12px; align-items:baseline; padding:7px 2px; border-bottom:1px solid var(--combobox-line)}
.permhist__row:last-child{border-bottom:none}
.permhist__when{flex:0 0 110px; font-size:var(--fs-2)}
.permhist__what{font-size:var(--fs-3); color:var(--ink)}
.permhist__by{font-style:normal; font-family:var(--mono); font-size:var(--fs-2); color:var(--slate)}
.permhist__what .badge{margin-left:6px}

/* --- Response feedback layer: press, success, enter/exit, status ----------
   highlights. All on the shared motion tokens, so the single reduced-motion
   block at the end of this file neutralises the movement (and only the
   movement) without a rule of its own here. */

/* Press acknowledgment: controls dip briefly while held */
.btn,.stripbtn,.toolbtn,.iconbtn,.rte__btn,.wkcal__btn,.wkcal__default,
.modal__close,.cs-btn,.ed-chip,.blk__insert,.chip button,.rail__tab,.rowmenu__trigger{
  transition:color var(--dur-fast) var(--ease-out),
             background-color var(--dur-fast) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out),
             opacity var(--dur-fast) var(--ease-out),
             transform var(--dur-instant) var(--ease-out)}
.btn:active:not(.is-loading),.stripbtn:active,.toolbtn:active,.iconbtn:active,
.rte__btn:active,.wkcal__btn:active,.wkcal__default:active,.modal__close:active,
.cs-btn:active,.ed-chip:active,.blk__insert:active,.chip button:active,
.rowmenu__trigger:active,.menu__item:active,.usermenu__panel a:active,.usermenu__signout:active{
  transform:scale(var(--motion-press))}

/* Success confirmations: a brief pop + a fading ring. The ring is a
   pseudo-element that scales and fades — box-shadow is never animated. */
@keyframes motionPop{0%{transform:scale(var(--motion-pop-from)); opacity:0}60%{transform:scale(var(--motion-pop-peak))}100%{transform:none; opacity:1}}
@keyframes motionPopY{0%{transform:translateY(-50%) scale(var(--motion-pop-from)); opacity:0}60%{transform:translateY(-50%) scale(var(--motion-pop-peak))}100%{transform:translateY(-50%) scale(1); opacity:1}}
@keyframes motionRing{from{opacity:.9}to{opacity:0}}
.btn.is-copied,.flash--success{position:relative}
.btn.is-copied::after,.flash--success::after{content:""; position:absolute; inset:0; pointer-events:none;
  box-shadow:0 0 0 9px var(--focus-ring); border-radius:inherit; opacity:0;
  animation:motionRing var(--dur-slow) var(--ease-out)}
.rtable__title.is-copied .copyfb{animation:motionPopY var(--dur-slow) var(--ease-out)}
.btn.is-copied{border-color:var(--badge-clear-line); color:var(--badge-clear-ink)}
.step--ok .step__icon{animation:motionPop var(--dur-slow) var(--ease-out)}
.flash--success{animation:motionRiseIn var(--dur-base) var(--ease-out)}

/* Enter transitions for dynamically added content */
@keyframes motionLeave{to{opacity:0; transform:scale(var(--motion-leave-to))}}
.rail__panel .cmt,.cmt-bubble,.cmt-m__item{animation:motionRiseIn var(--dur-base) var(--ease-out)}
.mselect__chips .chip,.auditapplied .chip,.sharecreate ~ .linklist--modal .linkcard,.peoplerow{animation:motionRiseIn var(--dur-base) var(--ease-out)}
.combobox__option,.mselect__opt{animation:motionFadeIn var(--dur-base) var(--ease-out)}
.rowmenu__panel:not([hidden]){animation:motionMenuIn var(--dur-base) var(--ease-out)}
.menu--open .menu__pop{animation:motionMenuIn var(--dur-base) var(--ease-out)}
.palette{animation:motionMenuIn var(--dur-base) var(--ease-out)}
.cmt-pop{animation:motionModalIn var(--dur-slow) var(--ease-out)}
.cmt-fab{animation:motionPop var(--dur-base) var(--ease-out)}
/* Animated cards: keep their paint work to themselves. */
.rtoast,.cmt-bubble,.linkcard{contain:paint}
/* Exit: leaving is shorter than entering and uses --ease-in. JS adds
   .is-leaving, waits for --dur-fast (read from the token), then removes it. */
.is-leaving{animation:motionLeave var(--dur-fast) var(--ease-in) both; pointer-events:none}

/* Status / badge / count changes draw the eye briefly */
@keyframes motionHighlight{0%{background-color:var(--hover-tint)}100%{background-color:transparent}}
.is-updated{animation:motionPop var(--dur-base) var(--ease-out)}
/* A row whose state just changed on its own (a generation run finishing while
   the dashboard is open) flashes its background once and fades back. Bounded:
   one pass at --dur-hold, then the row is still again. */
.row-highlight{animation:motionHighlight var(--dur-hold) var(--ease-out)}

/* Optimistic UI: the result of a user's action is painted immediately at the
   fast duration; if the request then fails, the revert is animated at the base
   duration (slower, so the value visibly going back is not missed) and a toast
   explains it. Both are opacity-only, so nothing shifts. */
.is-applied{animation:motionFadeIn var(--dur-fast) var(--ease-out)}
.is-reverted{animation:motionFadeIn var(--dur-base) var(--ease-out)}

/* The third and last --ease-emphasis moment in the app (the other two — a
   successful publish/share and a resolved comment thread — live in the
   micro-interaction section below): a briefing has
   finished generating. The card carrying it pops in and its ring pulses once
   — fired once per run, never looping, and never on a route change. The ring
   is inset so hosts that `contain:paint` (the run toast) still show it. */
.motion-celebrate{position:relative; animation:motionPop var(--dur-slow) var(--ease-emphasis)}
.motion-celebrate::after{content:""; position:absolute; inset:0; pointer-events:none;
  box-shadow:inset 0 0 0 3px var(--focus-ring); opacity:0;
  animation:motionRing var(--dur-slow) var(--ease-emphasis)}

/* Save state: "Saving…" → "All changes saved" crossfades in place, and the
   check draws itself in rather than appearing whole. Stroke length is a
   geometry constant, not a duration — the timing is all tokens. */
@keyframes motionDraw{from{stroke-dashoffset:var(--draw-len)}to{stroke-dashoffset:0}}
.docbar__saved-text.is-swapped{animation:motionFadeIn var(--dur-base) var(--ease-out)}
.docbar__saved--ok .docbar__saved-icon--check .icon path{--draw-len:28px; stroke-dasharray:28px;
  stroke-dashoffset:0; animation:motionDraw var(--dur-base) var(--ease-out)}


/* --------------------------------------------------------------------- *
 * Data overview (admin homepage) — task 179
 * Combined map + external context feeds + pathogen-trend chart + headline
 * counts + AI situational summary, rendered from a stored snapshot.
 * Appended at end of file so its responsive overrides win the cascade.
 * --------------------------------------------------------------------- */
.ovr{margin:0 0 34px}
.ovr__head{display:flex; justify-content:space-between; align-items:flex-end; gap:16px; flex-wrap:wrap; margin-bottom:16px}
.ovr__title{font-family:var(--serif); font-size:var(--fs-6); font-weight:700; line-height:1.1; margin:6px 0 0}
.ovr__regen{margin:0}
.ovr__body{position:relative; display:flex; flex-direction:column; gap:18px}

.ovr__stamp{display:flex; align-items:center; gap:12px; flex-wrap:wrap}
.ovr__stamp .mono-label{display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-2)}
.ovr__stamp .icon{color:var(--slate-dim)}

/* Headline counts */
.ovr-kpis{display:grid; grid-template-columns:repeat(4,1fr); gap:14px}
.ovr-kpi{display:flex; flex-direction:column; align-items:flex-start; justify-content:center;
  background:var(--panel-grad); border:1px solid var(--line); padding:18px 20px; position:relative}
/* Tabular figures so a counting-up number can't jitter its own width. */
.ovr-kpi__num{font-family:var(--serif); font-size:var(--fs-7); font-weight:700; line-height:1; color:var(--ink-strong);
  font-variant-numeric:tabular-nums}
.ovr-kpi__lab{font-family:var(--mono); text-transform:uppercase; letter-spacing:.16em; font-size:var(--fs-2); color:var(--slate); margin-top:9px}
/* All stat values share one colour treatment; the flagged-signals card carries
   its alert cue on the card outline + label instead of recolouring the number. */
.ovr-kpi--alert{border-color:var(--badge-high-line)}
.ovr-kpi--alert .ovr-kpi__lab{color:var(--badge-high-ink)}

/* AI summary */
.ovr-ai{padding:20px 22px}
.ovr-ai__eyebrow{display:flex; align-items:center; gap:7px; font-family:var(--mono); text-transform:uppercase;
  letter-spacing:.16em; font-size:var(--fs-2); color:var(--slate); margin-bottom:12px}
.ovr-ai__eyebrow .icon{color:var(--crimson-bright)}
.ovr-ai__headline{font-family:var(--serif); font-size:var(--fs-5); font-weight:700; line-height:1.3; color:var(--ink-strong); margin:0 0 8px}
.ovr-ai__body{font-size:var(--fs-body); line-height:1.6; color:var(--ink); margin:0}
.ovr-ai__body b{color:var(--ink-strong)}
.ovr-ai__note{display:flex; align-items:flex-start; gap:6px; font-size:var(--fs-sm); margin:12px 0 0}
.ovr-ai__note .icon{flex:none; margin-top:2px; color:var(--slate-dim)}

/* Inline degraded / error notes */
.ovr__note{display:flex; align-items:flex-start; gap:7px; font-size:var(--fs-sm); margin:0;
  background:var(--callout-info-bg); border:1px solid var(--line); padding:10px 12px}
.ovr__note .icon{flex:none; margin-top:2px; color:var(--amber-ink)}
.ovr__error{font-size:var(--fs-sm); color:var(--error-ink); margin:0 0 4px;
  background:var(--flash-err-bg); border:1px solid var(--badge-high-line); padding:10px 12px}

/* Map + feeds two-column layout */
.ovr__grid{display:grid; grid-template-columns:2fr 1fr; gap:18px; align-items:start}
.ovr__mapcol{min-width:0}
.ovr__mapcol .sec--map{margin:0}
.ovr__mapcol .map__intro{margin-top:0}

/* Fits its content and top-aligns in the grid (no align-self:stretch), so a
   short feed list can't leave a large dead panel beside a tall map. */
.ovr-feeds{padding:18px 20px}
.ovr-feeds__meta{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:12px 0 0}
.ovr-feeds__note{font-size:var(--fs-sm); margin:8px 0 0}
.ovr-feeds__list{list-style:none; margin:14px 0 0; padding:0}
.ovr-feed{padding:11px 0; border-top:1px solid var(--line)}
.ovr-feed:first-child{border-top:0}
.ovr-feed__top{display:flex; align-items:center; justify-content:space-between; gap:10px}
.ovr-feed__name{font-size:var(--fs-sm); color:var(--ink); font-weight:600;
  flex:1 1 auto; min-width:0; overflow-wrap:anywhere}
.ovr-feed__top .badge{flex:none}
.ovr-feed__note{font-size:var(--fs-2); margin:5px 0 0; line-height:1.45}
.ovr-feeds__foot{margin:14px 0 0; padding-top:12px; border-top:1px solid var(--line); font-size:var(--fs-2)}

/* Pathogen-trend chart */
.ovr-trend{padding:18px 20px}
/* Positioning context for the hover tooltip panel. */
.ovr-trend__chart{width:100%; margin-top:14px; position:relative}
.ovr-trend__svg{width:100%; height:auto; display:block; overflow:visible}
.ovr-bar--rising{fill:var(--pin-rising-fill)}
.ovr-bar--watch{fill:var(--amber)}
/* Hover is read off the plot area as a whole (crosshair + panel), so the bars
   themselves never take the pointer. */
.ovr-bar{transform-box:fill-box; transform-origin:bottom; pointer-events:none}
/* Chart draw-in is the one animation allowed past --dur-slow, and it runs
   once, on the render that adds .is-anim: axes and gridlines fade first, then
   the columns grow out of the baseline one stagger step apart. */
.ovr-trend__svg.is-anim .ovr-trend__grid,
.ovr-trend__svg.is-anim .ovr-trend__ytick,
.ovr-trend__svg.is-anim .ovr-trend__xtick,
.ovr-trend__svg.is-anim .ovr-trend__axis-title{animation:motionFadeIn var(--dur-base) var(--ease-out) both}
.ovr-trend__svg.is-anim .ovr-bar{animation:ovr-grow var(--dur-chart) var(--ease-out) both;
  animation-delay:calc(var(--dur-base) + var(--motion-stagger) * var(--bar-i,0))}
/* Data change: the columns travel from their old geometry to the new one
   instead of being redrawn. JS parks each bar on its previous rect, then
   releases the transform on the next frame. */
.ovr-bar.is-tween{transition:transform var(--dur-base) var(--ease-in-out)}
/* Crosshair tracks the pointer with no transition at all — it must feel
   welded to the cursor. */
.ovr-trend__cross{stroke:var(--line-strong); stroke-width:1; stroke-dasharray:2 3; pointer-events:none; opacity:0}
.ovr-trend__svg.is-hover .ovr-trend__cross{opacity:1}
/* The panel fades at instant but travels at ease-out, so hopping between
   neighbouring weeks slides rather than jitters. */
.ovr-trend__tip{position:absolute; left:0; top:0; z-index:2; pointer-events:none; opacity:0;
  min-width:130px; padding:8px 10px; background:var(--panel); border:1px solid var(--line-strong);
  box-shadow:var(--shadow-tip); font-family:var(--mono); font-size:var(--fs-2); color:var(--ink);
  transition:opacity var(--dur-instant) var(--ease-out), transform var(--dur-base) var(--ease-out)}
.ovr-trend__tip.is-on{opacity:1}
.ovr-trend__tip-wk{color:var(--ink-strong); letter-spacing:.06em; margin-bottom:4px}
.ovr-trend__tip-row{display:flex; align-items:center; gap:7px; line-height:1.6}
.ovr-trend__tip-row .ovr-trend__sw{flex:none}
.ovr-trend__tip-val{margin-left:auto; color:var(--ink-strong); font-variant-numeric:tabular-nums}
.ovr-trend__grid{stroke:var(--grid-line); stroke-width:1}
.ovr-trend__ytick,.ovr-trend__xtick{fill:var(--slate); font-family:var(--mono); font-size:var(--fs-1)}
.ovr-trend__axis-title{fill:var(--slate); font-family:var(--mono); font-size:var(--fs-1);
  text-transform:uppercase; letter-spacing:.12em}
.ovr-trend__legend{display:flex; align-items:center; gap:16px; flex-wrap:wrap; margin-top:12px}
.ovr-trend__key{display:inline-flex; align-items:center; gap:6px; font-size:var(--fs-sm); color:var(--slate)}
.ovr-trend__sw{width:11px; height:11px; border-radius:2px; display:inline-block}
.ovr-trend__sw--rising{background:var(--pin-rising-fill)}
.ovr-trend__sw--watch{background:var(--amber)}
.ovr-trend__src{margin-left:auto}
.ovr-trend__note{font-size:var(--fs-sm); margin:10px 0 0}

@keyframes ovr-grow{from{transform:scaleY(var(--motion-grow-from))} to{transform:scaleY(1)}}

/* Regenerate loading overlay */
.ovr-load{position:absolute; inset:0; z-index:5; display:flex; align-items:center; justify-content:center;
  padding:24px; background:color-mix(in srgb, var(--bg) 74%, transparent); backdrop-filter:blur(2px)}
.ovr-load[hidden]{display:none !important}
.ovr-load__card{display:flex; align-items:center; gap:16px; max-width:520px;
  background:var(--panel-grad); border:1px solid var(--line-strong); padding:20px 24px; box-shadow:var(--shadow-modal)}
.ovr-load__spin{flex:none; --spin-size:26px; --spin-stroke:3px; --spin-head:var(--crimson-bright)}
.ovr-load__title{font-family:var(--serif); font-size:var(--fs-4); font-weight:700; color:var(--ink-strong); margin:0}
.ovr-load__sub{font-size:var(--fs-sm); color:var(--slate); margin:5px 0 0; line-height:1.5}
.ovr.is-regenerating .ovr__body > :not(.ovr-load){opacity:.5}

@media (max-width:900px){
  .ovr__grid{grid-template-columns:1fr}
  .ovr-kpis{grid-template-columns:repeat(2,1fr)}
}
@media (max-width:640px){
  .ovr__head{align-items:flex-start}
  .ovr__regen{width:100%}
  .ovr__regen .btn{width:100%; justify-content:center}
}

/* --- Background generation-run toasts (app-wide, bottom-right, admins only) ---
   Colours come from the theme tokens, so light/dark are handled automatically;
   the spinner + slide-in entrance run on the motion tokens, so reduced motion
   is handled by the single block at the end of this file. Sits below modals
   (z-index 60) so an open dialog is never obscured. */
.rtoasts{position:fixed; right:20px; bottom:20px; z-index:50; width:330px;
  max-width:calc(100vw - 32px); display:flex; flex-direction:column-reverse; gap:10px;
  pointer-events:none}
.rtoast{pointer-events:auto; position:relative; background:var(--menu-grad);
  border:1px solid var(--line-strong); box-shadow:var(--shadow-pop);
  padding:13px 32px 13px 14px; display:flex; flex-direction:column; gap:11px;
  opacity:0; transform:translateY(var(--motion-rise));
  transition:opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out)}
.rtoast.is-in{opacity:1; transform:none}
.rtoast__main{display:flex; gap:12px; align-items:flex-start; color:var(--ink)}
.rtoast__main:hover{color:var(--ink-strong)}
.rtoast__icon{flex:0 0 auto; width:20px; height:20px; margin-top:1px;
  display:flex; align-items:center; justify-content:center; color:var(--slate)}
/* Shape comes from the shared spinner rule; the toast only picks the size. */
.rtoast__spin{--spin-size:16px}
.rtoast__text{display:flex; flex-direction:column; gap:2px; min-width:0}
.rtoast__title{font-family:var(--serif); font-size:var(--fs-4); line-height:1.2}
.rtoast__sub{font-family:var(--mono); font-size:var(--fs-2); color:var(--slate);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.rtoast__step{font-family:var(--mono); font-size:var(--fs-2); color:var(--slate-dim);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap}
.rtoast__dismiss{position:absolute; top:7px; right:7px; width:24px; height:24px;
  display:flex; align-items:center; justify-content:center; color:var(--slate);
  background:none; border:1px solid transparent; cursor:pointer; padding:0}
.rtoast__dismiss:hover{color:var(--ink-strong); border-color:var(--line)}
.rtoast__action{display:none}
.rtoast__action .btn{width:100%; justify-content:center}
.rtoast--success .rtoast__icon{color:var(--green)}
.rtoast--success .rtoast__title{color:var(--ink-strong)}
.rtoast--error .rtoast__icon,.rtoast--stalled .rtoast__icon{color:var(--crimson-bright)}
.rtoast--error .rtoast__step{color:var(--error-ink); white-space:normal}
/* App toasts (BRToast) reuse this card — the same stack, the same rise-in. */
.rtoast--info .rtoast__title,.rtoast--error .rtoast__title{color:var(--ink-strong)}
.rtoast--info .rtoast__title{white-space:normal}
.rtoast--error .rtoast__title{white-space:normal}
.rtoast--info .rtoast__icon:empty,.rtoast--error .rtoast__icon:empty{display:none}
.rtoast--stalled .rtoast__step{color:var(--amber-ink); white-space:normal}
@media (max-width:640px){
  .rtoasts{right:12px; left:12px; bottom:12px; width:auto; max-width:none}
}

/* -------------------------------------------------------------------------
   Settings › Template editor tab toolbar (replaces the old 2-row docbar)
   ------------------------------------------------------------------------- */
/* Sticks *below* the app top bar (whose tab chips hang ~13px past its border)
   and behind it in the stacking order, so a scrolled toolbar can never sit over
   the tab bar. .strip has a fixed 40px height; this one wraps, so it must grow
   or the wrapped right-hand chips spill outside the card's border. */
.tpl-toolbar{position:sticky;top:64px;z-index:10;margin:0 0 .9rem;background:var(--bg);padding-top:.3rem}
.tpl-toolbar .strip--bar{display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;
  height:auto;min-height:40px;
  padding:.4rem .5rem;border:1px solid var(--line);border-radius:10px;background:var(--panel)}
.tpl-toolbar__right{margin-left:auto;display:flex;align-items:center;gap:.6rem;padding-right:.2rem}
.tpl-toolbar .docbar__saved{display:inline-flex;align-items:center;gap:.35rem;
  font-size:var(--fs-1);color:var(--slate-dim);white-space:nowrap}


/* ---------------------------------------------------------------------------
   MICRO-INTERACTION MOTION — the shared motion for the controls people touch
   all day. Buttons/inputs get their press, hover and focus feedback from the
   response-feedback layer above (one rule, every variant, danger included);
   this section owns the overlays, tabs, accordions, toast stack, selection
   chips and the "it worked" morphs. Everything rides the tokens at the top of
   the file, so the two reduced-motion switches below neutralise all of it
   without a single rule of its own here.
   -------------------------------------------------------------------------- */

/* ---- Overlay entrance / exit -------------------------------------------
   Dropdowns unfold from the corner nearest their trigger; modals rise and
   settle. Exits are shorter than entrances and use --ease-in. The 4px menu
   drop is half the shared rise token and the menu scale is the shared
   small-surface scale, so reduced motion collapses both to a pure fade. */
@keyframes motionMenuIn{from{opacity:0; transform:translateY(calc(var(--motion-rise) * -.5)) scale(var(--motion-press))}to{opacity:1; transform:none}}
@keyframes motionMenuOut{from{opacity:1; transform:none}to{opacity:0; transform:translateY(calc(var(--motion-rise) * -.5)) scale(var(--motion-press))}}
@keyframes motionFadeOut{from{opacity:1}to{opacity:0}}
@keyframes motionModalOut{from{opacity:1; transform:none}to{opacity:0; transform:translateY(var(--motion-rise)) scale(var(--motion-scale-in))}}

.usermenu__panel,.rowmenu__panel,.menu__pop{transform-origin:top right}
.menu--actions .menu__pop,.palette{transform-origin:top left}
.combobox__list,.mselect__panel,.wkcal__pop{transform-origin:top center}
.menu--closing .menu__pop{animation:motionMenuOut var(--dur-fast) var(--ease-in) both}

/* Modals: the scrim fades and the panel drops back while docbar.js / comments.js
   hold the dialog in the DOM for exactly --dur-base. */
.modal.is-closing{pointer-events:none}
.modal.is-closing .modal__backdrop{animation:motionFadeOut var(--dur-base) var(--ease-in) both}
.modal.is-closing .modal__panel{animation:motionModalOut var(--dur-base) var(--ease-in) both}

/* ---- Tabs: one shared-element indicator --------------------------------
   tabs.js measures the active tab and publishes --tab-x/--tab-w on the list, so
   the marker slides AND resizes through a single transform — no width
   animation, and it never jumps between tabs. The per-tab bottom border stays
   as the no-JS fallback and steps aside once the indicator exists. */
.tabs__list{position:relative}
.tabs__ind{position:absolute; left:0; bottom:-1px; width:1px; height:2px;
  background:var(--crimson-bright); transform-origin:left center;
  transform:translateX(var(--tab-x,0)) scaleX(var(--tab-w,0)); pointer-events:none;
  transition:transform var(--dur-base) var(--ease-in-out)}
.tabs__list.has-ind .tabs__tab.is-active,
.tabs__list.has-ind .rail__tab.is-active{border-bottom-color:transparent}
.rail__tabs .tabs__ind{background:var(--crimson)}
/* Panel content crossfades up on every change. The panel's HEIGHT is never
   animated — it snaps to the new content and only the content moves. */
[data-tabpanel].is-entering,.tabpanel.is-entering{animation:motionRiseIn var(--dur-base) var(--ease-out)}

/* ---- Accordions ---------------------------------------------------------
   The one place a layout property is animated: grid-template-rows 0fr -> 1fr
   reveals content of unknown height without measuring it in JS. The content
   fades in over the final 60% of the reveal and the chevron turns 180°.
   micro.js wraps the content and holds [open] until a collapse finishes. */
details[data-acc]{--acc-dur:var(--dur-base)}
details[data-acc] > summary{list-style:none; display:flex; align-items:center; gap:8px; cursor:pointer}
details[data-acc] > summary::-webkit-details-marker{display:none}
details[data-acc] > summary::before{content:""; flex:none; width:6px; height:6px; margin-right:1px;
  border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
  transform:rotate(45deg); transition:transform var(--acc-dur) var(--ease-out)}
details[data-acc][open]:not([data-acc-closing]) > summary::before{transform:rotate(225deg)}
.acc__wrap{display:grid; grid-template-rows:0fr;
  transition:grid-template-rows var(--acc-dur) var(--ease-out)}
details[data-acc][open] .acc__wrap{grid-template-rows:1fr}
details[data-acc][open][data-acc-closing] .acc__wrap{grid-template-rows:0fr}
.acc__inner{overflow:hidden; min-height:0; opacity:0;
  transition:opacity calc(var(--acc-dur) * .6) var(--ease-out)}
details[data-acc][open] .acc__inner{opacity:1; transition-delay:calc(var(--acc-dur) * .4)}
details[data-acc][open][data-acc-closing] .acc__inner{opacity:0; transition-delay:var(--delay-0)}

/* ---- Toasts ------------------------------------------------------------
   Entrance and auto-dismiss already ride the tokens (.rtoast / .cmt-toast
   above). This is the stack reflow: when one card leaves, runtoasts.js FLIPs
   the survivors so the stack slides into its new position. */
.rtoast.is-reflow{transition:transform var(--dur-base) var(--ease-in-out)}
.cmt-toast{animation:motionRiseIn var(--dur-base) var(--ease-out)}

/* ---- Selection: chips, filter pills, map legend -----------------------
   Selection is a colour crossfade only — no movement, no width change (chips
   pick their crossfade up from the shared hover/focus block above). */
.map__key-item{transition:color var(--dur-fast) var(--ease-out)}
.map__swatch{transition:box-shadow var(--dur-fast) var(--ease-out)}

/* ---- Icon -> checkmark morph ------------------------------------------
   ONE implementation, two callers: copy-to-clipboard feedback (standard
   easing, label crossfades with it) and the publish/share success moment
   (--ease-emphasis, which the whole app spends on just three delight
   moments). micro.js wraps a button's leading icon and adds the check, so the
   two never move the button's width. */
.btn__ico{position:relative; display:inline-flex; align-items:center; justify-content:center; flex:none}
.btn__ico .icon{transition:opacity var(--dur-fast) var(--ease-out)}
.btn__check{position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
  opacity:0; pointer-events:none; transition:opacity var(--dur-fast) var(--ease-out)}
.is-checked .btn__ico .icon{opacity:0}
.is-checked .btn__check{opacity:1}
.is-checked .btn__label{animation:motionFadeIn var(--dur-fast) var(--ease-out)}
/* Delight moment 1 of 2: a successful publish or share pops the checkmark in,
   once per success. */
.is-checked--delight .btn__check{animation:motionPop var(--dur-base) var(--ease-emphasis)}

/* Delight moment 2 of 2: a resolved thread settles with a single bounce as its
   card collapses out of the open list. */
@keyframes motionSettle{from{transform:scale(var(--motion-pop-peak))}to{transform:none}}
.cmt--settling{animation:motionSettle var(--dur-base) var(--ease-emphasis)}

/* ----------------------------------------------------------------------------
   DATA-VISUALISATION MOTION — draw-in and value tweening for the surfaces
   where movement carries meaning: sparklines, the heat/anchor markers, popups
   and threshold crossings. Everything below is transform/opacity/colour only,
   drives off the motion tokens, and is neutralised by the reduced-motion
   switch at the bottom of this file.
   -------------------------------------------------------------------------- */

/* Sparkline draw-in. JS arms each card (dash offsets + .is-armed) only when it
   is about to draw; without JS the sparkline renders complete. The line draws
   over the chart duration, then the fill/labels fade in at ~60% progress so
   the shape leads and the area follows. --sig-delay is the card-to-card
   stagger, set inline as cards enter the viewport. */
.sig-trend.is-armed .sig-trend__line{transition:stroke-dashoffset var(--dur-chart) var(--ease-out);
  transition-delay:var(--sig-delay,0s)}
.sig-trend.is-armed .sig-trend__area,
.sig-trend.is-armed .sig-trend__dot,
.sig-trend.is-armed .sig-trend__vlab{opacity:0;
  transition:opacity calc(var(--dur-chart) * .4) var(--ease-out);
  transition-delay:calc(var(--sig-delay,0s) + var(--dur-chart) * .6)}
.sig-trend.is-armed.is-drawn .sig-trend__area{opacity:var(--sig-area-op)}
.sig-trend.is-armed.is-drawn .sig-trend__dot,
.sig-trend.is-armed.is-drawn .sig-trend__vlab{opacity:1}

/* Map markers: colour, dimming and intensity all tween on a week or pathogen
   switch — a site's glow travels from its old value to its new one. The
   selection scale is quicker (--dur-fast) so picking a site feels immediate.
   The tile layer is never animated (Leaflet's own fade is switched off in JS). */
.map-glow__i,.map-anchor{transition:background-color var(--dur-base) var(--ease-in-out),
  opacity var(--dur-base) var(--ease-in-out),
  transform var(--dur-base) var(--ease-in-out)}
.map-anchor.is-sel{transform:scale(calc(var(--anchor-s,1) * var(--motion-pop-peak)));
  transition:transform var(--dur-fast) var(--ease-out)}
/* Entrance: markers and glows scale up from --motion-pin-from, one stagger
   step apart. Only a `from` frame, so the resting state stays whatever the
   custom properties say; JS drops .is-enter once it has played. */
@keyframes motionPinIn{from{opacity:0; transform:scale(var(--motion-pin-from))}}
.map-glow.is-enter .map-glow__i,
.map-anchor-ic.is-enter .map-anchor{animation:motionPinIn var(--dur-base) var(--ease-out) both;
  animation-delay:calc(var(--motion-stagger) * var(--pin-i,0))}
/* Selection ring: one outward pulse, never a loop. */
.map-anchor::after{content:""; position:absolute; inset:0; border-radius:50%; pointer-events:none;
  border:1px solid var(--anchor-c,var(--slate-dim)); opacity:0}
.map-anchor.is-ping::after{animation:motionPinRing var(--dur-slow) var(--ease-out) 1}
@keyframes motionPinRing{from{opacity:.9; transform:scale(1)}to{opacity:0; transform:scale(var(--motion-ring-to))}}
/* Popups fade and rise. The animation sits on the content wrapper, never on
   .leaflet-popup itself — Leaflet owns that element's transform. */
.mappop-wrap .leaflet-popup-content-wrapper{animation:motionRiseIn var(--dur-base) var(--ease-out)}

/* Threshold crossings: the badge ticks once (the shared .is-updated pop) and
   the card's severity border crossfades. Never a persistent loop. */
.signal{transition:border-left-color var(--dur-base) var(--ease-in-out)}
.mapsig__badge{transition:color var(--dur-base) var(--ease-in-out),
  background-color var(--dur-base) var(--ease-in-out),
  border-color var(--dur-base) var(--ease-in-out)}

/* Values that change too often to count up crossfade instead: JS marks the
   element swappable once (so the fade back in transitions too) and toggles
   .is-swapping around the text change. */
.is-swappable{transition:opacity var(--dur-fast) var(--ease-in-out)}
.is-swapping{opacity:0}
[data-countup],.mapsig__status,.map__scrub-label{font-variant-numeric:tabular-nums}

/* ---------------------------------------------------------------------------
   ROWS, CARDS & LISTS — the motion that makes a list legible.
   Kept late (just above the reduced-motion switches) so these hover treatments
   win over the component rules that define the rows and cards themselves.
   Everything rides the shared tokens, so the two switches below neutralise it
   without a rule of its own: the durations collapse to --dur-nil (feedback
   still happens, it just arrives at once), --motion-lift and --motion-rise
   collapse to --motion-still (the lift and the rise become pure opacity) and
   --motion-stagger collapses to --delay-0. The JS half (rowmotion.js) asks
   BRMotion.reduced() and skips the stagger, the removal slide and the FLIP
   outright.
   Only opacity and transform ever animate here — never width, height, padding
   or margin — so nothing in this block can shift the layout.
   -------------------------------------------------------------------------- */

/* --- Rows: background crossfade + a 2px left accent bar on hover ----------
   A dense table must not move under the pointer, so a hovered row NEVER
   transforms: the background crossfades at --dur-instant while a 2px bar
   scales in on the Y axis. The bar is an absolutely positioned pseudo-element,
   so it sits outside the row's grid/table flow and costs nothing in layout. On
   a <tr> it hangs off the first cell instead — a table row makes a poor
   containing block, and the first cell already stretches to the row's full
   height, so the result is identical. */
.rtable__row,
.auditlist__row:not(.auditlist__row--empty),
.runrow:not(.runrow--head),
.regtable tbody tr{
  transition:color var(--dur-instant) var(--ease-out),
             background-color var(--dur-instant) var(--ease-out),
             border-color var(--dur-instant) var(--ease-out)}
.rtable__row,
.auditlist__row:not(.auditlist__row--empty),
.runrow:not(.runrow--head),
.regtable tbody td:first-child{position:relative}
.rtable__row::before,
.auditlist__row:not(.auditlist__row--empty)::before,
.runrow:not(.runrow--head)::before,
.regtable tbody td:first-child::before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:2px; z-index:1;
  background:var(--crimson); pointer-events:none;
  transform:scaleY(0); transform-origin:50% 50%;
  transition:transform var(--dur-instant) var(--ease-out)}
.rtable__row:hover::before,
.auditlist__row:not(.auditlist__row--empty):hover::before,
.runrow:not(.runrow--head):hover::before,
.regtable tbody tr:hover td:first-child::before{transform:scaleY(1)}
/* The audit log had no hover feedback at all: give it the shared row tint. */
.auditlist__row:not(.auditlist__row--empty):hover{background:var(--hover-row)}

/* --- Cards: the hover lift is reserved for clickable cards ----------------
   A lift promises "activating this does something", so it is keyed on real
   interactivity: the card IS a link or a button, exposes role="button", or
   carries .is-clickable because JS activates the whole card. Informational
   stat/signal/source cards stay flat on purpose — that is exactly what keeps
   the lift meaningful. Elevation rides a pseudo-element's opacity; the shadow
   itself is never animated. */
:is(.stat,.ovr-kpi,.signal,.mapsig__sig,.linkcard,.dsrc__flag,.countycard):is(a[href],button,[role="button"],.is-clickable){
  position:relative;
  transition:transform var(--dur-fast) var(--ease-out)}
:is(.stat,.ovr-kpi,.signal,.mapsig__sig,.linkcard,.dsrc__flag,.countycard):is(a[href],button,[role="button"],.is-clickable)::after{
  content:""; position:absolute; inset:0; pointer-events:none; opacity:0;
  box-shadow:var(--shadow-tip);
  transition:opacity var(--dur-fast) var(--ease-out)}
:is(.stat,.ovr-kpi,.signal,.mapsig__sig,.linkcard,.dsrc__flag,.countycard):is(a[href],button,[role="button"],.is-clickable):hover{
  transform:translateY(var(--motion-lift))}
:is(.stat,.ovr-kpi,.signal,.mapsig__sig,.linkcard,.dsrc__flag,.countycard):is(a[href],button,[role="button"],.is-clickable):hover::after{
  opacity:1}

/* --- List entrance: one capped stagger, on first render only --------------
   rowmotion.js tags the items of a [data-list-enter] container with .br-enter
   and an --enter-i index. The index is capped there (eight items, a quarter of
   a second) so a long list never queues a slow cascade, and it runs once per
   list per session: this is a "the list just arrived" cue, not a scroll
   effect. */
.br-enter{animation:motionRiseIn var(--dur-base) var(--ease-out) both;
  animation-delay:calc(var(--motion-stagger) * var(--enter-i,0))}

/* A row that arrives on its own (a source added, older audit entries loaded)
   fades in where it lands — nothing to stagger against. */
.br-inserted{animation:motionRiseIn var(--dur-base) var(--ease-out) both}

/* A leaving row stops being interactive the moment it starts to go. Its fade
   and the neighbours' slide are driven by rowmotion.js through the Web
   Animations API — opacity and transform only, so a collapsing row never
   animates a layout property. */
.br-removing{pointer-events:none}

/* --- Skeleton → content crossfade ----------------------------------------
   Loading is one shimmer app-wide (see the .skel block); arriving is one
   crossfade. rowmotion.js lifts the skeleton into this overlay, which fades
   out while the real content fades in underneath over the same beat, so the
   swap is never a cut. The overlay is out of flow and the skeleton mirrors the
   real rows' metrics, so nothing shifts in either direction. */
.br-swap{position:relative}
.br-swap-out{position:absolute; inset:0; pointer-events:none; z-index:2}
.br-swap-in > :not(.br-swap-out){animation:motionFadeIn var(--dur-base) var(--ease-out)}

/* ----------------------------------------------------------------------------
   REDUCED MOTION — the one and only place movement is neutralised.
   Two switches, one behaviour:
     · @media (prefers-reduced-motion: reduce) below — the OS setting, honoured
       unless the reader explicitly chose full motion on /account;
     · html[data-motion="reduced"] — the /account preference, server-rendered
       on <html>, which also applies when the OS says nothing.
   Neither one says "animation:none". Instead both route the motion tokens onto
   their resting values, so:
     · every duration becomes --dur-nil: hover, focus, press and state changes
       still give feedback, they just arrive at once (less movement, never no
       feedback);
     · every travel/scale token collapses, which turns every transform-based
       animation into a pure opacity fade — no keyframe needs a special case;
     · animations run once and never wait;
     · loading indicators keep animating so "busy" stays legible: the spin and
       shimmer keyframes are swapped for a slow opacity pulse (the two shared
       loader rules above carry !important so the safety net cannot stop them).
   ANY component needing different reduced-motion behaviour belongs in these
   tokens. Do not add a second media query. Keep the two switches in lockstep.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  html:not([data-motion="full"]){
    --dur-instant:var(--dur-nil); --dur-fast:var(--dur-nil); --dur-base:var(--dur-nil);
    --dur-slow:var(--dur-nil); --dur-chart:var(--dur-nil); --dur-hold:var(--dur-nil);
    --dur-loop:var(--dur-pulse);
    --motion-lift:var(--motion-still); --motion-rise:var(--motion-still);
    --motion-nudge:var(--motion-still); --motion-stagger:var(--delay-0);
    --motion-press:var(--motion-flat); --motion-scale-in:var(--motion-flat);
    --motion-pop-from:var(--motion-flat); --motion-pop-peak:var(--motion-flat);
    --motion-leave-to:var(--motion-flat); --motion-focus-scale:var(--motion-flat);
    --motion-grow-from:var(--motion-flat);
    --motion-pin-from:var(--motion-flat); --motion-ring-to:var(--motion-flat);
    --motion-spin:motionPulse; --motion-shimmer:motionPulse;
    --motion-shimmer-x:var(--motion-still);
  }
  /* Safety net for anything not on the token scale (e.g. Leaflet's own CSS). */
  html:not([data-motion="full"]) *,
  html:not([data-motion="full"]) *::before,
  html:not([data-motion="full"]) *::after{
    animation-duration:var(--dur-nil) !important;
    animation-delay:var(--delay-0) !important;
    animation-iteration-count:1 !important;
    transition-duration:var(--dur-nil) !important;
  }
}
html[data-motion="reduced"]{
  --dur-instant:var(--dur-nil); --dur-fast:var(--dur-nil); --dur-base:var(--dur-nil);
  --dur-slow:var(--dur-nil); --dur-chart:var(--dur-nil); --dur-hold:var(--dur-nil);
  --dur-loop:var(--dur-pulse);
  --motion-lift:var(--motion-still); --motion-rise:var(--motion-still);
  --motion-nudge:var(--motion-still); --motion-stagger:var(--delay-0);
  --motion-press:var(--motion-flat); --motion-scale-in:var(--motion-flat);
  --motion-pop-from:var(--motion-flat); --motion-pop-peak:var(--motion-flat);
  --motion-leave-to:var(--motion-flat); --motion-focus-scale:var(--motion-flat);
  --motion-grow-from:var(--motion-flat);
  --motion-pin-from:var(--motion-flat); --motion-ring-to:var(--motion-flat);
  --motion-spin:motionPulse; --motion-shimmer:motionPulse;
  --motion-shimmer-x:var(--motion-still);
}
html[data-motion="reduced"] *,
html[data-motion="reduced"] *::before,
html[data-motion="reduced"] *::after{
  animation-duration:var(--dur-nil) !important;
  animation-delay:var(--delay-0) !important;
  animation-iteration-count:1 !important;
  transition-duration:var(--dur-nil) !important;
}
