/* =============================================================================================
   ui-v4.css — WorkSight v4 presentation layer (SHIFT1 REVIEW ONLY). Owner: Agent A2.
   Design source: worksight_reference_beautified_interactive_v1.html (light-first teal, dark twin,
   232px sidebar, radii 6/10, zone-kind colours, ws* motion set). See docs/v4/BUILD_CONTRACT.md.

   TOKEN RULE: the reference palette is carried as --v4-* ONLY. No --vx-* variable is defined or
   overridden anywhere in this file (they belong to the frozen Movement Tracker).

   Loads after styles.css / ui-v3.css / movement-history.css, so an equal-specificity rule here wins
   by order. The app's own tokens (styles.css :root/[data-theme], ui-v3.css .v3) are re-pointed at the
   v4 palette on html[data-theme], so every existing page adopts the look without its markup
   changing. Movement Tracker (.mh-app / #mh* / .vx-replay*) is pinned back to its original values.

   Sections: 1 tokens · 2 app-token bridge · 3 base · 4 shell · 5 motion · 6 v4 core · 7 primitives
             8 grid · 9 restyle of existing pages · 10 mobile shell · 11 reduced motion
   ============================================================================================= */

/* ---------------------------------------------------------------------------------------------
   1. TOKENS — light is the default; dark twin keyed on html[data-theme="dark"].
   --------------------------------------------------------------------------------------------- */
:root,
html[data-theme="light"]{
  --v4-bg:#EEF1F2; --v4-surface:#FFFFFF; --v4-surface-2:#F7F9F9; --v4-surface-3:#EFF3F3;
  --v4-line:#DCE2E3; --v4-line-strong:#C3CCCD;
  --v4-ink:#152220; --v4-ink-2:#4A5857; --v4-ink-3:#5F6C6B;   /* VQ: ref #7D8A89 was 3.0–3.6:1 as text → 5.2:1 */
  --v4-muted:#5F6D6C;
  --v4-accent:#0E6B62; --v4-accent-ink:#FFFFFF; --v4-accent-soft:#DCEFEC; --v4-accent-2:#12877B;
  --v4-crit:#B3261E; --v4-crit-soft:#F8E1DF; --v4-crit-ink:#9E2019;
  --v4-high:#C2621C; --v4-high-soft:#FBE8DA; --v4-high-ink:#94470F;
  --v4-med:#A9821A;  --v4-med-soft:#F7EDCD;  --v4-med-ink:#735708;
  --v4-info:#2C5AA0; --v4-info-soft:#DEE7F5; --v4-info-ink:#244C88;
  --v4-ok:#2E7D4F;   --v4-ok-soft:#DDF0E4;   --v4-ok-ink:#23653F;
  --v4-z-work:#0E6B62; --v4-z-meet:#2C5AA0; --v4-z-cafe:#C2621C; --v4-z-common:#A9821A;
  --v4-z-lobby:#7D8A89; --v4-z-out:#D8DEDF; --v4-z-park:#5B5F7A;
  --v4-hover:color-mix(in srgb,var(--v4-accent-soft) 45%,var(--v4-surface-2));
  --v4-selected:var(--v4-accent-soft);
  --v4-focus:0 0 0 3px color-mix(in srgb,var(--v4-accent) 16%,transparent);
  --v4-shadow-1:0 1px 2px rgba(10,28,25,.05),0 8px 24px rgba(10,28,25,.05);
  --v4-shadow-2:0 12px 36px rgba(10,28,25,.10),0 2px 8px rgba(10,28,25,.06);
  --v4-shadow-3:0 20px 60px rgba(5,20,18,.18);
  --v4-glass:color-mix(in srgb,var(--v4-surface) 86%,transparent);
  --v4-scrim:rgba(10,20,19,.35);
  --v4-ease:cubic-bezier(.22,.8,.3,1);
  --v4-font:"Inter Tight",Inter,system-ui,-apple-system,"Segoe UI",sans-serif;
  --v4-mono:"IBM Plex Mono","JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --v4-r:6px; --v4-r-lg:10px; --v4-side:232px; --v4-top:56px; --v4-max:1400px;
  /* person type — ONE pill shape; Employee = teal + solid person, Visitor = orange + dashed person */
  --v4-emp:var(--v4-accent); --v4-emp-bg:var(--v4-accent-soft); --v4-emp-line:color-mix(in srgb,var(--v4-accent) 34%,transparent);
  --v4-vis:var(--v4-high-ink); --v4-vis-bg:var(--v4-high-soft); --v4-vis-line:color-mix(in srgb,var(--v4-high) 60%,transparent);
}
html[data-theme="dark"]{
  --v4-bg:#0F1615; --v4-surface:#172120; --v4-surface-2:#1E2A29; --v4-surface-3:#1A2524;
  --v4-line:#293736; --v4-line-strong:#3A4A49;
  --v4-ink:#EAF0EF; --v4-ink-2:#B4C0BF; --v4-ink-3:#8E9D9C; --v4-muted:#93A2A1;   /* VQ: ink-3 ≥4.5:1 on surface-2 */
  --v4-accent:#4CC2B4; --v4-accent-ink:#0B1413; --v4-accent-soft:#183B37; --v4-accent-2:#6fd3c7;
  --v4-crit:#F08A83; --v4-crit-soft:#4A1F1C; --v4-crit-ink:#F4A09A;
  --v4-high:#F0A56B; --v4-high-soft:#4A2E1A; --v4-high-ink:#F3B584;
  --v4-med:#E3C15E;  --v4-med-soft:#463A15;  --v4-med-ink:#E8CB76;
  --v4-info:#86ACE8; --v4-info-soft:#1D2E4A; --v4-info-ink:#9DBCEE;
  --v4-ok:#79C795;   --v4-ok-soft:#1B3A28;   --v4-ok-ink:#8ED3A7;
  --v4-z-work:#4CC2B4; --v4-z-meet:#86ACE8; --v4-z-cafe:#F0A56B; --v4-z-common:#E3C15E;
  --v4-z-lobby:#8E9C9B; --v4-z-out:#2A3736; --v4-z-park:#9A9FC4;
  --v4-shadow-1:0 1px 2px rgba(0,0,0,.22),0 10px 28px rgba(0,0,0,.16);
  --v4-shadow-2:0 14px 42px rgba(0,0,0,.30),0 2px 8px rgba(0,0,0,.20);
  --v4-shadow-3:0 28px 80px rgba(0,0,0,.45);
  --v4-glass:color-mix(in srgb,var(--v4-surface) 88%,transparent);
  --v4-scrim:rgba(0,0,0,.5);
  --v4-vis:var(--v4-high-ink);
}
/* DESIGN-SYSTEM SCALES — the ONLY sizes/radii/timings any v4 stylesheet may use (theme-independent). */
:root{
  /* spacing (4px base) */
  --v4-space-1:4px; --v4-space-2:8px; --v4-space-3:12px; --v4-space-4:16px; --v4-space-5:20px; --v4-space-6:24px; --v4-space-8:32px; --v4-space-10:40px;
  /* radii */
  --v4-r-sm:4px; --v4-r-md:8px; --v4-r-xl:14px; --v4-r-pill:999px;       /* + --v4-r (6) and --v4-r-lg (10) above */
  /* type scale (role names) */
  --v4-fs-3xs:11px; --v4-fs-2xs:11px; --v4-fs-xs:11px;   /* VQ: nothing below 11px */ --v4-fs-meta:11.5px; --v4-fs-sm:12px; --v4-fs-ui:12.5px;
  --v4-fs-base:13px; --v4-fs-nav:13.5px; --v4-fs-md:14px; --v4-fs-lg:15px; --v4-fs-title:16px; --v4-fs-h2:17px;
  --v4-fs-kpi-sm:22px; --v4-fs-kpi:26px;
  --v4-fw-reg:400; --v4-fw-med:500; --v4-fw-semi:600;
  --v4-lh-tight:1.25; --v4-lh:1.45;
  /* heading hierarchy: page title (top bar) → section (h2) → card (h3) → group label (h4) */
  --v4-h1:var(--v4-fw-semi) var(--v4-fs-title)/var(--v4-lh-tight) var(--v4-font);
  --v4-h2:var(--v4-fw-semi) var(--v4-fs-h2)/var(--v4-lh-tight) var(--v4-font);
  --v4-h3:var(--v4-fw-semi) var(--v4-fs-md)/1.3 var(--v4-font);
  --v4-h4:var(--v4-fw-semi) var(--v4-fs-xs)/1.3 var(--v4-font);
  /* icons */
  --v4-ic-sm:14px; --v4-ic:16px; --v4-ic-lg:20px;
  /* control heights */
  --v4-h-sm:26px; --v4-h:32px; --v4-h-lg:38px;
  /* tables */
  --v4-row-h:40px; --v4-row-h-compact:34px; --v4-cell-y:8px; --v4-cell-x:10px;
  /* surfaces of overlays */
  --v4-drawer-w:480px; --v4-drawer-pad:var(--v4-space-5); --v4-modal-pad:var(--v4-space-4); --v4-card-pad:var(--v4-space-4);
  /* charts */
  --v4-chart-pad:var(--v4-space-3) var(--v4-space-2) var(--v4-space-1);
  /* motion: 150–300 ms, one easing */
  --v4-dur-fast:150ms; --v4-dur:200ms; --v4-dur-slow:280ms;
  /* border strengths */
  --v4-bw:1px; --v4-bw-strong:1.5px; --v4-bw-focus:2px;
}
/* 4th surface level (sunken wells: table heads, segmented tracks) is --v4-surface-3; overlays use --v4-surface. */

/* LEGACY ALIASES — sibling v4 files (pages/evidence) were written against these names. */
:root,html[data-theme="light"],html[data-theme="dark"]{
  --v4-panel:var(--v4-surface); --v4-panel2:var(--v4-surface-2); --v4-panel3:var(--v4-surface-3); --v4-raise:var(--v4-surface-2);
  --v4-text:var(--v4-ink); --v4-text2:var(--v4-ink-2); --v4-faint:var(--v4-ink-3);
  --v4-line2:var(--v4-line-strong);
  --v4-brand:var(--v4-accent); --v4-brand2:var(--v4-info); --v4-brandSoft:var(--v4-accent-soft); --v4-brandInk:var(--v4-accent);
  --v4-green:var(--v4-ok); --v4-red:var(--v4-crit); --v4-yellow:var(--v4-med); --v4-orange:var(--v4-high);
  --v4-cyan:var(--v4-info); --v4-violet:var(--v4-z-park);
  --v4-ok-bg:var(--v4-ok-soft); --v4-bad-ink:var(--v4-crit-ink); --v4-bad-bg:var(--v4-crit-soft);
  --v4-warn-ink:var(--v4-med-ink); --v4-warn-bg:var(--v4-med-soft); --v4-info-bg:var(--v4-info-soft);
  --v4-card-shadow:var(--v4-shadow-1); --v4-shadow:var(--v4-shadow-2); --v4-drawer-shadow:var(--v4-shadow-3);
  --v4-r-kpi:var(--v4-r-lg); --v4-r-wrap:var(--v4-r-lg); --v4-r-ctl:var(--v4-r);
}

/* ---------------------------------------------------------------------------------------------
   2. APP-TOKEN BRIDGE — styles.css (:root/[data-theme]) and ui-v3.css (.v3 / [data-theme] .v3)
   read these names. html[...] out-ranks both by one element.
   --------------------------------------------------------------------------------------------- */
html[data-theme="light"], html[data-theme="light"] .v3,
html[data-theme="dark"],  html[data-theme="dark"] .v3{
  --bg:var(--v4-bg); --panel:var(--v4-surface); --panel-2:var(--v4-surface-2); --panel-3:var(--v4-surface-3);
  --ink:var(--v4-ink); --ink-2:var(--v4-ink-2); --muted:var(--v4-muted); --faint:var(--v4-ink-3);
  --line:var(--v4-line); --line-2:var(--v4-line-strong); --line-strong:var(--v4-line-strong);
  --brand:var(--v4-accent); --brand-2:var(--v4-accent-2); --cyan:var(--v4-info);
  --ok:var(--v4-ok); --ok-bg:var(--v4-ok-soft); --warn:var(--v4-med); --warn-bg:var(--v4-med-soft);
  --bad:var(--v4-crit); --bad-bg:var(--v4-crit-soft); --info:var(--v4-info); --info-bg:var(--v4-info-soft);
  --surface-hover:var(--v4-hover); --surface-selected:var(--v4-selected); --focus-ring:var(--v4-focus);
  --sh-1:var(--v4-shadow-1); --sh-2:var(--v4-shadow-1); --sh-3:var(--v4-shadow-3);
  --sh-brand:0 8px 20px color-mix(in srgb,var(--v4-accent) 22%,transparent);
  --shadow-card:var(--v4-shadow-1); --shadow-hover:var(--v4-shadow-2); --shadow-float:var(--v4-shadow-3);
  --grid:var(--v4-line);
  --r:var(--v4-r-lg); --r-sm:8px; --r-xs:var(--v4-r);
  --font-display:var(--v4-font);
  --nav:var(--v4-surface); --nav-2:var(--v4-surface); --nav-ink:var(--v4-ink-2); --nav-ink-2:var(--v4-ink-3);
  --nav-overlay:var(--v4-surface-2); --nav-overlay-2:var(--v4-line); --nav-border:var(--v4-line); --nav-hover-ink:var(--v4-ink);
}
/* ui-v3's --accent is a cyan highlight (e.g. the active Live Cameras grid button); inside ported
   pages it follows the teal accent. The global styles.css --accent (amber) is left alone. */
html[data-theme="light"] .v3, html[data-theme="dark"] .v3{ --accent:var(--v4-accent); }

/* MOVEMENT TRACKER IS FROZEN — pin every app token it could read back to its styles.css value. */
html[data-theme="dark"] .mh-app{
  --bg:#0a0f1d; --panel:#111a2e; --panel-2:#16223a; --panel-3:#1b2942;
  --ink:#e9eef9; --ink-2:#b7c2d8; --muted:#8b98b3; --faint:#5e6b86;
  --line:#243250; --line-2:#2c3c5e; --line-strong:#2c3c5e; --brand:#6d84ff; --brand-2:#8398ff; --cyan:#2fc6e6;
  --ok:#2ec48a; --ok-bg:#2ec48a1f; --warn:#e6ab4d; --warn-bg:#e6ab4d20; --bad:#f06b7e; --bad-bg:#f06b7e1f;
  --info:#7d92ff; --info-bg:#7d92ff20; --grid:#22314f; --r:16px; --r-sm:11px; --r-xs:8px;
  --sh-1:0 1px 2px rgba(0,0,0,.3); --sh-2:0 6px 16px rgba(0,0,0,.36); --sh-3:0 18px 44px rgba(0,0,0,.5);
  --sh-brand:0 12px 26px rgba(60,80,220,.4);
}
html[data-theme="light"] .mh-app{
  --bg:#eef1f7; --panel:#ffffff; --panel-2:#f6f8fc; --panel-3:#eef2f9;
  --ink:#141d34; --ink-2:#3b475f; --muted:#69748c; --faint:#9aa5bb;
  --line:#e2e7f0; --line-2:#d7deea; --line-strong:#d7deea; --brand:#4f63f6; --brand-2:#6d84ff; --cyan:#12b5d6;
  --ok:#12a670; --ok-bg:#12a67018; --warn:#d9922a; --warn-bg:#d9922a1a; --bad:#e05265; --bad-bg:#e0526518;
  --info:#4f63f6; --info-bg:#4f63f618; --grid:#e6ebf4; --r:16px; --r-sm:11px; --r-xs:8px;
  --sh-1:0 1px 2px rgba(20,29,52,.05),0 1px 3px rgba(20,29,52,.04); --sh-2:0 4px 12px rgba(20,29,52,.06),0 1px 3px rgba(20,29,52,.05);
  --sh-3:0 16px 38px rgba(20,29,52,.11),0 2px 8px rgba(20,29,52,.06); --sh-brand:0 12px 26px rgba(79,99,246,.32);
}

/* ---------------------------------------------------------------------------------------------
   3. BASE
   --------------------------------------------------------------------------------------------- */
html body{
  background:
    radial-gradient(900px 520px at 76% -12%,color-mix(in srgb,var(--v4-accent) 10%,transparent),transparent 72%),
    radial-gradient(700px 420px at 0% 110%,color-mix(in srgb,var(--v4-info) 6%,transparent),transparent 70%),
    var(--v4-bg);
  background-attachment:fixed;color:var(--v4-ink);
}
:where(h1,h2,h3,h4,.v):not(.mh-app *){font-family:var(--v4-font);letter-spacing:-.01em}
::selection{background:var(--v4-accent);color:var(--v4-accent-ink)}
:focus-visible{outline:2px solid var(--v4-accent);outline-offset:2px}
.app{background:transparent}

/* ---------------------------------------------------------------------------------------------
   4. SHELL — 232px sidebar, grouped collapsible nav, 56px glass top bar, centred content.
   --------------------------------------------------------------------------------------------- */
.side{width:var(--v4-side);padding:0;background:var(--v4-surface);border-right:1px solid var(--v4-line);
  color:var(--v4-ink-2);box-shadow:6px 0 26px rgba(12,34,30,.035);gap:0}
.side .brand{position:sticky;top:0;z-index:6;min-height:var(--v4-top);height:var(--v4-top);margin:0;padding:0 44px 0 16px;gap:10px;
  flex-wrap:nowrap;align-items:center;border-bottom:1px solid var(--v4-line);background:var(--v4-glass);
  -webkit-backdrop-filter:blur(16px) saturate(145%);backdrop-filter:blur(16px) saturate(145%);flex:0 0 auto}
.side .brand .brandicon{width:28px;height:28px;border-radius:7px;box-shadow:0 6px 18px color-mix(in srgb,var(--v4-accent) 24%,transparent)}
.side .brand .brandlogo{height:30px}
.side .brandtext{min-width:0;margin:0;flex:1 1 auto}
.side .brandtext b{display:block;font:600 var(--v4-fs-lg)/1.2 var(--v4-font);letter-spacing:-.01em;color:var(--v4-ink)}
.side .brandtext .ai{color:var(--v4-accent)}
.side .brandtext small{display:block;color:var(--v4-ink-3);font-size:var(--v4-fs-xs);font-weight:400;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
html[data-theme="light"] .side .brand{flex-wrap:nowrap;padding-right:44px}
html[data-theme="light"] .side .brandtext{display:none}
.side .brand .sidemin,
html[data-theme="light"] .side .brand .sidemin{position:absolute;right:10px;top:50%;transform:translateY(-50%);width:24px;height:24px;
  border-radius:var(--v4-r);background:transparent;color:var(--v4-ink-3)}
.side .brand .sidemin:hover{background:var(--v4-surface-2);color:var(--v4-ink)}
.side .brand .sidemin svg{width:14px;height:14px}

#nav{padding:8px;margin:0;gap:0;flex:1 1 auto}
#nav .v4-navgrp{margin:0}
#nav .v4-navhead,
#nav .nav{position:relative;overflow:hidden;display:flex;align-items:center;gap:9px;width:100%;min-height:var(--v4-h);margin:0;
  background:none;border:0;padding:7px 10px;border-radius:var(--v4-r);cursor:pointer;text-align:left;box-shadow:none;
  color:var(--v4-ink-2);font:500 var(--v4-fs-nav)/1.25 var(--v4-font);letter-spacing:0;text-transform:none;
  transition:transform var(--v4-dur-fast) var(--v4-ease),background-color var(--v4-dur-fast) ease,color var(--v4-dur-fast) ease,box-shadow var(--v4-dur-fast) var(--v4-ease)}
#nav .v4-navhead:hover,
#nav .nav:hover{background:var(--v4-surface-2);color:var(--v4-ink);transform:translateX(2px)}
#nav .v4-navhead:focus-visible,#nav .nav:focus-visible{outline:2px solid var(--v4-accent);outline-offset:-2px}
#nav .v4-navgrp.has-on > .v4-navhead{color:var(--v4-ink);font-weight:600}
#nav .v4-navhead .v4-navgi,
#nav .nav .v4-navgi{width:16px;height:16px;opacity:.85;color:currentColor}
#nav .v4-navhead .v4-navgl{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#nav .v4-navhead .v4-chev{width:12px;height:12px;margin-left:auto;opacity:.6;transition:transform var(--v4-dur-fast)}
#nav .v4-navgrp.open > .v4-navhead .v4-chev{transform:rotate(90deg)}
#nav .v4-navitems{display:none;padding:2px 0 4px;margin:0;border:0}
#nav .v4-navgrp.open > .v4-navitems{display:block}
#nav .v4-navgrp.v4-anim > .v4-navitems{animation:v4NavOpen var(--v4-dur) var(--v4-ease) both}
#nav .v4-navitems .nav{padding:5px 10px 5px 35px;min-height:30px;font-size:var(--v4-fs-base)}
#nav .nav b{font:inherit;font-weight:inherit;color:inherit;min-width:0;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;letter-spacing:0}
#nav .v4-navitems .nav > svg{display:none}               /* reference: sub-items carry no icon */
#nav .nav.on{background:var(--v4-accent-soft);color:var(--v4-accent);font-weight:600;
  box-shadow:inset 3px 0 0 var(--v4-accent),0 4px 14px color-mix(in srgb,var(--v4-accent) 10%,transparent)}
#nav .nav.on b{color:var(--v4-accent);font-weight:600}
#nav .nav .badge{margin-left:auto;flex:0 0 auto;font:500 var(--v4-fs-xs)/1.5 var(--v4-mono);background:var(--v4-surface-2);padding:1px 6px;border-radius:var(--v4-r-lg);color:var(--v4-ink-2)}
#nav .nav.on .badge{background:var(--v4-surface);color:var(--v4-accent)}
#nav .nav .badge.crit{background:var(--v4-crit-soft);color:var(--v4-crit-ink)}

.side .sidefoot{padding:12px 16px;margin-top:auto;border-top:1px solid var(--v4-line);color:var(--v4-ink-3);font-size:var(--v4-fs-sm);line-height:1.55}
.side .sidefoot .ping{color:var(--v4-ink-2);font-size:var(--v4-fs-sm);gap:7px;margin-bottom:2px}
.side .sidefoot .ping .dot.ok{animation:v4Pulse 2.2s ease-out infinite}
.side .sidefoot .foothint,.side .sidefoot .foothint .muted{color:var(--v4-ink-3)}
.side .sidefoot .foothint b{color:var(--v4-ink)}

/* Icon rail (the console's own collapse, desktop only). Sub-item icons appear only here. */
@media (min-width:900px){
  .side.min{width:64px;padding:0}
  .side.min .brand{padding:0;justify-content:center;flex-direction:row}
  .side.min .brand .brandicon{display:block}
  .side.min .brand .sidemin{right:auto;left:50%;top:auto;bottom:-12px;transform:translateX(-50%) rotate(180deg);background:var(--v4-surface);border:1px solid var(--v4-line);z-index:2}
  .side.min #nav{padding:10px 8px}
  .side.min #nav .v4-navhead{display:none}
  .side.min #nav .v4-navitems{display:block;padding:4px 0;border-top:1px solid var(--v4-line)}
  .side.min #nav .v4-navgrp:first-child .v4-navitems{border-top:0}
  .side.min #nav .nav{justify-content:center;padding:8px 0;gap:0}
  .side.min #nav .nav b,.side.min #nav .nav .badge{display:none}
  .side.min #nav .v4-navitems .nav > svg{display:block;width:18px;height:18px}
  .side.min .sidefoot{padding:12px 8px}
}

/* Top bar */
.main > .top{position:sticky;top:0;z-index:30;min-height:var(--v4-top);height:var(--v4-top);padding:0 20px;gap:12px;min-width:0;
  background:var(--v4-glass);-webkit-backdrop-filter:blur(16px) saturate(145%);backdrop-filter:blur(16px) saturate(145%);
  border-bottom:1px solid var(--v4-line);box-shadow:0 8px 24px rgba(10,28,25,.025)}
.top .titlewrap{min-width:0;flex:0 1 auto}
.top .titlewrap h1{font:600 var(--v4-fs-title)/1.25 var(--v4-font);letter-spacing:-.01em;color:var(--v4-ink);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.top .titlewrap h1 .v4-crumb{color:var(--v4-ink-3);font-weight:500}
.top .titlewrap h1 .v4-crumb-sep{color:var(--v4-ink-3);margin:0 .4em;font-weight:400}
.top .titlewrap .sub{font-size:var(--v4-fs-meta);color:var(--v4-muted);margin-top:1px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.top .live{display:inline-flex;align-items:center;gap:6px;font-size:var(--v4-fs-sm);font-weight:500;padding:3px 9px;border-radius:var(--v4-r-pill);
  border:1px solid var(--v4-line);background:var(--v4-surface-2);color:var(--v4-ink-2);white-space:nowrap}
.top .live #clock{font-family:var(--v4-mono);font-size:var(--v4-fs-sm);color:var(--v4-ink-2)}
.top .live .dot.ok{background:var(--v4-ok);animation:v4Pulse 2.2s ease-out infinite}
.top .lbadge{background:transparent;color:var(--v4-accent);font:600 var(--v4-fs-3xs)/1 var(--v4-font);letter-spacing:.08em;padding:0}
.top .rolewrap{border:1px solid var(--v4-line);background:var(--v4-surface-2);border-radius:var(--v4-r-pill)}
.top .rolewrap .rl{color:var(--v4-ink-2)}
.top .rolesel{border:1px solid var(--v4-line-strong);background:var(--v4-surface);color:var(--v4-ink);border-radius:var(--v4-r-pill)}
.top .topbtn,.top .iconbtn{position:relative;overflow:hidden;height:var(--v4-h);border-radius:var(--v4-r);border:1px solid var(--v4-line-strong);
  background:var(--v4-surface);color:var(--v4-ink);font:500 var(--v4-fs-base)/1 var(--v4-font);
  transition:transform var(--v4-dur-fast) var(--v4-ease),box-shadow var(--v4-dur-fast) var(--v4-ease),background-color var(--v4-dur-fast) ease,border-color var(--v4-dur-fast) ease}
.top .topbtn{padding:0 11px;gap:6px}
.top .iconbtn{width:32px;padding:0;color:var(--v4-ink-2)}
.top .topbtn:hover,.top .iconbtn:hover{background:var(--v4-surface-2);color:var(--v4-ink);border-color:var(--v4-line-strong);transform:translateY(-1px);box-shadow:0 6px 16px rgba(10,28,25,.08)}
.top .topbtn:active,.top .iconbtn:active{transform:translateY(0) scale(.985)}
.top .topbtn svg{width:15px;height:15px}
.top .iconbtn svg{width:17px;height:17px}
@media (max-width:1400px){ .top .topbtn span{display:none} .top .topbtn{padding:0 9px} }
@media (max-width:1180px){ .top .live #clock{display:none} .top .titlewrap .sub{display:none} }
/* WEB-I/§18: at ≤1440 the three scope selects + their labels crowded the title and pushed the
   profile button off-screen / forced header horizontal scroll. Drop the scope word-labels early,
   tighten the gap, cap the select widths, and clip any residual overflow so the header never scrolls.
   The title keeps flex priority (ellipsises last) and the profile/notification buttons stay on screen. */
.main > .top{overflow:clip}
@media (max-width:1440px){
  .top .rolewrap .rl{display:none}
  .main > .top{gap:8px;padding:0 14px}
  .top .rolesel{max-width:150px}
  .top .titlewrap{flex:1 1 auto}
}
@media (max-width:1150px){
  .top .rolesel{max-width:118px}
  .top .live{padding:3px 7px}
  .top .titlewrap h1{font-size:var(--v4-fs-lg)}
}

/* Content column */
.main > .content{max-width:calc(var(--v4-max) + 40px);width:100%;margin:0 auto;padding:20px 20px 40px}
@media (max-width:1024px){ .main > .content{padding:16px 14px 32px} .main > .top{padding:0 14px} }
.app > .main,.main > .content,#view{min-width:0;max-width:100%}

/* ---------------------------------------------------------------------------------------------
   5. MOTION (reference ws* set; everything is off under prefers-reduced-motion, §11)
   Entrance animations only run inside #view.v4-enter (set by the shell for ~0.7s on a route change)
   so a same-page data repaint never replays them.
   --------------------------------------------------------------------------------------------- */
@keyframes v4PageIn{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
@keyframes v4NavOpen{from{opacity:0;transform:translateY(-4px) scaleY(.98)}to{opacity:1;transform:none}}
@keyframes v4PaneIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
@keyframes v4GrowX{from{transform:scaleX(0)}to{transform:scaleX(1)}}
@keyframes v4GrowY{from{transform:scaleY(0)}to{transform:scaleY(1)}}
@keyframes v4ChartIn{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
@keyframes v4Pulse{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--v4-ok) 42%,transparent)}70%,100%{box-shadow:0 0 0 7px transparent}}
@keyframes v4Sheen{0%,72%{transform:translateX(-120%)}88%,100%{transform:translateX(120%)}}
@keyframes v4Ripple{to{opacity:0;transform:translate(-50%,-50%) scale(10)}}
@keyframes v4DrawerIn{from{transform:translateX(24px);opacity:0}to{transform:none;opacity:1}}
@keyframes v4ModalIn{from{opacity:0;transform:translateY(8px) scale(.985)}to{opacity:1;transform:none}}
@keyframes v4Skel{0%{background-position:120% 0}100%{background-position:-20% 0}}

#view.v4-enter > *{animation:v4PageIn var(--v4-dur-slow) var(--v4-ease) both}
#view.v4-enter .v4-bar > i,#view.v4-enter .v4-bar > span{animation:v4GrowX var(--v4-dur-slow) var(--v4-ease) both}
#view.v4-enter .v4-vbars > i{animation:v4GrowY var(--v4-dur-slow) var(--v4-ease) both}
#view.v4-enter .v4-chart,#view.v4-enter svg.chart{animation:v4ChartIn var(--v4-dur-slow) var(--v4-ease) both}
.v4-ripple{position:absolute;border-radius:var(--v4-r-pill);pointer-events:none;background:currentColor;opacity:.14;
  transform:translate(-50%,-50%) scale(0);animation:v4Ripple var(--v4-dur-slow) ease-out forwards}
.v4-live-sheen{position:relative;overflow:hidden}
.v4-live-sheen::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(100deg,transparent 0%,rgba(255,255,255,.05) 47%,transparent 60%);transform:translateX(-120%);animation:v4Sheen 6.5s ease-in-out infinite}

/* ---------------------------------------------------------------------------------------------
   6. V4 CORE COMPONENTS (classes emitted by ui-v4-core.js)
   --------------------------------------------------------------------------------------------- */
.v4-ico{display:inline-grid;place-items:center;width:1em;height:1em;flex:none;line-height:0}
.v4-ico svg{width:100%;height:100%;display:block;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}

.v4-card{position:relative;background:var(--v4-surface);border:var(--v4-card-bd);border-radius:var(--v4-card-r);
  box-shadow:var(--v4-card-sh);padding:16px;min-width:0;color:var(--v4-ink);
  transition:box-shadow var(--v4-dur-fast) var(--v4-ease),border-color var(--v4-dur-fast) ease}
.v4-card:hover{box-shadow:var(--v4-shadow-2);border-color:color-mix(in srgb,var(--v4-accent) 22%,var(--v4-line))}
.v4-card.flat{background:var(--v4-surface-2);box-shadow:none}
.v4-card-h{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px;min-width:0}
.v4-card-h > div{min-width:0}
.v4-card-h h3{font:600 var(--v4-fs-md)/1.3 var(--v4-font);letter-spacing:-.01em;margin:0;color:var(--v4-ink)}
.v4-card-h small{display:block;color:var(--v4-muted);font-size:var(--v4-fs-sm);font-weight:400;margin-top:2px}
.v4-card-b{min-width:0}

.v4-kpi{position:relative;overflow:hidden;min-width:0;padding:12px 14px;border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);
  background:var(--v4-surface);box-shadow:var(--v4-shadow-1);color:var(--v4-ink);
  transition:transform var(--v4-dur-fast) var(--v4-ease),box-shadow var(--v4-dur-fast) var(--v4-ease),border-color var(--v4-dur-fast) ease}
.v4-kpi.crit{border-left:3px solid var(--v4-crit)} .v4-kpi.high{border-left:3px solid var(--v4-high)}
.v4-kpi.ok{border-left:3px solid var(--v4-ok)} .v4-kpi.acc{border-left:3px solid var(--v4-accent)} .v4-kpi.info{border-left:3px solid var(--v4-info)}
.v4-kpi[data-v4go]{cursor:pointer}
.v4-kpi:hover{transform:translateY(-2px);box-shadow:var(--v4-shadow-2);border-color:color-mix(in srgb,var(--v4-accent) 22%,var(--v4-line))}
.v4-kpi[data-v4go]:focus-visible{outline:2px solid var(--v4-accent);outline-offset:2px}
.v4-kpi-l{display:flex;align-items:center;gap:7px;font-size:var(--v4-fs-sm);color:var(--v4-ink-2);font-weight:500;min-width:0}
.v4-kpi-l .v4-ico{width:15px;height:15px;color:var(--v4-accent)}
.v4-kpi-v{font:600 var(--v4-fs-kpi)/1.1 var(--v4-font);letter-spacing:-.02em;margin-top:4px;font-variant-numeric:tabular-nums;color:var(--v4-ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.v4-kpi-s{font-size:var(--v4-fs-sm);color:var(--v4-muted);margin-top:4px;min-width:0}
.v4-kpi-s.up{color:var(--v4-ok-ink)} .v4-kpi-s.dn{color:var(--v4-crit-ink)}

/* Person type — ONE pill; Employee = teal solid person, Visitor = orange dashed person + badge + dashed edge. */
.v4-type,
.astag.ok,.astag.warn{display:inline-flex;align-items:center;gap:4px;padding:1px 7px 1px 5px;border-radius:var(--v4-r-pill);
  font:600 var(--v4-fs-xs)/1.45 var(--v4-font);letter-spacing:0;text-transform:none;white-space:nowrap;border:1px solid transparent;vertical-align:middle;max-width:none}
.v4-type .v4-ico{width:12px;height:12px}
.v4-type--emp,.astag.ok{color:var(--v4-emp);background:var(--v4-emp-bg);border-color:var(--v4-emp-line)}
.v4-type--vis,.astag.warn{color:var(--v4-vis);background:var(--v4-vis-bg);border-color:var(--v4-vis-line);border-style:dashed}
/* UI TAXONOMY 2026-09-18: Unresolved = neutral muted pill, dotted edge, distinct from Employee (solid) / Visitor (dashed). */
.v4-type--unres,.astag.unres{color:var(--v4-muted);background:var(--v4-surface-2);border-color:var(--v4-line);border-style:dotted}
.astag.ok::before,.astag.warn::before{content:"";width:12px;height:12px;flex:none;background:currentColor;
  -webkit-mask:var(--v4-glyph) center/contain no-repeat;mask:var(--v4-glyph) center/contain no-repeat}
.astag.ok{--v4-glyph:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='8' r='3.6'/%3E%3Cpath d='M4.8 20c.9-3.7 3.7-5.6 7.2-5.6s6.3 1.9 7.2 5.6'/%3E%3C/svg%3E")}
.astag.warn{--v4-glyph:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='8' r='3.6'/%3E%3Cpath d='M4.8 20c.9-3.7 3.7-5.6 7.2-5.6s6.3 1.9 7.2 5.6' stroke-dasharray='2.4 2.2'/%3E%3Crect x='15.5' y='14.5' width='5' height='4' rx='.8'/%3E%3C/svg%3E")}

/* 7:9 portrait slot — real crop or the approved glyph (live avSlot() convention). */
.v4-face{position:relative;display:inline-block;flex:none;overflow:hidden;aspect-ratio:7/9;border-radius:var(--v4-r);
  background:var(--v4-surface-2);border:1px solid var(--v4-line);vertical-align:middle;max-width:100%}
.v4-face--sm{width:28px;border-radius:5px}
.v4-face--md{width:44px}
.v4-face--lg{width:88px;border-radius:var(--v4-r-lg)}
.v4-face img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 20%;display:block}
.v4-face-ph{position:absolute;inset:0}
.v4-face-ph::before{content:"";position:absolute;left:14%;right:14%;top:20%;bottom:0;background:var(--v4-ink-3);opacity:.55;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 26'%3E%3Ccircle cx='12' cy='8' r='5.2'/%3E%3Cpath d='M1.5 26c.7-6.6 4.9-10.4 10.5-10.4S21.8 19.4 22.5 26z'/%3E%3C/svg%3E") bottom center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 26'%3E%3Ccircle cx='12' cy='8' r='5.2'/%3E%3Cpath d='M1.5 26c.7-6.6 4.9-10.4 10.5-10.4S21.8 19.4 22.5 26z'/%3E%3C/svg%3E") bottom center/contain no-repeat}

.v4-person{display:flex;align-items:center;gap:9px;min-width:0}
.v4-person-t{min-width:0}
.v4-person b{display:block;font:500 var(--v4-fs-nav)/1.3 var(--v4-font);color:var(--v4-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.v4-person small{display:block;color:var(--v4-muted);font-size:var(--v4-fs-meta);margin-top:1px;font-family:var(--v4-mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

.v4-empty{padding:28px 16px;text-align:center;color:var(--v4-muted);font-size:var(--v4-fs-base);line-height:1.5}
.v4-empty.err{color:var(--v4-crit-ink)}

.v4-toast{position:fixed;left:50%;bottom:20px;transform:translate(-50%,10px);opacity:0;z-index:2000;pointer-events:none;
  background:var(--v4-ink);color:var(--v4-bg);border-radius:var(--v4-r-pill);padding:9px 16px;font-size:var(--v4-fs-base);font-weight:500;
  box-shadow:var(--v4-shadow-2);transition:opacity var(--v4-dur) ease,transform var(--v4-dur) var(--v4-ease);max-width:calc(100vw - 32px)}
.v4-toast.on{opacity:1;transform:translate(-50%,0)}

/* ---------------------------------------------------------------------------------------------
   7. SHARED PRIMITIVES (for the page agents)
   --------------------------------------------------------------------------------------------- */
/* Page head */
.v4-head{display:flex;align-items:flex-end;justify-content:space-between;gap:12px;margin-bottom:16px;flex-wrap:wrap}
.v4-head h2{font:600 var(--v4-fs-h2)/1.25 var(--v4-font);margin:0;color:var(--v4-ink)}
.v4-head p{margin:3px 0 0;color:var(--v4-ink-2);font-size:var(--v4-fs-base)}
.v4-head .v4-tools{display:flex;gap:8px;flex-wrap:wrap;align-items:center}

/* Buttons (+ ripple from the shell) */
.v4-btn{position:relative;overflow:hidden;display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:var(--v4-h);
  border:1px solid var(--v4-line-strong);background:var(--v4-surface);padding:6px 11px;border-radius:var(--v4-r);cursor:pointer;
  font:500 var(--v4-fs-base)/1.2 var(--v4-font);color:var(--v4-ink);white-space:nowrap;text-decoration:none;
  transition:transform var(--v4-dur-fast) var(--v4-ease),box-shadow var(--v4-dur-fast) var(--v4-ease),background-color var(--v4-dur-fast) ease,border-color var(--v4-dur-fast) ease,color var(--v4-dur-fast) ease}
.v4-btn:hover{background:var(--v4-surface-2);transform:translateY(-1px);box-shadow:0 6px 16px rgba(10,28,25,.08)}
.v4-btn:active{transform:translateY(0) scale(.985)}
.v4-btn.primary{background:var(--v4-accent);color:var(--v4-accent-ink);border-color:var(--v4-accent);box-shadow:0 8px 20px color-mix(in srgb,var(--v4-accent) 22%,transparent)}
.v4-btn.primary:hover{background:var(--v4-accent-2);border-color:var(--v4-accent-2)}
.v4-btn.ghost{background:transparent;border-color:transparent}
.v4-btn.ghost:hover{background:var(--v4-surface-2);box-shadow:none}
.v4-btn.danger{color:var(--v4-crit-ink);border-color:color-mix(in srgb,var(--v4-crit) 40%,var(--v4-line))}
.v4-btn.sm{min-height:var(--v4-h-sm);padding:4px 8px;font-size:var(--v4-fs-sm)}
.v4-btn[disabled],.v4-btn.disabled{opacity:.45;pointer-events:none;box-shadow:none}
.v4-btn .v4-ico{width:14px;height:14px}

/* Tabs — underline grows in (.on) */
.v4-tabs{display:flex;gap:2px;border-bottom:1px solid var(--v4-line);margin-bottom:16px;overflow-x:auto;scrollbar-width:none;max-width:100%}
.v4-tabs::-webkit-scrollbar{display:none}
.v4-tabs button,.v4-tabs a{position:relative;background:none;border:0;border-bottom:2px solid transparent;padding:8px 12px;margin-bottom:-1px;
  cursor:pointer;color:var(--v4-ink-2);font:500 var(--v4-fs-base)/1.3 var(--v4-font);white-space:nowrap;text-decoration:none;flex:0 0 auto;transition:color var(--v4-dur-fast) ease}
.v4-tabs button:hover,.v4-tabs a:hover{color:var(--v4-ink)}
.v4-tabs button::after,.v4-tabs a::after{content:"";position:absolute;left:16%;right:16%;bottom:-1px;height:2px;background:var(--v4-accent);
  transform:scaleX(0);transition:transform var(--v4-dur) var(--v4-ease)}
.v4-tabs button.on,.v4-tabs a.on,.v4-tabs [aria-selected="true"]{color:var(--v4-accent);font-weight:600}
.v4-tabs button.on::after,.v4-tabs a.on::after,.v4-tabs [aria-selected="true"]::after{transform:scaleX(1);left:0;right:0}
.v4-tabs .n{font-family:var(--v4-mono);font-size:var(--v4-fs-xs);margin-left:5px;color:var(--v4-ink-3)}
.v4-pane{animation:v4PaneIn var(--v4-dur) var(--v4-ease) both}

/* Chips — pill filters */
.v4-chips{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 12px}
.v4-chips button{position:relative;overflow:hidden;border:1px solid var(--v4-line);background:var(--v4-surface);border-radius:var(--v4-r-pill);padding:5px 11px;
  font:500 var(--v4-fs-ui)/1.3 var(--v4-font);cursor:pointer;color:var(--v4-ink-2);transition:border-color var(--v4-dur-fast) ease,color var(--v4-dur-fast) ease,background-color var(--v4-dur-fast) ease}
.v4-chips button:hover{border-color:var(--v4-accent);color:var(--v4-accent)}
.v4-chips button.on{background:var(--v4-accent-soft);border-color:color-mix(in srgb,var(--v4-accent) 40%,transparent);color:var(--v4-accent);font-weight:600}
.v4-chips button .n{font-family:var(--v4-mono);font-size:var(--v4-fs-xs);margin-left:4px;opacity:.8}

/* Segmented control */
.v4-seg{display:inline-flex;gap:2px;padding:3px;background:var(--v4-surface-2);border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);max-width:100%;overflow-x:auto}
.v4-seg button{position:relative;overflow:hidden;border:0;background:transparent;border-radius:var(--v4-r);padding:5px 11px;cursor:pointer;
  font:500 var(--v4-fs-ui)/1.3 var(--v4-font);color:var(--v4-ink-2);white-space:nowrap;transition:background-color var(--v4-dur-fast) ease,color var(--v4-dur-fast) ease,box-shadow var(--v4-dur-fast) ease}
.v4-seg button:hover{color:var(--v4-ink)}
.v4-seg button.on{background:var(--v4-surface);color:var(--v4-accent);font-weight:600;box-shadow:0 1px 2px rgba(10,28,25,.08),0 0 0 1px var(--v4-line)}

/* Filters row */
.v4-filters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:12px}
.v4-filters select,.v4-filters input,.v4-input{padding:6px 9px;min-height:var(--v4-h);border:1px solid var(--v4-line-strong);border-radius:var(--v4-r);
  background:var(--v4-surface);color:var(--v4-ink);font:400 var(--v4-fs-base)/1.3 var(--v4-font);transition:border-color var(--v4-dur-fast) ease,box-shadow var(--v4-dur-fast) ease;max-width:100%}
.v4-filters select:focus,.v4-filters input:focus,.v4-input:focus{border-color:var(--v4-accent);box-shadow:var(--v4-focus);outline:none}

/* Tables — intentional horizontal scroll inside the wrap; sticky head when the wrap scrolls. */
.v4-tablewrap{overflow:auto;max-width:100%;border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);background:var(--v4-surface);-webkit-overflow-scrolling:touch}
.v4-tablewrap.bare{border:0;border-radius:0;background:transparent}
.v4-tablewrap.tall{max-height:min(70vh,720px)}
.v4-table{width:100%;border-collapse:separate;border-spacing:0;font-size:var(--v4-fs-base);color:var(--v4-ink)}
.v4-table th{position:sticky;top:0;z-index:1;text-align:left;font:500 var(--v4-fs-sm)/1.3 var(--v4-font);color:var(--v4-muted);padding:8px 10px;
  border-bottom:1px solid var(--v4-line);white-space:nowrap;background:var(--v4-surface-2)}
.v4-table td{padding:8px 10px;border-bottom:1px solid var(--v4-line);vertical-align:middle}
.v4-table tr:last-child td{border-bottom:0}
.v4-table td.n,.v4-table th.n{text-align:right;font-family:var(--v4-mono);font-size:var(--v4-fs-ui);font-variant-numeric:tabular-nums}
.v4-table tbody tr{transition:background-color var(--v4-dur-fast) ease}
.v4-table tbody tr.click,.v4-table tbody tr[data-v4row]{cursor:pointer}
.v4-table tbody tr.click:hover td,.v4-table tbody tr[data-v4row]:hover td{background:var(--v4-hover)}
.v4-table .v4-min{min-width:140px}

/* Bars (animated fill on entry) */
.v4-bar{height:8px;border-radius:var(--v4-r-sm);background:var(--v4-line);overflow:hidden;min-width:40px}
.v4-bar > i,.v4-bar > span{display:block;height:100%;background:var(--v4-accent);border-radius:var(--v4-r-sm);transform-origin:left center}
.v4-bar > i.warn,.v4-bar > i.high{background:var(--v4-high)} .v4-bar > i.crit{background:var(--v4-crit)}
.v4-bar > i.info{background:var(--v4-info)} .v4-bar > i.ok{background:var(--v4-ok)} .v4-bar > i.med{background:var(--v4-med)}
.v4-rowbar{display:grid;grid-template-columns:minmax(90px,150px) minmax(0,1fr) 70px;gap:10px;align-items:center;padding:6px 0;font-size:var(--v4-fs-base)}
.v4-rowbar .n{text-align:right;font-family:var(--v4-mono);font-size:var(--v4-fs-ui)}
.v4-vbars{height:34px;display:flex;align-items:flex-end;gap:2px}
.v4-vbars > i{display:block;flex:1;background:var(--v4-accent);border-radius:2px 2px 0 0;min-height:2px;opacity:.85;transform-origin:bottom center}
.v4-vbars > i.hi{background:var(--v4-high)}

/* Badges / pills / severity */
.v4-badge,.v4-pill{display:inline-flex;align-items:center;gap:5px;font:500 var(--v4-fs-meta)/1.35 var(--v4-font);padding:2px 7px;border-radius:var(--v4-r-sm);
  background:var(--v4-surface-2);color:var(--v4-ink-2);white-space:nowrap;border:0}
.v4-pill{border-radius:var(--v4-r-pill);padding:2px 9px;border:1px solid var(--v4-line)}
.v4-badge.ok,.v4-pill.ok{background:var(--v4-ok-soft);color:var(--v4-ok-ink);border-color:transparent}
.v4-badge.med,.v4-pill.med,.v4-badge.warn,.v4-pill.warn{background:var(--v4-med-soft);color:var(--v4-med-ink);border-color:transparent}
.v4-badge.high,.v4-pill.high{background:var(--v4-high-soft);color:var(--v4-high-ink);border-color:transparent}
.v4-badge.crit,.v4-pill.crit,.v4-badge.bad,.v4-pill.bad{background:var(--v4-crit-soft);color:var(--v4-crit-ink);border-color:transparent}
.v4-badge.info,.v4-pill.info{background:var(--v4-info-soft);color:var(--v4-info-ink);border-color:transparent}
.v4-badge.acc,.v4-pill.acc{background:var(--v4-accent-soft);color:var(--v4-accent);border-color:transparent}
.v4-badge .dot,.v4-pill .dot{width:7px;height:7px;border-radius:50%;background:currentColor;flex:none}
.v4-sev{display:inline-flex;align-items:center;gap:6px;font:500 var(--v4-fs-ui)/1.3 var(--v4-font);color:var(--v4-ink)}
.v4-sev::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--v4-ink-3);flex:none}
.v4-sev.crit::before{background:var(--v4-crit)} .v4-sev.high::before{background:var(--v4-high)}
.v4-sev.med::before{background:var(--v4-med)} .v4-sev.info::before{background:var(--v4-info)} .v4-sev.ok::before{background:var(--v4-ok)}
.v4-live-dot{display:inline-block;width:7px;height:7px;border-radius:50%;background:var(--v4-ok);flex:none;animation:v4Pulse 2.2s ease-out infinite}
.v4-live-dot.off{background:var(--v4-ink-3);animation:none}
.v4-live-dot.bad{background:var(--v4-crit);animation:none}

/* Zone-kind colours (reference ribbon palette) */
.v4-z{--v4-zc:var(--v4-z-lobby)}
.v4-z--work{--v4-zc:var(--v4-z-work)} .v4-z--meet{--v4-zc:var(--v4-z-meet)} .v4-z--cafe{--v4-zc:var(--v4-z-cafe)}
.v4-z--common{--v4-zc:var(--v4-z-common)} .v4-z--lobby{--v4-zc:var(--v4-z-lobby)} .v4-z--out{--v4-zc:var(--v4-z-out)} .v4-z--park{--v4-zc:var(--v4-z-park)}
.v4-zdot{display:inline-block;width:10px;height:10px;border-radius:2px;background:var(--v4-zc,var(--v4-z-lobby));flex:none;vertical-align:-1px}
.v4-legend{display:flex;flex-wrap:wrap;gap:10px 14px;font-size:var(--v4-fs-sm);color:var(--v4-ink-2);margin-top:10px}
.v4-legend > span{display:inline-flex;align-items:center;gap:5px}
.v4-ribbon{position:relative;height:22px;border-radius:var(--v4-r-sm);overflow:hidden;background:var(--v4-z-out);display:flex}
.v4-ribbon > span{display:block;height:100%;min-width:1px;background:var(--v4-zc,var(--v4-z-lobby));transform-origin:left center}

/* Skeleton loading */
.v4-skel{position:relative;overflow:hidden;border-radius:var(--v4-r);min-height:12px;
  background:linear-gradient(100deg,var(--v4-surface-2) 30%,color-mix(in srgb,var(--v4-surface) 60%,var(--v4-line)) 50%,var(--v4-surface-2) 70%);
  background-size:220% 100%;animation:v4Skel 1.4s ease-in-out infinite}
.v4-skel.line{height:12px;margin:8px 0} .v4-skel.block{height:120px} .v4-skel.kpi{height:78px;border-radius:var(--v4-r-lg)}

/* Drawer (right, 480px) + scrim */
.v4-scrim{position:fixed;inset:0;background:var(--v4-scrim);z-index:940;opacity:0;pointer-events:none;transition:opacity var(--v4-dur) ease;
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.v4-scrim.on{opacity:1;pointer-events:auto}
.v4-drawer{position:fixed;top:0;right:0;bottom:0;width:min(480px,100vw);z-index:950;overflow:auto;padding:20px;color:var(--v4-ink);
  background:linear-gradient(180deg,color-mix(in srgb,var(--v4-accent) 4%,transparent),transparent 140px),var(--v4-surface);
  border-left:1px solid var(--v4-line);box-shadow:var(--v4-shadow-3);transform:translateX(102%);opacity:.2;
  transition:transform var(--v4-dur-slow) var(--v4-ease),opacity var(--v4-dur) ease;overscroll-behavior:contain}
.v4-drawer.on,.v4-drawer[open]{transform:none;opacity:1}
.v4-drawer .v4-x{position:absolute;top:14px;right:14px}
.v4-drawer-h{display:flex;align-items:flex-start;gap:12px;padding-right:40px;margin-bottom:12px}
.v4-drawer-h h2{font:600 var(--v4-fs-h2)/1.25 var(--v4-font);margin:0}
.v4-stats2{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin:12px 0}
.v4-stats2 > div{padding:8px 10px;background:var(--v4-surface-2);border-radius:var(--v4-r)}
.v4-stats2 b{display:block;font:600 var(--v4-fs-h2)/1.2 var(--v4-font);letter-spacing:-.01em}
.v4-stats2 span{font-size:var(--v4-fs-meta);color:var(--v4-ink-2)}

/* Modal */
.v4-modal{position:fixed;inset:0;z-index:960;display:none;align-items:center;justify-content:center;padding:20px;background:var(--v4-scrim);
  -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.v4-modal.on,.v4-modal[open]{display:flex}
.v4-modal-box{width:min(640px,100%);max-height:calc(100dvh - 40px);overflow:auto;background:var(--v4-surface);color:var(--v4-ink);
  border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);box-shadow:var(--v4-shadow-3);animation:v4ModalIn var(--v4-dur) var(--v4-ease) both}
.v4-modal-h{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--v4-line)}
.v4-modal-h h3{font:600 var(--v4-fs-lg)/1.3 var(--v4-font);margin:0;flex:1}
.v4-modal-b{padding:16px}
.v4-modal-f{display:flex;justify-content:flex-end;gap:8px;padding:12px 16px;border-top:1px solid var(--v4-line)}

/* List rows */
.v4-list{display:flex;flex-direction:column}
.v4-row{display:flex;align-items:center;gap:12px;padding:10px 0;border-bottom:1px solid var(--v4-line);min-width:0}
.v4-row:last-child{border-bottom:0}
.v4-row .grow{flex:1;min-width:0}
.v4-row .t1{font-weight:500;font-size:var(--v4-fs-nav)}
.v4-row .t2{color:var(--v4-muted);font-size:var(--v4-fs-sm);margin-top:1px}
.v4-row.click{cursor:pointer;margin:0 -8px;padding-left:8px;padding-right:8px;border-radius:var(--v4-r);transition:transform var(--v4-dur-fast) var(--v4-ease),background-color var(--v4-dur-fast) ease}
.v4-row.click:hover{background:var(--v4-surface-2);transform:translateX(3px)}
.v4-note{font-size:var(--v4-fs-sm);color:var(--v4-muted);line-height:1.5}
.v4-scope{display:inline-flex;align-items:center;gap:5px;font-size:var(--v4-fs-meta);color:var(--v4-muted);background:var(--v4-surface-2);border:1px solid var(--v4-line);border-radius:var(--v4-r-pill);padding:1px 8px}
/* "Preview data" marker (V4.previewMark) — subtle amber chip; never looks like a status/alert pill. */
.v4-preview-chip{display:inline-flex;align-items:center;gap:5px;font:500 var(--v4-fs-xs)/1.4 var(--v4-font);letter-spacing:.01em;white-space:nowrap;
  color:var(--v4-med-ink);background:color-mix(in srgb,var(--v4-med-soft) 70%,transparent);
  border:1px dashed color-mix(in srgb,var(--v4-med) 45%,transparent);border-radius:var(--v4-r-pill);padding:1px 8px;vertical-align:middle;pointer-events:none;user-select:none}
.v4-preview-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--v4-med);flex:none;opacity:.85}
.v4-preview-chip.float{position:absolute;top:10px;right:12px;z-index:2}

/* ---------------------------------------------------------------------------------------------
   8. GRID HELPERS — 12 columns (reference .g / .c*). ≤1180 the partial spans pair up at 6.
   --------------------------------------------------------------------------------------------- */
/* Spans (.v4-s*, .v4-c*, legacy .s*) are owned by the ONE span system in §8b. KPI rows below set their
   column TRACKS (not spans); their breakpoints are part of the shared KPI primitive. */
.v4-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-bottom:14px;min-width:0}
.v4-kpi6{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:10px;margin-bottom:14px;min-width:0}
@media (max-width:1180px){ .v4-kpi6{grid-template-columns:repeat(3,minmax(0,1fr))} }   /* same breakpoint as every other row */
@media (max-width:760px){ .v4-grid{gap:10px} .v4-kpis,.v4-kpi6{gap:8px;grid-template-columns:repeat(2,minmax(0,1fr))} .v4-kpi-v{font-size:var(--v4-fs-kpi-sm)} .v4-card{padding:12px}
  .v4-rowbar{grid-template-columns:minmax(70px,110px) minmax(0,1fr) 60px} .v4-drawer{width:100vw} }
@media (max-width:340px){ .v4-kpis,.v4-kpi6{grid-template-columns:1fr} }

/* ---------------------------------------------------------------------------------------------
   8b. LAYOUT PRIMITIVES — FIXED API (BUILD_CONTRACT "CARD GEOMETRY / ALIGNMENT"). Every agent USES these;
   only this file defines geometry. No inline widths/heights anywhere.
     Grid   .v4-grid (12 cols, gutter --v4-gap) · spans .v4-s3 .v4-s4 .v4-s6 .v4-s8 .v4-s12 only
            allowed rows: 6+6 · 4+8 · 8+4 · 4+4+4 · 3+3+3+3 (3+9 is NOT allowed → 4+8)
            .v4-c3/c4/c6/c8/c12 are aliases; legacy .v4-c5/.v4-c7 → 6, .v4-c9 → 8
     Row    .v4-row  equal-height flex row (stretch)
     Card   .v4-card (flex column, padding --v4-pad-card) › .v4-card-h (title row) › .v4-card-b (flex:1)
            › .v4-card-f (pinned footer) · .v4-card--scroll / .v4-card--collapse (body capped at
            --v4-card-scroll-max) so one card never stretches a row
     KPI    .v4-kpis / .v4-kpi6 — identical tile heights (--v4-kpi-h)
     Plot   .v4-plot — fixed plot-area height (--v4-plot-h) for every chart in a row
     Media  .v4-media-169 (camera) · .v4-media-79 (portrait) · .v4-cam-meta (fixed --v4-cam-meta-h)
     Cards  .v4-pcard (person/visitor) · .v4-rcard (report) — uniform heights
     Forms  .v4-form-row — one vertical rhythm for settings rows
     Responsive: spans collapse in GROUPS — ≤1180px 3→6, 4/8→12; ≤760px everything → 12.
   --------------------------------------------------------------------------------------------- */
:root{
  --v4-gap:14px; --v4-pad-card:var(--v4-space-4); --v4-card-head-h:28px; --v4-card-scroll-max:360px;
  --v4-kpi-h:104px; --v4-plot-h:220px; --v4-cam-meta-h:44px; --v4-pcard-h:300px; --v4-rcard-h:176px;
  /* SHARED CARD TOKENS — one source of truth for both `.v4-card` and legacy `.card` (v4 look). */
  --v4-card-r:var(--v4-r-xl); --v4-card-bd:1px solid var(--v4-line); --v4-card-sh:var(--v4-shadow-1);
}
.v4-grid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--v4-gap);align-items:stretch;min-width:0;margin-bottom:var(--v4-gap)}
.v4-grid > *{min-width:0}
.v4-grid > .v4-card,.v4-grid > .v4-rcard,.v4-grid > .v4-pcard{height:100%}
.v4-row{display:flex;gap:var(--v4-gap);align-items:stretch;min-width:0;margin-bottom:var(--v4-gap)}
.v4-row > *{flex:1 1 0;min-width:0}
@media (max-width:760px){ .v4-row{flex-direction:column} }

/* ===== SPAN SYSTEM — the ONE mechanism for v4 grids AND legacy (app.js / ui-v3) grids ===============
   1. Classes only DECLARE values, at every width: --v4-span-lg (desktop) and --v4-span-md (≤1180px).
   2. Two GENERIC breakpoint rules choose the tier for any grid item — they name no class.
   3. ONE rule applies grid-column: span var(--v4-span). Its specificity (0,3,0) + !important beats
      ui-v3.css `.v3 .s7` and styles.css's ≤1024 `grid-column:auto!important` once, here.
   Legacy classes therefore inherit the documented breakpoints automatically; no class-specific span rule
   exists inside any media query. Documented pairs: 6+6 · 4+8 · 8+4 · 4+4+4 · 3+3+3+3 (no 3+9, no 7+5).
   Classless legacy .grid children are not touched (they keep their own auto placement). */
:is(.v4-s3,.v4-c3,.s1,.s3)                        {--v4-span-lg:3;  --v4-span-md:6}
:is(.v4-s4,.v4-c4,.s2,.s4,.s5)                    {--v4-span-lg:4;  --v4-span-md:12}   /* s5 → 4 (pairs 4+8) */
:is(.v4-s6,.v4-c6,.v4-c5,.v4-c7,.s6)              {--v4-span-lg:6;  --v4-span-md:6}
:is(.v4-s8,.v4-c8,.v4-c9,.s7,.s8,.s9,.s10)        {--v4-span-lg:8;  --v4-span-md:12}   /* s7/s9/s10 → 8 */
:is(.v4-s12,.v4-c12,.s11,.s12)                    {--v4-span-lg:12; --v4-span-md:12}
/* context pairings — values only, width-independent */
:is(.v4-grid,.grid):has(> :is(.v4-c9,.s9)) > :is(.v4-s3,.v4-c3,.s3){--v4-span-lg:4; --v4-span-md:12}      /* 3 beside 9 → 4+8 */
.grid > .s5:is(:has(+ .s6 + .s6),:has(+ :not(.card) + .s6 + .s6)) ~ .s6{--v4-span-lg:4}                  /* 4 + (6,6) → 4+4+4 */
.grid > .s6:first-child:has(+ :not(.s6)),.grid > .s6:only-child,.grid > :not(.s6) + .s6:last-child,
.grid > :not(.s6) + .s6:has(+ :not(.s6)),.grid > :not(.s6) + .s6 + .s6 + .s6:is(:last-child,:has(+ :not(.s6))){--v4-span-md:12} /* lone 6 */
/* all-3-span grids (v4 and legacy alike) — the final partial row is regrouped by COUNT, never by width:
   desktop (4 per row): 4n+1 → last card 12 · 4n+2 → last two 6+6 · 4n+3 → last three 4+4+4;
   ≤1180 (2 per row): odd count → last card 12. */
:is(.v4-grid,.grid):not(:has(> :not(.v4-s3,.v4-c3,.s3))) > :last-child:nth-child(4n+1){--v4-span-lg:12}
:is(.v4-grid,.grid):not(:has(> :not(.v4-s3,.v4-c3,.s3))) > :is(:nth-last-child(2):nth-child(4n+1),:last-child:nth-child(4n+2)){--v4-span-lg:6}
:is(.v4-grid,.grid):not(:has(> :not(.v4-s3,.v4-c3,.s3))) > :is(:nth-last-child(3):nth-child(4n+1),:nth-last-child(2):nth-child(4n+2),:last-child:nth-child(4n+3)){--v4-span-lg:4}
:is(.v4-grid,.grid):not(:has(> :not(.v4-s3,.v4-c3,.s3))) > :last-child:nth-child(odd){--v4-span-md:12}                  /* 3s → 6+6, odd last */
/* generic tiers — the documented breakpoints; they set only the variable and name NO span class */
/* all-4 grids (3 per row, e.g. person/visitor cards): never a lone card, never a 12-wide person card.
   3n+1 (≥4) → last FOUR regroup 6+6 / 6+6 · 3n+2 → last TWO 6+6. */
:is(.v4-grid,.grid):not(:has(> :not(.v4-s4,.v4-c4,.s4))):has(> :last-child:nth-child(3n+4)) > :nth-last-child(-n+4){--v4-span-lg:6}
:is(.v4-grid,.grid):not(:has(> :not(.v4-s4,.v4-c4,.s4))) > :is(:nth-last-child(2):nth-child(3n+1),:last-child:nth-child(3n+2)){--v4-span-lg:6}
:is(.v4-grid,.grid) > *{--v4-span:var(--v4-span-lg,12)}
@media (max-width:1180px){ :is(.v4-grid,.grid) > *{--v4-span:var(--v4-span-md,12)} }
@media (max-width:760px){ :is(.v4-grid,.grid) > *{--v4-span:12} }
/* the ONE apply rule */
.v4-grid > *,
.v3 .grid > :is(.s1,.s2,.s3,.s4,.s5,.s6,.s7,.s8,.s9,.s10,.s11,.s12),
:where(#view > :not(.mh-app)) .grid > :is(.s1,.s2,.s3,.s4,.s5,.s6,.s7,.s8,.s9,.s10,.s11,.s12){grid-column:span var(--v4-span) !important}

.v4-card{display:flex;flex-direction:column;padding:var(--v4-pad-card)}
.v4-card-h{flex:none;min-height:var(--v4-card-head-h)}
.v4-card-b{flex:1 1 auto;min-height:0}
.v4-card-f{flex:none;margin-top:auto;padding-top:var(--v4-space-3);display:flex;align-items:center;justify-content:flex-end;gap:var(--v4-space-2);flex-wrap:wrap}
.v4-card--scroll .v4-card-b{max-height:var(--v4-card-scroll-max);overflow:auto;overscroll-behavior:auto}
.v4-card--collapse .v4-card-b{max-height:var(--v4-card-scroll-max);overflow:hidden;
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 48px),transparent);mask-image:linear-gradient(to bottom,#000 calc(100% - 48px),transparent)}
.v4-card--collapse.open .v4-card-b{max-height:none;-webkit-mask-image:none;mask-image:none}

.v4-kpis > .v4-kpi,.v4-kpi6 > .v4-kpi,.v4-kpis > *,.v4-kpi6 > *{min-height:var(--v4-kpi-h);height:100%}
.v4-kpi{display:flex;flex-direction:column}
.v4-kpi .v4-kpi-s{margin-top:auto;padding-top:var(--v4-space-1)}

.v4-plot{position:relative;height:var(--v4-plot-h);min-width:0}
.v4-plot > svg,.v4-plot > canvas{display:block;width:100%;height:100%}

.v4-media-169,.v4-media-79{position:relative;width:100%;max-width:100%;overflow:hidden;border-radius:var(--v4-r);background:var(--v4-surface-3)}
.v4-media-169{aspect-ratio:16/9;background:#0b1211}
.v4-media-79{aspect-ratio:7/9}
.v4-media-169 > img,.v4-media-169 > video,.v4-media-79 > img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.v4-cam-meta{height:var(--v4-cam-meta-h);overflow:hidden;display:flex;align-items:center;gap:var(--v4-space-2);min-width:0}

.v4-pcard{display:flex;flex-direction:column;min-height:var(--v4-pcard-h);height:100%;min-width:0}
.v4-rcard{display:flex;flex-direction:column;min-height:var(--v4-rcard-h);height:100%;min-width:0}
.v4-pcard > :last-child,.v4-rcard > :last-child{margin-top:auto}

.v4-form-row{display:grid;grid-template-columns:minmax(140px,220px) minmax(0,1fr);gap:var(--v4-space-3);align-items:center;
  padding:var(--v4-space-3) 0;border-bottom:var(--v4-bw) solid var(--v4-line);min-height:calc(var(--v4-h) + 2 * var(--v4-space-3))}
.v4-form-row:last-child{border-bottom:0}
@media (max-width:760px){ .v4-form-row{grid-template-columns:minmax(0,1fr);gap:var(--v4-space-2)} }

/* ---------------------------------------------------------------------------------------------
   8c. LEGACY NORMALISATION — app.js / ui-v3 surfaces onto the same geometry (nothing moves):
   one gutter, one card padding, one card-head height, equal heights within a row, KPI tiles at
   --v4-kpi-h, camera metadata at --v4-cam-meta-h.
   --------------------------------------------------------------------------------------------- */
:root{ --v4-card-pad:var(--v4-pad-card); }
.v3 .grid,:where(#view > :not(.mh-app)) .grid{gap:var(--v4-gap);align-items:stretch}
.v3 .kpis,:where(#view > :not(.mh-app)) .kpis{gap:var(--v4-gap);align-items:stretch}
.v3 .grid > .card,:where(#view > :not(.mh-app)) .grid > .card{display:flex;flex-direction:column;height:100%;min-width:0}
.v3 .grid > .card > .head,:where(#view > :not(.mh-app)) .grid > .card > .head{flex:none}
.v3 .card,:where(#view > :not(.mh-app)) .card{padding:var(--v4-pad-card)}
.v3 .card > .head,:where(#view > :not(.mh-app)) .card > .head{min-height:var(--v4-card-head-h);margin-bottom:var(--v4-space-3)}
.v3 .kpis > .kpi,:where(#view > :not(.mh-app)) .kpis > .kpi{min-height:var(--v4-kpi-h);height:100%}
/* Legacy .s1–.s12 spans (7+5 → 8+4, s9 → 8, 3-beside-9 → 4, lone s6 → full row at ≤1180) are mapped by
   the ONE span system in §8b — no width-specific legacy span rule exists anywhere in this file. */

/* ONE GUTTER + ONE KPI HEIGHT, app-wide (VQ audit 16:05). Every container whose direct children are
   card/KPI tiles — legacy .grid/.kpis, v4 grids, page-owner grids, the mobile .mkpis — uses --v4-gap for
   BOTH axes; every KPI tile (legacy .kpi, .v4-kpi, mobile .mkpi, any class ending in -kpi) is exactly
   --v4-kpi-h tall (one value per viewport) with label / value / subline each on one line + ellipsis.
   !important so ui-v3.css (generated) and the page files cannot re-introduce a second value. */
:root{ --v4-kpi-h:108px; }
@media (max-width:899px){ :root{ --v4-kpi-h:96px; } }
:is(#view,#mobileShellRoot) :has(> :is(.card,.v4-card,.kpi,.v4-kpi,.mkpi,.mcard,.camtile,.galcard,.v4-rcard,.v4-pcard,.hs-panel,
  [class$="-card"],[class*="-card "],[class$="-kpi"],[class*="-kpi "],[class$="-tile"],[class*="-tile "]) + *):not(.mh-app *){
  column-gap:var(--v4-gap)!important;row-gap:var(--v4-gap)!important}
:is(#view,#mobileShellRoot) :is(.kpi,.v4-kpi,.mkpi,[class$="-kpi"],[class*="-kpi "]):not(.mh-app *){
  height:var(--v4-kpi-h)!important;min-height:0!important;max-height:var(--v4-kpi-h)!important;overflow:hidden;box-sizing:border-box}
:is(#view,#mobileShellRoot) :is(.kpi,.v4-kpi,.mkpi,[class$="-kpi"],[class*="-kpi "]):not(.mh-app *)
  :is(.kt,.k-label,.kv,.k-value,.kd,.k-sub,.v4-kpi-l,.v4-kpi-v,.v4-kpi-s,.mkt,.mkv,.mkd,[class*="kpi-l"],[class*="kpi-v"],[class*="kpi-s"]){
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;max-width:100%}

/* KPI-ROW GROUPING — ONE generic rule set for EVERY KPI row alike (legacy .kpis, .v4-kpis, .v4-kpi6, mobile
   .mkpis). KPI rows are track grids (not span grids), so grouping works on their tracks, on the SAME shared
   breakpoints (1180 / 899) for all of them — never a per-row, per-width patch:
     · 900–1180px (3-track range): a 4-tile row groups 2+2; otherwise a lone last tile (3n+1) spans the row.
     · <900px (mobile shell; every KPI row is 2 tracks): an odd last tile spans the row.
   Card/span grids get the same guarantees from the §8b span system (lone .s6 and odd all-3 rows → full row). */
@media (min-width:900px) and (max-width:1180px){
  :is(.kpis,.v4-kpis,.v4-kpi6):has(> :nth-child(4):last-child){grid-template-columns:repeat(2,minmax(0,1fr))!important}
  :is(.kpis,.v4-kpi6):not(:has(> :nth-child(4):last-child)) > :last-child:nth-child(3n+1){grid-column:1 / -1}
}
@media (max-width:899px){
  :is(.kpis,.v4-kpis,.v4-kpi6,.mkpis) > :last-child:nth-child(odd){grid-column:1 / -1}
}

/* =====================================================================================================
   IMAGE PARITY — TOP BAR + SIDEBAR (ref_overview_2026-09-11.png). Existing controls restyled in place;
   icons are the current WorkSight set (sizes/containers only).
   ===================================================================================================== */
:root{ --v4-top:64px; --v4-ctl-h:38px; }
.main > .top{height:var(--v4-top);min-height:var(--v4-top);gap:var(--v4-space-3)}
.top .titlewrap h1{font:var(--v4-fw-semi) var(--v4-fs-h2)/1.2 var(--v4-font);font-size:20px;letter-spacing:-.015em}
.top .titlewrap .sub{font-size:var(--v4-fs-base);color:var(--v4-muted);margin-top:2px}
/* LIVE pill: live / delayed / offline from the freshness signal (never green without data) */
.top .live{height:var(--v4-ctl-h);padding:0 var(--v4-space-3);gap:var(--v4-space-2);border-radius:var(--v4-r-pill);
  background:var(--v4-surface);border:var(--v4-bw) solid var(--v4-line);box-shadow:var(--v4-shadow-1)}
.top .live .lbadge{font:700 var(--v4-fs-sm)/1 var(--v4-font);letter-spacing:.04em;order:1}
.top .live .dot{order:0}
.top .live #clock{order:2;font:var(--v4-fw-med) var(--v4-fs-ui)/1 var(--v4-font);color:var(--v4-ink-2)}
.top .live #clock::before{content:"•";margin-right:var(--v4-space-2);color:var(--v4-ink-3)}
.top .live.is-live .lbadge{color:var(--v4-ok-ink)}
.top .live.is-live .dot{background:var(--v4-ok)}
.top .live.is-delayed .lbadge{color:var(--v4-med-ink)}
.top .live.is-delayed .dot{background:var(--v4-med);animation:none}
.top .live.is-offline .lbadge{color:var(--v4-ink-3)}
.top .live.is-offline .dot{background:var(--v4-ink-3);animation:none}
/* global search field + shortcut hint (the existing Advanced Search action) */
.top .topbtn.v4-search{min-width:240px;height:var(--v4-ctl-h);justify-content:flex-start;gap:var(--v4-space-2);padding:0 var(--v4-space-2) 0 var(--v4-space-3);
  background:var(--v4-surface);border:var(--v4-bw) solid var(--v4-line);border-radius:var(--v4-r-lg);color:var(--v4-muted);font-weight:var(--v4-fw-reg)}
.top .topbtn.v4-search span{flex:1;text-align:left;display:inline}
.top .topbtn.v4-search:hover{border-color:var(--v4-line-strong);color:var(--v4-ink-2)}
.top .v4-kbd{font:var(--v4-fw-semi) var(--v4-fs-xs)/1 var(--v4-font);color:var(--v4-ink-2);background:var(--v4-surface-2);
  border:var(--v4-bw) solid var(--v4-line);border-radius:var(--v4-r-sm);padding:3px 6px;margin-left:auto}
.top .v4-search ~ #globalSearch{display:none}
@media (max-width:1400px){ .top .topbtn.v4-search{min-width:180px} }
@media (max-width:1180px){ .top .topbtn.v4-search{min-width:0} .top .topbtn.v4-search span,.top .v4-kbd{display:none} }
/* icon buttons, bell count, theme */
.top .iconbtn{width:var(--v4-ctl-h);height:var(--v4-ctl-h);border-radius:var(--v4-r-lg)}
.top .notifwrap{position:relative}
/* bare unread DOT (not a count pill): fixed ~9px circle, no number/padding; JS injects a count
   into textContent but font-size:0 hides it; visibility driven by [hidden] toggle (unread>0). */
.top .notifdot{position:absolute;top:-2px;right:-2px;width:9px;height:9px;min-width:0;padding:0;border-radius:var(--v4-r-pill);
  background:var(--v4-crit);font-size:0;line-height:0;color:transparent;box-shadow:0 0 0 2px var(--v4-surface)}
/* profile */
.v4-profile{position:relative;flex:none}
.v4-profile[hidden]{display:none!important}
/* Always-visible top-bar Sign out (owner request) — compact icon button (fits with sidebar expanded) */
.v4-signout{display:inline-flex;align-items:center;justify-content:center;width:var(--v4-ctl-h);height:var(--v4-ctl-h);padding:0;margin-right:var(--v4-space-1);border:0;border-radius:var(--v4-r-pill);background:none;color:var(--v4-ink-2);cursor:pointer;flex:none}
.v4-signout:hover{background:var(--v4-crit-soft);color:var(--v4-crit,#c0392b)}
.v4-signout svg{display:block}
.v4-profile-btn{display:inline-flex;align-items:center;gap:var(--v4-space-1);height:var(--v4-ctl-h);padding:0 var(--v4-space-1);border:0;background:none;cursor:pointer;color:var(--v4-ink-2);border-radius:var(--v4-r-pill)}
.v4-profile-btn:hover{background:var(--v4-surface-2)}
.v4-avatar{width:34px;height:34px;border-radius:50%;display:grid;place-items:center;background:var(--v4-surface-3);color:var(--v4-ink);
  font:var(--v4-fw-semi) var(--v4-fs-base)/1 var(--v4-font);border:var(--v4-bw) solid var(--v4-line)}
.v4-chevd{width:14px;height:14px;transform:rotate(90deg)}
.v4-profile-menu{position:absolute;right:0;top:calc(100% + 6px);min-width:200px;padding:var(--v4-space-2);z-index:60;background:var(--v4-surface);
  border:var(--v4-bw) solid var(--v4-line);border-radius:var(--v4-r-lg);box-shadow:var(--v4-shadow-2)}
.v4-profile-who{padding:var(--v4-space-2);border-bottom:var(--v4-bw) solid var(--v4-line);margin-bottom:var(--v4-space-1)}
.v4-profile-who b{display:block;font:var(--v4-fw-semi) var(--v4-fs-base)/1.3 var(--v4-font);color:var(--v4-ink)}
.v4-profile-who small{display:block;font-size:var(--v4-fs-sm);color:var(--v4-muted)}
.v4-profile-out{width:100%;text-align:left;border:0;background:none;padding:var(--v4-space-2);border-radius:var(--v4-r);cursor:pointer;
  font:var(--v4-fw-med) var(--v4-fs-base)/1.2 var(--v4-font);color:var(--v4-crit-ink)}
.v4-profile-out:hover{background:var(--v4-crit-soft)}
.top .v4-profile:not([hidden]) ~ #logout{display:none!important}
/* brand: the CURRENT logo, sized like the reference (asset unchanged) */
.side .brand{height:var(--v4-top);min-height:var(--v4-top)}
.side .brand .brandlogo{height:38px;width:auto}
.side .brand .brandicon{width:32px;height:32px}
/* sidebar: larger rows, soft tinted active pill, status block card, collapse row */
#nav .v4-navhead,#nav .nav{min-height:40px;font-size:var(--v4-fs-md);gap:var(--v4-space-3);border-radius:var(--v4-r-lg)}
#nav .v4-navhead .v4-navgi,#nav .nav .v4-navgi{width:18px;height:18px}
#nav .v4-navitems .nav{padding-left:42px;min-height:34px;font-size:var(--v4-fs-base)}
#nav .nav.on{box-shadow:none;background:var(--v4-accent-soft)}
.side .sidefoot{margin:var(--v4-space-3);padding:var(--v4-space-3);border:var(--v4-bw) solid var(--v4-line);border-radius:var(--v4-r-lg);
  background:var(--v4-surface);box-shadow:var(--v4-shadow-1)}
.side .sidefoot .ping{margin-bottom:var(--v4-space-2);font-size:var(--v4-fs-sm);color:var(--v4-ink-2)}
.side .sidefoot .v4-site{display:block;font:var(--v4-fw-semi) var(--v4-fs-md)/1.3 var(--v4-font);color:var(--v4-ink)}
.side .sidefoot .v4-sitesub{display:block;font-size:var(--v4-fs-sm);color:var(--v4-muted)}
.side .v4-collapse{display:flex;align-items:center;gap:var(--v4-space-2);margin:0 var(--v4-space-3) var(--v4-space-3);padding:var(--v4-space-2) var(--v4-space-3);
  border:0;background:none;border-radius:var(--v4-r-lg);cursor:pointer;color:var(--v4-ink-2);font:var(--v4-fw-med) var(--v4-fs-base)/1.2 var(--v4-font);flex:none}
.side .v4-collapse:hover{background:var(--v4-surface-2);color:var(--v4-ink)}
.side .v4-collapse-ic{display:inline-grid;width:16px;height:16px}
.side .v4-collapse-ic svg{width:16px;height:16px}
.side .v4-collapse.is-min .v4-collapse-ic{transform:rotate(180deg)}
@media (min-width:900px){ .side.min .v4-collapse{justify-content:center;margin:0 var(--v4-space-2) var(--v4-space-2);padding:var(--v4-space-2) 0} .side.min .v4-collapse-l{display:none} .side.min .sidefoot{margin:var(--v4-space-2);padding:var(--v4-space-2)} }
/* cards: calm white surfaces, soft borders, restrained shadow, one radius/padding */
.v3 .card,:where(#view > :not(.mh-app)) .card,.v4-card{border-radius:var(--v4-card-r)}

/* =====================================================================================================
   TELEMETRY TILE — the ONE primitive for the Overview KPI row (documented family .hs-panel; own height,
   all six tiles equal). Restyles the EXISTING ui-v3 commandV3 DOM in place (C2a renders it unchanged):
     .hs-row                                        row: 6 tiles ≥1440px, 3 tiles below (never an orphan)
     .hs-panel[.is-good|.is-warn|.is-bad|.is-na]   tile (button, data-go) — band drives dot/ring/tint
       .hs-card-top   HEADER  › .hs-icon-badge (the CURRENT WorkSight icon, untouched; tinted container)
                               › .hs-label (short) › .hs-status-beacon > .hs-beacon-dot
       .hs-card-mid   BODY    › .hs-value-wrap > .hs-value (value or state word; <small> = denominator)
                               › .hs-side-visual › .hs-gauge-dial (ring — ONLY when a real % exists)
                                                   or .hs-count-badge > .hs-count-pill (count, no ring)
       .hs-card-bot   FOOTER  › ONE .hs-detail line  OR  ONE .v4-badge
   Tokens only; the ring is an SVG sized by --v4-tile-ring. Other pages' KPI tiles keep --v4-kpi-h.
   ===================================================================================================== */
:root{
  /* sized so a ≤16-char label ("Workplace status") and a one-line footer ("open · last 30 days") fit a
     6-up tile at 1440 (inner ≈155px) and a 3-up tile at 1366/1024 */
  --v4-tile-h:150px; --v4-tile-pad:14px 14px; --v4-tile-icon:32px; --v4-tile-icon-r:var(--v4-r-md); --v4-tile-gap:6px;
  --v4-tile-ring:clamp(44px,3.1vw,60px); --v4-tile-value:clamp(20px,1.5vw,26px); --v4-tile-denom:var(--v4-fs-lg);
  --v4-tile-label:var(--v4-fs-ui); --v4-stack-min:0px; --v4-stack-tall-h:520px;   /* Review C self-review: alerts card = its content, people fills the rest */
}
.hs-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--v4-gap);perspective:none}
@media (min-width:1440px){ .hs-row{grid-template-columns:repeat(6,minmax(0,1fr))} }
/* Owner decision 2026-09-13: the Overview strip is 4 people tiles (3 for a role without alerts). Tracks follow
   the tile count so no row carries empty slots or a lone orphan: 4 → 4 across (2+2 at ≤1180), 3 → 3 across. */
.hs-row:has(> .hs-panel:nth-child(4):last-child){grid-template-columns:repeat(4,minmax(0,1fr))}
.hs-row:has(> .hs-panel:nth-child(3):last-child){grid-template-columns:repeat(3,minmax(0,1fr))}
@media (max-width:1180px){ .hs-row:has(> .hs-panel:nth-child(4):last-child){grid-template-columns:repeat(2,minmax(0,1fr))} }
.hs-row .hs-panel{height:var(--v4-tile-h);padding:var(--v4-tile-pad);display:flex;flex-direction:column;
  background:var(--v4-surface);border:var(--v4-bw) solid var(--v4-line);border-radius:var(--v4-r-lg);
  box-shadow:var(--v4-shadow-1);color:var(--v4-ink);font-family:var(--v4-font);
  transform:none!important;transform-style:flat;will-change:auto;animation:none;
  transition:box-shadow var(--v4-dur) var(--v4-ease),border-color var(--v4-dur) var(--v4-ease)}
.hs-row .hs-panel.is-warn{background:linear-gradient(180deg,color-mix(in srgb,var(--v4-med-soft) 55%,var(--v4-surface)) 0%,var(--v4-surface) 70%)}
.hs-row .hs-panel.is-bad{background:linear-gradient(180deg,color-mix(in srgb,var(--v4-crit-soft) 55%,var(--v4-surface)) 0%,var(--v4-surface) 70%)}
.hs-row .hs-panel:hover{border-color:color-mix(in srgb,var(--v4-accent) 24%,var(--v4-line));box-shadow:var(--v4-shadow-2)}
.hs-row .hs-panel:active{transform:none!important}
.hs-row .hs-panel:focus-visible{outline:var(--v4-bw-focus) solid var(--v4-accent);outline-offset:2px;box-shadow:var(--v4-shadow-1)}
.hs-row .hs-card-glaze,.hs-row .hs-card-glow{display:none}
.hs-row .hs-card-content{height:100%;display:flex;flex-direction:column;transform-style:flat}
.hs-row :is(.hs-card-top,.hs-card-mid,.hs-card-bot,.hs-side-visual,.hs-card-label-row){transform:none!important}
/* header */
.hs-row .hs-card-top{display:flex;align-items:center;justify-content:flex-start;gap:var(--v4-tile-gap);margin:0;min-width:0;flex:none}
.hs-row .hs-icon-badge{width:var(--v4-tile-icon);height:var(--v4-tile-icon);flex:none;border-radius:var(--v4-tile-icon-r);
  background-color:var(--v4-accent-soft);border:0;box-shadow:none;color:var(--v4-accent)}
.hs-row .hs-panel.is-warn .hs-icon-badge{background-color:var(--v4-med-soft);color:var(--v4-med-ink)}
.hs-row .hs-panel.is-bad .hs-icon-badge{background-color:var(--v4-crit-soft);color:var(--v4-crit-ink)}
.hs-row .hs-panel.is-na .hs-icon-badge{background-color:var(--v4-surface-2);color:var(--v4-ink-2)}
.hs-row .hs-icon-badge svg{width:var(--v4-ic-lg);height:var(--v4-ic-lg)}
.hs-row .hs-label{flex:0 1 auto;font:var(--v4-fw-semi) var(--v4-tile-label)/1.25 var(--v4-font);letter-spacing:-.01em;color:var(--v4-ink);min-width:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hs-row .hs-panel:hover .hs-label{color:var(--v4-ink)}
.hs-row .hs-status-beacon{width:auto;height:auto;flex:none;background:none;border:0;box-shadow:none;margin-left:0!important;
  position:static!important;inset:auto!important;transform:none!important}   /* in the header flow: dot follows the label, never overlaps it */
.hs-row .hs-card-top > .hs-label{flex:0 1 auto!important}   /* dot follows the label (reference), not pushed to the edge */
.hs-row .hs-beacon-dot{width:8px;height:8px;box-shadow:none!important}
.hs-row .hs-panel.is-good .hs-beacon-dot{background:var(--v4-ok)}
.hs-row .hs-panel.is-warn .hs-beacon-dot{background:var(--v4-med)}
.hs-row .hs-panel.is-bad .hs-beacon-dot{background:var(--v4-crit)}
.hs-row .hs-panel.is-na .hs-beacon-dot{background:var(--v4-ink-3)}
/* body */
.hs-row .hs-card-mid{flex:1 1 auto;display:flex;align-items:center;justify-content:space-between;gap:var(--v4-space-2);margin:0;min-height:0;min-width:0}
.hs-row .hs-value-wrap{min-width:0;overflow:hidden}
.hs-row .hs-value{font:700 var(--v4-tile-value)/1.1 var(--v4-font);letter-spacing:-.02em;color:var(--v4-ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.hs-row .hs-value small{font:var(--v4-fw-med) var(--v4-tile-denom)/1 var(--v4-font);color:var(--v4-muted);letter-spacing:0}
.hs-row .hs-side-visual{flex:none;width:auto!important;min-width:0;height:auto!important}   /* holder = its ring (ui-v3 pinned it at 44px) */
/* ring box and SVG share ONE size token (ui-v3's size pass pinned the box at 44px while the SVG grew to 60px
   at wide screens — the ring spilled past the tile edge and "100%" lost its "1") */
.hs-row .hs-gauge-dial,.hs-row .hs-gauge-svg{width:var(--v4-tile-ring)!important;height:var(--v4-tile-ring)!important;flex:none}
.hs-row .hs-gauge-dial{position:relative;display:grid;place-items:center}
.hs-row .hs-gauge-svg{position:absolute;inset:0}
.hs-row .hs-gauge-svg{filter:none}
.hs-row .hs-gauge-track{stroke:var(--v4-line);stroke-width:5}
.hs-row .hs-gauge-arc{stroke-width:5}
.hs-row .hs-panel.is-good .hs-gauge-arc{stroke:var(--v4-ok)}
.hs-row .hs-panel.is-warn .hs-gauge-arc{stroke:var(--v4-med)}
.hs-row .hs-panel.is-bad .hs-gauge-arc{stroke:var(--v4-crit)}
.hs-row .hs-panel.is-na .hs-gauge-arc{stroke:var(--v4-ink-3)}
.hs-row .hs-gauge-center{width:auto;height:auto;background:none;border:0;box-shadow:none}
/* the % scales with the ring (inner diameter = ring − 2×stroke), so "100%" never touches the arc */
.hs-row .hs-gauge-pct{font:var(--v4-fw-semi) calc(var(--v4-tile-ring) * .21)/1 var(--v4-font);color:var(--v4-ink);letter-spacing:-.02em}
/* narrow tile (6-up at 1440): the header compacts inside the TILE's own width — never ellipsis a ≤16-char label */
.hs-row .hs-panel{container-type:inline-size}
@container (max-width:190px){
  .hs-row .hs-card-top{gap:4px}
  .hs-row .hs-icon-badge{width:28px;height:28px}
  .hs-row .hs-label{font-size:var(--v4-fs-sm);letter-spacing:-.03em}   /* "Workplace status" needs 109px of 107 at 6-up/1440 */
}
/* BODY = value (+ denominator) and a ring ONLY for a real %. The neutral count pill repeats the number the
   value already shows ("14 · ON SITE", "281 · OPEN") and squeezed value/footer — not part of the tile. */
.hs-row .hs-count-badge{display:none}
.hs-row .hs-count-pill{width:auto;min-width:52px;height:auto;padding:var(--v4-space-1) var(--v4-space-2);border-radius:var(--v4-r-md);
  background:var(--v4-surface-2);border:var(--v4-bw) solid var(--v4-line);box-shadow:none}
.hs-row .hs-count-num{font:700 var(--v4-fs-lg)/1.1 var(--v4-font);color:var(--v4-ink)}
.hs-row .hs-panel.is-good .hs-count-num{color:var(--v4-ok-ink)}
.hs-row .hs-count-sub{font:var(--v4-fw-semi) var(--v4-fs-3xs)/1 var(--v4-font);letter-spacing:.06em;color:var(--v4-muted)}
/* footer: ONE line or ONE badge */
.hs-row .hs-card-bot{flex:none;margin:0;padding:0;border:0;min-width:0}
.hs-row .hs-detail{font:var(--v4-fw-reg) var(--v4-fs-sm)/1.35 var(--v4-font);color:var(--v4-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hs-row .hs-card-bot > .v4-badge{max-width:100%;overflow:hidden;text-overflow:ellipsis}
@media (prefers-reduced-motion:reduce){ .hs-row .hs-panel{transition:none} }

/* STACK COLUMN — generic 8+4 row whose 4-column holds a stack (any grid whose FIRST card spans 8 and two
   rows: legacy .span2 / v4 .v4-rows2). Rows become `auto 1fr`, so the tall card's extra height goes to the
   flexible row only: the first stacked card is content-driven (≥ --v4-stack-min), the second contributes no
   height of its own, fills the rest and scrolls internally — both bottoms align with the tall card.
   Only where the 8+4 exists (desktop tier); below it everything stacks full width and this is inert. */
.v4-grid > .v4-rows2{grid-row:span 2}
@media (min-width:1181px){
  :is(.v3 .grid,.v4-grid):has(> :is(.span2,.v4-rows2):first-child){grid-template-rows:auto minmax(0,1fr)}
  /* the tall card has a DEFINITE height (px, not %): a % height is ignored during track sizing, so its content
     height (~700px) sized the rows and the stack overran it by 108px. Definite → rows = card, stack fills it. */
  :is(.v3 .grid,.v4-grid) > :is(.span2,.v4-rows2):first-child{height:var(--v4-stack-tall-h)!important;align-self:start}
  :is(.v3 .grid,.v4-grid):has(> :is(.span2,.v4-rows2):first-child) > :is(.span2,.v4-rows2):first-child + *{min-height:var(--v4-stack-min);align-self:start;height:auto}
  :is(.v3 .grid,.v4-grid):has(> :is(.span2,.v4-rows2):first-child) > :is(.span2,.v4-rows2):first-child + * + *{
    contain:size;height:auto;min-height:0;align-self:stretch;display:flex;flex-direction:column;overflow:hidden}
  /* contain:size = the filler contributes NO intrinsic height, so row 2 is exactly what the tall card leaves
     (was height:0 + min-height:100%, which resolved as content height and pushed the column 108px below the map) */
  :is(.v3 .grid,.v4-grid):has(> :is(.span2,.v4-rows2):first-child) > :is(.span2,.v4-rows2):first-child + * + * > :last-child{
    flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:auto}
}

.camtile{display:flex;flex-direction:column}
.camtile .camhead{height:var(--v4-cam-meta-h);min-height:var(--v4-cam-meta-h);align-items:center;overflow:hidden}
.camtile .camvid{aspect-ratio:16/9;flex:none}

/* ---------------------------------------------------------------------------------------------
   9. RESTYLE OF EXISTING PAGES. Colours come through the §2 bridge; the rules below align
   geometry/typography with the reference. `.v3 X` = ported pages; `:where(#view > :not(.mh-app)) X`
   = legacy app.js pages at bare-X specificity, never inside Movement Tracker.
   --------------------------------------------------------------------------------------------- */
/* Page heads */
.v3 .pagehead{margin-bottom:16px;align-items:flex-end}
.v3 .pagehead h2{font:600 var(--v4-fs-h2)/1.25 var(--v4-font);letter-spacing:-.01em}
.v3 .pagehead .sub{font-size:var(--v4-fs-base);color:var(--v4-ink-2)}

/* Cards */
.v3 .card,
:where(#view > :not(.mh-app)) .card{background:var(--v4-surface);border:var(--v4-card-bd);border-radius:var(--v4-card-r);box-shadow:var(--v4-card-sh)}
.v3 .card.support{background:var(--v4-surface-2)}
.v3 .card .head h3,
:where(#view > :not(.mh-app)) .card .head h3{font:600 var(--v4-fs-md)/1.3 var(--v4-font);letter-spacing:-.01em;text-transform:none;color:var(--v4-ink)}
:where(#view > :not(.mh-app)) .head h3::before{display:none}
.v3 .card .head small,
:where(#view > :not(.mh-app)) .head small{font-size:var(--v4-fs-sm);color:var(--v4-muted)}

/* KPI tiles */
.v3 .kpi,
:where(#view > :not(.mh-app)) .kpi{border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);box-shadow:var(--v4-shadow-1);background:var(--v4-surface)}
.v3 .kpi .k-label,
:where(#view > :not(.mh-app)) .kpi .kt{font-size:var(--v4-fs-sm);color:var(--v4-ink-2)}
.v3 .kpi .k-value,
:where(#view > :not(.mh-app)) .kpi .kv{font-family:var(--v4-font);font-weight:600;letter-spacing:-.02em;color:var(--v4-ink)}
.v3 .kpi .k-sub,
:where(#view > :not(.mh-app)) .kpi .kd{font-size:var(--v4-fs-sm)}

/* Tables */
.v3 .tablewrap,
:where(#view > :not(.mh-app)) .tablewrap{border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);max-width:100%;overflow-x:auto;background:var(--v4-surface)}
.v3 thead th,
:where(#view > :not(.mh-app)) th{font:500 var(--v4-fs-sm)/1.3 var(--v4-font);letter-spacing:0;color:var(--v4-muted);background:var(--v4-surface-2);border-bottom:1px solid var(--v4-line)}
.v3 tbody td,
:where(#view > :not(.mh-app)) td{font-size:var(--v4-fs-base);border-bottom:1px solid var(--v4-line)}
.v3 tbody tr.click:hover,
.v3 tbody tr[data-prow2]:hover,
:where(#view > :not(.mh-app)) tbody tr:hover{background:var(--v4-hover)}
.v3 tbody tr.click:hover td,
.v3 tbody tr[data-prow2]:hover td{background:transparent}

/* Status pills / tags */
.v3 .pill{font:500 var(--v4-fs-meta)/1.35 var(--v4-font);padding:2px 8px;border-radius:var(--v4-r-pill)}
.v3 .pill.ok,.pill.ok{color:var(--v4-ok-ink);background:var(--v4-ok-soft);border-color:transparent}
.v3 .pill.warn,.pill.warn{color:var(--v4-med-ink);background:var(--v4-med-soft);border-color:transparent}
.v3 .pill.bad,.pill.bad{color:var(--v4-crit-ink);background:var(--v4-crit-soft);border-color:transparent}
:where(#view > :not(.mh-app)) .tag,.modal .tag{font:500 var(--v4-fs-meta)/1.35 var(--v4-font);letter-spacing:0;text-transform:none;padding:2px 7px;border-radius:var(--v4-r-sm)}
.tag.ok{color:var(--v4-ok-ink);background:var(--v4-ok-soft)}
.tag.warn{color:var(--v4-med-ink);background:var(--v4-med-soft)}
.tag.bad{color:var(--v4-crit-ink);background:var(--v4-crit-soft)}
.tag.info{color:var(--v4-info-ink);background:var(--v4-info-soft)}

/* Buttons */
.v3 .btn,
:where(#view > :not(.mh-app)) .btn,
.modal .btn,.setdrawer .btn,.setmodal .btn{position:relative;overflow:hidden;min-height:var(--v4-h);border-radius:var(--v4-r);border:1px solid var(--v4-line-strong);
  background:var(--v4-surface);color:var(--v4-ink);font-weight:500;font-family:var(--v4-font);
  transition:transform var(--v4-dur-fast) var(--v4-ease),box-shadow var(--v4-dur-fast) var(--v4-ease),background-color var(--v4-dur-fast) ease,border-color var(--v4-dur-fast) ease}
.v3 .btn{height:auto;min-height:var(--v4-h);font-size:var(--v4-fs-base)}
.v3 .btn:hover,
:where(#view > :not(.mh-app)) .btn:hover,
.modal .btn:hover,.setdrawer .btn:hover,.setmodal .btn:hover{background:var(--v4-surface-2);color:var(--v4-ink);border-color:var(--v4-line-strong);transform:translateY(-1px);box-shadow:0 6px 16px rgba(10,28,25,.08)}
.v3 .btn:active,:where(#view > :not(.mh-app)) .btn:active{transform:translateY(0) scale(.985)}
.v3 .btn.primary,
:where(#view > :not(.mh-app)) .btn.primary,
.modal .btn.primary,.setdrawer .btn.primary,.setmodal .btn.primary{background:var(--v4-accent);border-color:var(--v4-accent);color:var(--v4-accent-ink);
  box-shadow:0 8px 20px color-mix(in srgb,var(--v4-accent) 22%,transparent)}
.v3 .btn.primary:hover,
:where(#view > :not(.mh-app)) .btn.primary:hover,
.modal .btn.primary:hover,.setdrawer .btn.primary:hover,.setmodal .btn.primary:hover{background:var(--v4-accent-2);border-color:var(--v4-accent-2);color:var(--v4-accent-ink)}
.v3 .btn.ghost,.setdrawer .btn.ghost,.setmodal .btn.ghost{background:transparent}
.v3 .btn.danger,:where(#view > :not(.mh-app)) .btn.danger{color:var(--v4-crit-ink);border-color:color-mix(in srgb,var(--v4-crit) 40%,var(--v4-line));background:transparent}
.v3 .btn[disabled],:where(#view > :not(.mh-app)) .btn[disabled]{opacity:.5;transform:none;box-shadow:none}

/* Inputs */
.v3 .select,.v3 select,
.v3 input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),
:where(#view > :not(.mh-app)) select,
:where(#view > :not(.mh-app)) input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),
.setdrawer input:not([type=checkbox]):not([type=radio]),.setdrawer select,
.setmodal input:not([type=checkbox]):not([type=radio]),.setmodal select,.modal select,.modal input[type=text],.modal input:not([type]){
  border-color:var(--v4-line-strong);background-color:var(--v4-surface);color:var(--v4-ink);border-radius:var(--v4-r)}
.v3 .search input,.v3 .search input:focus{border:0;background:none;box-shadow:none}
.v3 .select:focus,.v3 select:focus,
:where(#view > :not(.mh-app)) select:focus,
:where(#view > :not(.mh-app)) input:focus,
.setdrawer input:focus,.setdrawer select:focus,.setmodal input:focus,.setmodal select:focus{border-color:var(--v4-accent);box-shadow:var(--v4-focus);outline:none}
.v3 .search{border-radius:var(--v4-r);border-color:var(--v4-line-strong);background:var(--v4-surface)}
.v3 .search:focus-within{border-color:var(--v4-accent);box-shadow:var(--v4-focus)}
.v3 .search svg{color:var(--v4-ink-3)}
input[type=checkbox],input[type=radio]{accent-color:var(--v4-accent)}

/* Segmented chip rows (All / Employees / Visitors …) */
.v3 .chips:not(.planmap *,.offplan *){gap:2px;padding:3px;background:var(--v4-surface-2);border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);width:max-content;max-width:100%}
.v3 .chip:not(.planmap *,.offplan *){border:0;background:transparent;border-radius:var(--v4-r);padding:5px 11px;font-size:var(--v4-fs-ui);font-weight:500;color:var(--v4-ink-2);line-height:1.4}
.v3 .chip:not(.planmap *,.offplan *):hover{color:var(--v4-ink);background:transparent}
.v3 .chip.on:not(.planmap *,.offplan *){background:var(--v4-surface);color:var(--v4-accent);font-weight:600;box-shadow:0 1px 2px rgba(10,28,25,.08),0 0 0 1px var(--v4-line)}

/* Tabs — underline everywhere. Kill the leaked pill track (styles.css .tabs 11px) and the
   8px top-corner item (ui-v3.css .v3 .tab) so .tabs radius is 0 in ALL contexts, not 8px here /
   0px there. */
.v3 .tabs{background:transparent;border:0;border-bottom:1px solid var(--v4-line);border-radius:0;padding:0;gap:2px}
.v3 .tab{border-radius:0;background:transparent;box-shadow:none;font-size:var(--v4-fs-base);font-weight:500;color:var(--v4-ink-2);padding:8px 12px}
.v3 .tab:hover{color:var(--v4-ink);background:transparent}
.v3 .tab.on{color:var(--v4-accent);font-weight:600;background:transparent;box-shadow:none}
.v3 .tab.on::after{background:var(--v4-accent)}
:where(#view > :not(.mh-app)) .tabs{background:transparent;border:0;border-bottom:1px solid var(--v4-line);border-radius:0;padding:0;gap:2px}
:where(#view > :not(.mh-app)) .tab{position:relative;border-radius:0;font-size:var(--v4-fs-base);font-weight:500;color:var(--v4-ink-2);padding:8px 12px;background:transparent}
:where(#view > :not(.mh-app)) .tab.on{background:transparent;box-shadow:none;color:var(--v4-accent);font-weight:600}
:where(#view > :not(.mh-app)) .tab.on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--v4-accent)}

/* Report / analytics section tabs (.antabs/.antab) — normalise the pill variant (styles.css:2831,
   99px) to the SAME v4 underline component as .tabs / .v4-tabs, so every tab bar reads alike. */
:where(#view) .antabs{background:transparent;border:0;border-bottom:1px solid var(--v4-line);border-radius:0;padding:0;gap:2px;flex-wrap:nowrap;overflow-x:auto;margin:0 0 16px}
:where(#view) .antab{position:relative;border:0;border-radius:0;background:transparent;color:var(--v4-ink-2);font:500 var(--v4-fs-base)/1.3 var(--v4-font);padding:8px 12px;margin-bottom:-1px;white-space:nowrap}
:where(#view) .antab:hover{color:var(--v4-ink);border-color:transparent;background:transparent}
:where(#view) .antab.on{color:var(--v4-accent);font-weight:600;background:transparent;border-color:transparent}
:where(#view) .antab.on::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--v4-accent)}
:where(#view) .antab-note{margin-left:auto;color:var(--v4-muted)}

/* Filters bar (legacy + detection log) */
:where(#view > :not(.mh-app)) .filters{background:var(--v4-surface);border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);box-shadow:var(--v4-shadow-1)}

/* Camera tiles (Live Cameras) */
.camtile{border-radius:var(--v4-r-lg);border-color:var(--v4-line);background:var(--v4-surface);box-shadow:var(--v4-shadow-1)}
.camvid{background:#0b1211}

/* Workplace Insights: the performance table only ever prints "—" for score / attendance / trend in
   live mode (employeePerfTable). The shell tags the table when every such cell is empty and these
   three columns are hidden then; any real value brings them back. */
.eptbl.v4-noscore th:nth-child(4),.eptbl.v4-noscore td:nth-child(4),
.eptbl.v4-noscore th:nth-child(5),.eptbl.v4-noscore td:nth-child(5),
.eptbl.v4-noscore th:nth-child(6),.eptbl.v4-noscore td:nth-child(6){display:none}

/* Person drawer panel (ui-v3 3-tab profile; its internals follow the bridged tokens). */
html .pdrawer,
html .pdrawer.pp3{width:min(480px,100vw);max-width:100vw;background:var(--v4-surface);border-left:1px solid var(--v4-line);box-shadow:var(--v4-shadow-3);color:var(--v4-ink)}

/* Modals (enrolment queue, galleries, evidence) */
.modal{background:var(--v4-scrim);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}
.modalbox{background:var(--v4-surface);color:var(--v4-ink);border:1px solid var(--v4-line);border-radius:var(--v4-r-lg);box-shadow:var(--v4-shadow-3)}
.modalhead{border-bottom:1px solid var(--v4-line)}
.modalhead b{font:600 var(--v4-fs-lg)/1.3 var(--v4-font)}
.evicon{border-radius:var(--v4-r-lg);background:var(--v4-accent-soft);color:var(--v4-accent)}
.callout{border-radius:var(--v4-r-lg);background:var(--v4-surface-2);border-color:var(--v4-line)}
/* Enrolment wizard / galleries / queue internals, Detection Log, Advanced Search, maps and the
   Movement Tracker host are styled by ui-v4-modules.css (Agent 4, loaded last) — no deep selectors here. */

/* Settings drawer / modal (ui-v3 setDrawer / setModal) */
.setdrawer,.setmodal{background:var(--v4-surface);color:var(--v4-ink);border-color:var(--v4-line);box-shadow:var(--v4-shadow-3)}
.setmodal{border-radius:var(--v4-r-lg)}
.setdhead{border-bottom-color:var(--v4-line)}
.setdhead h3{font:600 var(--v4-fs-title)/1.3 var(--v4-font)}
.setdfoot{border-top-color:var(--v4-line)}
.setdrawerbg{background:var(--v4-scrim)}

/* Empty text */
.v3 .empty{color:var(--v4-muted);font-size:var(--v4-fs-base)}

/* Photo slots (avSlot / .wsav, person .av fallback, detection thumb placeholder): same approved glyph,
   neutral tint instead of the emoji's purple — one treatment for every no-photo slot. */
.wsav{background:var(--v4-surface-2);border-radius:var(--v4-r)}
.wsav-ph,
.person .av:not(.hasimg)::after,.v3 .person .av:not(.hasimg)::after,.pdav .av:not(.hasimg)::after,
div[title="Photo loading…"]{filter:grayscale(1)!important;opacity:.5}
/* …and the slot behind that glyph follows the theme (the detection thumb wrapper paints a light box). */
/* background-COLOR only: the crop may be painted as this wrapper's background-image and must survive. */
/* WEB-A1 (perf): explicit class instead of app-wide `:has(> [title="Photo loading…"])`. The old
   :has selector forced the engine to re-test every mutated subtree under .v3/#view/#mobileShellRoot
   on every table poll — the multi-second main-thread freeze. detThumb/pdthumb wrappers carry these
   classes directly, so this is a flat, cheap rule. */
.dthumb,.pdthumb{background-color:var(--v4-surface-2);border-radius:var(--v4-r)}

/* ---------------------------------------------------------------------------------------------
   10. MOBILE SHELL (<900px, app.js mobile shell) + the desktop pages it hosts.
   --------------------------------------------------------------------------------------------- */
#mobileShellRoot.active{background:var(--v4-bg)}
.mscreen{background:var(--v4-bg)}
.mappbar{background:var(--v4-glass);border-bottom:1px solid var(--v4-line)}
.mappbar .mbrand{font-family:var(--v4-font);font-weight:600}
.mbotnav{background:var(--v4-glass);border-top:1px solid var(--v4-line)}
.mnav{color:var(--v4-ink-3)}
.mnav span{font:500 var(--v4-fs-2xs)/1.2 var(--v4-font)}
.mnav.on{color:var(--v4-accent)}
.mnav-ind{background:var(--v4-accent)}
.msheet{background:var(--v4-surface);border-radius:14px 14px 0 0;max-height:88dvh;overflow-y:auto;overscroll-behavior:contain}
.moptg{grid-template-columns:repeat(3,minmax(0,1fr))}
.mopt{border-radius:var(--v4-r-lg);background:var(--v4-surface-2);border:1px solid var(--v4-line);padding:12px 6px}
.mopt .moic{background:var(--v4-surface);color:var(--v4-accent)}
.mopt .mol{font:500 var(--v4-fs-meta)/1.25 var(--v4-font);color:var(--v4-ink)}
.mkpi,.mcard{border-radius:var(--v4-r-lg);border-color:var(--v4-line);background:var(--v4-surface);box-shadow:var(--v4-shadow-1)}
.mkpi .mkv{font-family:var(--v4-font);font-weight:600}
.v4-msec{min-width:0;max-width:100%}
.v4-msec .v3 .pagehead{margin-bottom:10px}
.v4-msec .tablewrap,.v4-msec .v4-tablewrap{max-width:100%}
.v4-msec .v4-kpis,.v4-msec .v4-kpi6{grid-template-columns:repeat(2,minmax(0,1fr))}
/* hosted .v4-grid keeps its 12 tracks: at phone width the span system gives every item 12 of 12 */
@media (max-width:360px){ .moptg{grid-template-columns:repeat(2,minmax(0,1fr))} }

/* ---------------------------------------------------------------------------------------------
   10b. POLISH PASS (in place — nothing moves). Tokens only.
   --------------------------------------------------------------------------------------------- */
/* Scrollbars: thin, theme-true, everywhere except the frozen Tracker's own scroller styling. */
html{scrollbar-width:thin;scrollbar-color:var(--v4-line-strong) transparent}
*:not(.mh-app *)::-webkit-scrollbar{width:10px;height:10px}
*:not(.mh-app *)::-webkit-scrollbar-thumb{background:var(--v4-line-strong);border-radius:var(--v4-r-pill);border:3px solid transparent;background-clip:padding-box}
*:not(.mh-app *)::-webkit-scrollbar-thumb:hover{background:var(--v4-ink-3);background-clip:padding-box;border:3px solid transparent}
*:not(.mh-app *)::-webkit-scrollbar-track{background:transparent}

/* Equal card heights inside a row; cards never collapse below their header. */
.v3 .grid{align-items:stretch}
.v3 .grid > .card,.v4-grid > .v4-card{height:100%}
.v3 .card{padding:var(--v4-card-pad)}
.v3 .card .head{margin-bottom:var(--v4-space-3);gap:var(--v4-space-3)}

/* Heading hierarchy */
.v3 .pagehead h2,.v4-head h2{font:var(--v4-h2);letter-spacing:-.01em}
.v3 .card .head h3,.v4-card-h h3{font:var(--v4-h3);letter-spacing:-.01em}
.v3 h4:not(.mh-app *){font:var(--v4-h4);letter-spacing:.06em;text-transform:uppercase;color:var(--v4-muted)}

/* One control height + icon size for every button, select and input in ported pages. */
.v3 .btn,:where(#view > :not(.mh-app)) .btn{min-height:var(--v4-h);padding:0 var(--v4-space-3);font-size:var(--v4-fs-base);gap:var(--v4-space-2)}
.v3 .btn svg,:where(#view > :not(.mh-app)) .btn svg{width:var(--v4-ic);height:var(--v4-ic)}
.v3 select,.v3 .select,
.v3 input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]),
:where(#view > :not(.mh-app)) select{min-height:var(--v4-h);font-size:var(--v4-fs-base)}
.v3 .search{min-height:var(--v4-h)}
.v3 .iconbtn,:where(#view > :not(.mh-app)) .iconbtn{width:var(--v4-h);height:var(--v4-h);border-radius:var(--v4-r);border:var(--v4-bw) solid var(--v4-line);
  background:var(--v4-surface);color:var(--v4-ink-2);transition:background-color var(--v4-dur-fast) var(--v4-ease),border-color var(--v4-dur-fast) var(--v4-ease),color var(--v4-dur-fast) var(--v4-ease)}
.v3 .iconbtn:hover,:where(#view > :not(.mh-app)) .iconbtn:hover{background:var(--v4-surface-2);border-color:var(--v4-line-strong);color:var(--v4-ink)}
.v3 .iconbtn svg{width:var(--v4-ic);height:var(--v4-ic)}

/* Tables: one row rhythm, one cell padding, right-aligned numerics stay mono. */
.v3 tbody td,:where(#view > :not(.mh-app)) tbody td{padding:var(--v4-cell-y) var(--v4-cell-x);height:var(--v4-row-h);vertical-align:middle}
.v3 thead th,:where(#view > :not(.mh-app)) thead th{padding:var(--v4-cell-y) var(--v4-cell-x);height:var(--v4-row-h-compact);white-space:nowrap}
.v3 tbody tr:last-child td{border-bottom:0}
.v3 tbody tr.on td,.v3 tbody tr[aria-selected="true"] td,.v4-table tbody tr.on td{background:var(--v4-selected)}

/* States: focus (keyboard only), selected, disabled — identical everywhere. */
:where(#view,.side,.top,.modal,.setdrawer,.setmodal,.pdrawer) :is(button,a,select,input,textarea,[tabindex]):focus-visible:not(.mh-app *){
  outline:var(--v4-bw-focus) solid var(--v4-accent);outline-offset:2px;box-shadow:none}
:where(#view,.modal,.setdrawer,.setmodal) :is(button,.btn,select,input)[disabled]:not(.mh-app *),
:where(#view,.modal,.setdrawer,.setmodal) .btn.disabled{opacity:.45;cursor:not-allowed;box-shadow:none;transform:none}
.v3 .setnavb{border-radius:var(--v4-r);font-size:var(--v4-fs-base);min-height:var(--v4-h)}
.v3 .setnavb.on{background:var(--v4-accent-soft);color:var(--v4-accent);font-weight:var(--v4-fw-semi);box-shadow:inset 0 -2px 0 var(--v4-accent)}

/* Status pills: one height, one radius, one weight. */
.v3 .pill,.pill.ok,.pill.warn,.pill.bad,.tag.ok,.tag.warn,.tag.bad,.tag.info{min-height:20px;display:inline-flex;align-items:center;gap:var(--v4-space-1)}

/* Table text never clips mid-word: labels wrap on word boundaries; a cell that is clipped by design
   ends with an ellipsis (the shell adds the full text as a title tooltip). */
.v3 tbody td{text-overflow:ellipsis;overflow-wrap:normal;word-break:normal}
.v3 .altype,:where(#view) .altype{white-space:normal;align-items:flex-start;min-width:0;max-width:100%;line-height:var(--v4-lh-tight)}
.v3 .altype svg,:where(#view) .altype svg{margin-top:1px}

/* Type pill inside fixed-width table columns: compact variant so "Employee" never clips. */
:is(.v3,#view) td .astag.ok,:is(.v3,#view) td .astag.warn,:is(.v3,#view) td .v4-type{padding:1px var(--v4-space-1) 1px 3px;gap:3px;font-size:var(--v4-fs-2xs);letter-spacing:-.01em}
:is(.v3,#view) td .astag.ok::before,:is(.v3,#view) td .astag.warn::before{width:11px;height:11px}
:is(.v3,#view) td:has(> .astag),:is(.v3,#view) td:has(> .v4-type){text-overflow:clip;overflow:visible}

/* VQ P1 — accent-FILLED controls use the accent-ink token (dark: #0B1413 on #4CC2B4 = 9.9:1; light: white on
   #0E6B62 = 6.4:1). Covers every primary button family and the inline-styled Live Cameras grid button. */
.btn.primary,.v4-btn.primary,.btn.pri,.v3 .btn.primary,:where(#view > :not(.mh-app)) .btn.primary,
.modal .btn.primary,.setdrawer .btn.primary,.setmodal .btn.primary,
.btn.primary:hover,.v4-btn.primary:hover,.v3 .btn.primary:hover{color:var(--v4-accent-ink)!important}
.btn.primary svg,.v4-btn.primary svg{color:var(--v4-accent-ink)}
[data-grid][style*="background"]{color:var(--v4-accent-ink)!important;background:var(--v4-accent)!important;border-color:var(--v4-accent)!important}
/* C2a's primary button (ui-v4-pages.css .v4p-btn--primary hard-codes #fff text on the brand fill). */
.v4p-btn--primary,.v4p-btn--primary:hover{color:var(--v4-accent-ink)!important}
.v4p-btn--primary svg{color:var(--v4-accent-ink)}
/* Current page in the ported pagers (Alerts & Review, Employees, Attendance): accent fill + accent-ink. */
.v3 .pg.on,.pg.on{background:var(--v4-accent)!important;border-color:var(--v4-accent)!important;color:var(--v4-accent-ink)!important}

/* VQ P1 — mobile site-health detail line: ≥11px, secondary-ink contrast. */
.hs-panel .hs-detail{font-size:var(--v4-fs-xs)!important;color:var(--v4-ink-2)!important;line-height:1.4}

/* Drawers / modals spacing */
.setdhead,.setdbody,.setdfoot{padding-left:var(--v4-drawer-pad);padding-right:var(--v4-drawer-pad)}
.setdfoot{gap:var(--v4-space-2)}
.modalhead{padding:var(--v4-space-3) var(--v4-modal-pad)}
.modalbody{padding:var(--v4-modal-pad)}

/* Chart framing */
.v3 svg.chart,.v4-chart{padding:var(--v4-chart-pad);overflow:visible}

/* ---------------------------------------------------------------------------------------------
   11. REDUCED MOTION — every animation / transition above is off.
   --------------------------------------------------------------------------------------------- */
@media (prefers-reduced-motion:reduce){
  #view.v4-enter > *,#view.v4-enter .v4-bar > i,#view.v4-enter .v4-bar > span,#view.v4-enter .v4-vbars > i,
  #view.v4-enter .v4-chart,#view.v4-enter svg.chart,#nav .v4-navgrp.v4-anim > .v4-navitems,.v4-pane,.v4-modal-box,
  .v4-live-dot,.v4-live-sheen::after,.v4-skel,.v4-ripple,.top .live .dot.ok,.side .sidefoot .ping .dot.ok{animation:none!important}
  .v4-card,.v4-kpi,.v4-btn,.v4-row.click,.v4-drawer,.v4-scrim,.v4-toast,#nav .nav,#nav .v4-navhead,.top .topbtn,.top .iconbtn,
  .v3 .btn,.v4-tabs button::after,.v4-chips button,.v4-seg button{transition:none!important}
  .v4-card:hover,.v4-kpi:hover,.v4-btn:hover,.v4-row.click:hover,#nav .nav:hover,#nav .v4-navhead:hover,.v3 .btn:hover,.top .topbtn:hover,.top .iconbtn:hover{transform:none!important}
  .v4-ripple{display:none}
}

/* P2-012 TRUNCATION: key table text wraps instead of ending in an ellipsis (styles.css .logstd/.astable/.altable,
   ui-v3.css #wfTable person column, ui-v4 .v3 tbody td). Photo, number and time cells stay on one line. Font sizes
   are unchanged. At narrow widths the wide tables keep a readable width and scroll sideways inside their wrapper. */
:where(#view) :is(.logstd,.astable,.altable,.v4q-table,#wfTable) tbody td,
:where(#view) :is(.logstd,.astable,.altable,.v4q-table,#wfTable) tbody td b,
:where(#view) #wfTable tbody td .person :is(.name,.meta){white-space:normal;overflow:visible;text-overflow:clip;overflow-wrap:anywhere}
:where(#view) :is(.logstd,.astable,.altable,.v4q-table,#wfTable) tbody td:is(.mono,.v4q-mono,.v4q-nowrap,.selcol,.attnum,:has(img,.ithumb,.asthumb,.noimg,.wsav,.v4q-facebtn)){white-space:nowrap;overflow-wrap:normal}
@media (max-width:900px){
  :where(#view) :is(.logstd table,table.astable,table.altable,table.v4q-table--alerts,table.v4q-table--zones,table.v4q-table--cams,#wfTable){min-width:720px}
}
