/* ==========================================================================
   Inter, self-hosted.

   The stack used to lead with the platform UI face, which meant the product
   looked different on every operating system and, on Windows, looked like
   Windows. For a tool people have open beside Linear, Jira and Notion all day,
   that reads as "internal script" rather than "product".

   Inter is the face those tools use, and it is licensed (SIL OFL) to
   redistribute. Bundling it rather than linking it keeps the app offline-first
   and satisfies the CSP, which allows font-src 'self' and nothing else.

   A system stack still follows it, so a failed font load degrades to something
   sensible instead of Times New Roman.
   ========================================================================== */
/* Inter variable, latin subset — the enterprise UI face. One file, weights
   100-900. It is the typeface of Linear, GitHub and Figma: neutral, dense,
   engineered for screens. SIL OFL, bundled, offline-first. Hierarchy comes
   from weight and tracking, not from a second decorative family — that
   restraint IS the enterprise look. */
@font-face {
  font-family: "Inter";
  src: url("fonts/Inter-Var.woff2") format("woff2");
  font-weight: 100 900; font-style: normal; font-display: swap;
}

/* ==========================================================================
   PulseIQ — instrument panel
   Palette: deep navy ground, signal-green for live state, amber paused,
   coral risk, indigo focus. Neutrals carry a blue bias so they read as
   chosen rather than defaulted. Data is set in a mono face throughout —
   the app is an instrument, and instruments use monospaced numerals.
   ========================================================================== */

:root {
  /* Meridian, dark. The navy bias is gone: neutrals are charcoal with a faint
     blue cast, the live accent is teal rather than green, and focus is a
     cooler cobalt. The old names stay — every view speaks them. */
  /* Aurora, dark: violet-tinted charcoal neutrals, electric violet as the
     action colour, emerald kept strictly for live/success. Token names are
     the contract; the values are the theme. */
  /* Ion, dark: obsidian-blue ground, electric azure as the action colour,
     cyan as its companion, emerald kept strictly for live/success. Token
     names are the contract; the values are the theme. */
  --ground:        #070B12;
  --surface:       #0E141F;
  --surface-2:     #151D2B;
  --surface-3:     #1E2938;
  --line:          #33415A;
  --line-soft:     #1B2534;

  --ink:           #EDF2FA;
  --ink-2:         #B7C3D6;
  --ink-3:         #8DA0B9;

  --signal:        #34D399;
  --signal-dim:    #10B981;
  --signal-ghost:  rgba(52, 211, 153, 0.12);

  --amber:         #FBBF57;
  --amber-ghost:   rgba(251, 191, 87, 0.13);
  --coral:         #F87168;
  --coral-ghost:   rgba(248, 113, 104, 0.12);
  --indigo:        #5BB2FF;
  --indigo-ghost:  rgba(91, 178, 255, 0.14);
  --violet:        #4DDCEC;
  /* Text that sits ON the accent — dark here, white in light mode, so a
     primary button never guesses at its own contrast. */
  --accent-contrast: #0A1B2E;   /* deep blue-ink for text on the light-azure action colour */

  /* ---------------------------------------------------------------- type
     Three roles, three faces, all resident on the machine — the agent is
     offline-first and the CSP blocks external font hosts, so a webfont would
     be a silent fallback waiting to happen.

     Bahnschrift is a DIN derivative: the lettering of gauges, dial faces and
     engineering drawings. It carries the display and every numeral, which is
     what makes this read as an instrument rather than a dashboard template.
     Segoe UI Variable brings genuine optical sizing — Display for headings,
     Text for prose, Small for micro-labels — and Cascadia Mono sets data
     without the code ligatures that would mangle a numeric column. */
  /* The portal is opened in a browser on whatever machine someone has, so the
     stack leads with the platform's own UI face — SF on macOS, Segoe on
     Windows, the distribution's default on Linux — rather than naming a
     Windows font first and letting everyone else fall through to whatever.

     Bahnschrift is kept for figures because its character is in the WIDTH
     axis, which is what makes a number read like a gauge face. Where it is
     absent the numerals simply set in the UI face; nothing breaks. */
  /* Display — headings, page titles, the big figures.

     Aptos Display is drawn for exactly this: larger sizes where its tighter
     apertures and shorter extenders keep a heading compact without looking
     condensed. Aptos follows for machines that have the family but not the
     display cut. Then the two faces asked for as substitutes, then bundled
     Inter as the guaranteed floor — see the note on licensing below. */
  --display: "Segoe UI Variable Display", "Segoe UI", "Inter", "Helvetica Neue",
             ui-sans-serif, system-ui, -apple-system, Arial, sans-serif;
  /* Body — everything that is read rather than scanned.

     Aptos text cut, not the display cut: display faces set at 15px look thin
     and their tight spacing hurts reading. This is the distinction the two
     names exist for, and using one for both would waste it.

     Licensing note: Aptos ships with Microsoft 365 and is proprietary, so it
     is referenced and never bundled. Inter is SIL OFL, which is why it can be
     shipped with the app — it is the reason a machine with none of the first
     four still gets a real typeface rather than Arial. */
  --sans:    "Segoe UI Variable Text", "Segoe UI", "Inter", "Helvetica Neue",
             ui-sans-serif, system-ui, -apple-system, Roboto, Arial, sans-serif;
  --sans-sm: "Segoe UI Variable Small", "Segoe UI", "Inter", "Helvetica Neue",
             ui-sans-serif, system-ui, -apple-system, Roboto, Arial, sans-serif;
  --mono:    "Cascadia Mono", "Cascadia Code", "SF Mono", "Menlo", ui-monospace, "Consolas", monospace;

  /* type scale — 1.2 minor third, anchored at 13px body */
  /* Measured before changing: 63% of on-screen text sat under 14px, and some
     of it at 9px — the sidebar section headers and the chart hour labels were
     genuinely too small to read. The whole scale moves up, and --t-xs is the
     floor: nothing in the product may be smaller than it.

     The step ratio is roughly 1.16, which keeps the density this kind of data
     screen needs while putting body copy at a size people can actually read. */
  /* Two numbers drive the whole interface.

     I could not see the screen while tuning this — no screenshots — and
     guessing at "bigger" from a distance is how a type scale ends up wrong
     twice. So the scale is derived rather than fixed, and the person using it
     sets the multiplier. Appearance → Text size writes --ui-scale; density
     writes --sp-scale. Everything else follows. */
  --ui-scale: 1;
  --sp-scale: 1;

  --t-xs:  calc(12.5px * var(--ui-scale));   /* floor — labels, badges  */
  --t-sm:  calc(14px   * var(--ui-scale));   /* secondary copy          */
  --t-md:  calc(16px   * var(--ui-scale));   /* body — held readable    */
  --t-lg:  calc(18px   * var(--ui-scale));   /* card titles             */
  --t-xl:  calc(24px   * var(--ui-scale));   /* page titles             */
  --t-2xl: calc(30px   * var(--ui-scale));   /* stat figures            */
  --t-3xl: calc(44px   * var(--ui-scale));   /* the clock               */

  /* motion — one spring, one ease, used everywhere */
  /* Motion.

     Durations were 300-500ms with a springy curve. That is presentation
     timing, not tool timing: on a screen someone opens forty times a day, an
     animation you have time to watch is an animation that is in the way.

     Enterprise motion is fast, decelerating, and never overshoots — the
     overshoot curve (--spring-out) is kept only for things that appear once,
     like a toast, where a little life is welcome.

     One duration token per role, so the whole app can be slowed down or sped
     up from three numbers. */
  --t-fast:   120ms;   /* hover, focus, colour — must feel instant       */
  --t-base:   180ms;   /* the default: entrances, expansions             */
  --t-slow:   260ms;   /* larger movements, panels sliding               */

  --spring: cubic-bezier(.22, .9, .28, 1);
  --spring-out: cubic-bezier(.34, 1.32, .48, 1);
  /* Decelerate: quick to leave, gentle to arrive. */
  --ease: cubic-bezier(.2, 0, 0, 1);
  --ease-out: cubic-bezier(0, 0, .2, 1);

  --r-sm: 3px;
  --r: 4px;
  --r-lg: 6px;

  --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px -8px rgba(0,0,0,.5);
  /* Trimmed: the sidebar and rail together were taking 41% of a 1440px
     screen, and the content is the point. */
  --sidebar-w: 226px;
}

:root[data-theme="light"] {
  /* Meridian, light: warm paper ground, pure white surfaces. The teal keeps
     4.5:1 on white; --ink-3 keeps it on every surface, same discipline as the
     value it replaces (the old #5F7087 measured 4.13:1 and was rejected). */
  /* Aurora, light: near-white cool ground with a violet-grey bias; soft
     shadow over hard border. Every ink keeps AA on every surface. */
  /* Fluent, light: Microsoft's neutral ramp with communication blue #0078D4.
     True grays (no blue cast), whisper-thin dividers, every ink AA. */
  --ground:        #F3F2F1;
  --surface:       #FFFFFF;
  --surface-2:     #FAF9F8;
  --surface-3:     #F3F2F1;
  --line:          #C8C6C4;
  --line-soft:     #EDEBE9;
  --ink:           #201F1E;
  --ink-2:         #484644;
  --ink-3:         #605E5C;
  --signal:        #0B6A0B;
  --signal-dim:    #094509;
  --signal-ghost:  rgba(16, 124, 16, 0.09);
  --amber:         #8A6116;
  --amber-ghost:   rgba(138, 97, 22, 0.11);
  --coral:         #C50F1F;
  --coral-ghost:   rgba(197, 15, 31, 0.08);
  --indigo:        #0078D4;
  --indigo-ghost:  rgba(0, 120, 212, 0.10);
  --violet:        #038387;
  --accent-contrast: #FFFFFF;
  --shadow: 0 1px 2px rgba(20,23,28,.05), 0 8px 24px -10px rgba(20,23,28,.14);
}

* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--indigo); outline-offset: 2px; border-radius: 4px; }
::selection { background: var(--signal-ghost); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 8px; border: 2px solid var(--ground); }
::-webkit-scrollbar-thumb:hover { background: var(--line); }
::-webkit-scrollbar-track { background: transparent; }

.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.num  { font-family: var(--mono); font-variant-numeric: tabular-nums; letter-spacing: -0.02em; }

/* ---------------------------------------------------------------- shell */
#app { display: flex; height: 100vh; }

.sidebar {
  /* The rail is dark in both themes. Every component inside it — nav items,
     the state chip, the user chip — styles itself from these tokens, so one
     local override re-skins the whole column without touching their CSS. */
  --surface:   #201F1E;
  --surface-2: #292827;
  --surface-3: #323130;
  --line:      #3B3A39;
  --line-soft: #292827;
  --ink:       #F3F2F1;
  --ink-2:     #C8C6C4;
  --ink-3:     #A19F9D;

  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--surface);
  /* Children inherit body's COMPUTED color, not the var — without this line
     every un-coloured label in the rail keeps the light theme's dark ink and
     vanishes against the dark background. */
  color: var(--ink);
  border-right: 1px solid var(--line-soft);
  display: flex; flex-direction: column;
  transition: width var(--t-base) var(--ease), flex-basis var(--t-base) var(--ease);
}

/* Collapsed to an icon rail — toggled from the topbar, remembered per user.
   The same rules the 900px breakpoint applies, available at any width. */
body.nav-collapsed .sidebar { --sidebar-w: 64px; }
body.nav-collapsed .sidebar .brand > div,
body.nav-collapsed .nav-item > span,
body.nav-collapsed .user-chip > div:not(.avatar),
body.nav-collapsed .state-label,
body.nav-collapsed .state-time,
body.nav-collapsed .nav-item .badge,
body.nav-collapsed #sync-line { display: none; }
body.nav-collapsed .nav-item { justify-content: center; }
body.nav-collapsed .nav-divider {
  font-size: 0; padding: var(--s-2) 0; margin: var(--s-1) var(--s-2);
  border-top: 1px solid var(--line-soft);
}
body.nav-collapsed .state-chip { justify-content: center; padding: var(--s-2); }
body.nav-collapsed .user-chip { justify-content: center; }

.brand {
  display: flex; align-items: center; gap: var(--s-2h);
  padding: var(--s-4) var(--s-4) var(--s-3);
  -webkit-app-region: drag;
}
.brand svg { flex: none; }
.brand-name { font-weight: 620; letter-spacing: -0.01em; font-size: 15px; }
.brand-sub { font-size: var(--t-xs); color: var(--ink-3); margin-top: -2px; }

/* live state chip — the traffic light, mirrored from the tray */
.state-chip {
  margin: var(--s-1) var(--s-3) var(--s-3); padding: var(--s-2h) var(--s-3);
  background: var(--surface-2); border: 1px solid var(--line-soft);
  border-radius: var(--r); display: flex; align-items: center; gap: var(--s-2h);
  cursor: pointer; transition: border-color var(--t-fast);
}
.state-chip:hover { border-color: var(--line); }
.state-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; background: var(--ink-3); }
.state-dot.tracking { background: var(--signal); box-shadow: 0 0 0 3px var(--signal-ghost); animation: breathe 2var(--t-base) ease-in-out infinite; }
.state-dot.paused   { background: var(--amber);  box-shadow: 0 0 0 3px var(--amber-ghost); }
.state-dot.offline  { background: var(--coral);  box-shadow: 0 0 0 3px var(--coral-ghost); }
.state-dot.focus    { background: var(--indigo); box-shadow: 0 0 0 3px var(--indigo-ghost); animation: breathe 3s ease-in-out infinite; }
@keyframes breathe { 0%,100% { opacity: 1; } 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) { .state-dot { animation: none !important; } }

.state-label { font-size: 12px; font-weight: 560; }
.state-time { margin-left: auto; font-size: 12px; color: var(--ink-2); }

nav { flex: 1; overflow-y: auto; padding: 0 var(--s-2) var(--s-2); }
.nav-divider {
  font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-3); padding: var(--s-4) var(--s-2h) var(--s-1h); font-weight: 600;
}
.nav-item {
  display: flex; align-items: center; gap: var(--s-2h);
  min-width: 0;
  padding: var(--s-2) var(--s-2h); border-radius: var(--r-sm);
  color: var(--ink-2); cursor: pointer; user-select: none;
  font-size: 13px; font-weight: 500; border: none; background: none;
  width: 100%; text-align: left; transition: background var(--t-fast), color var(--t-fast);
}
.nav-item:hover { background: var(--surface-2); color: var(--ink); }
.nav-item.active {
  background: rgba(255, 255, 255, .08);
  color: var(--ink); font-weight: 600;
  box-shadow: inset 3px 0 0 var(--indigo);
}
.nav-item.active svg { color: var(--indigo); }
.nav-item svg { flex: none; color: var(--ink-3); }
.nav-item > span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.nav-item .badge { margin-left: auto; }
.nav-sub { padding-left: var(--s-4h); }

.sidebar-foot { padding: var(--s-2h) var(--s-3); border-top: 1px solid var(--line-soft); }
.user-chip { display: flex; align-items: center; gap: var(--s-2h); padding: var(--s-1h); border-radius: var(--r-sm); cursor: pointer; }
.user-chip:hover { background: var(--surface-2); }
.avatar {
  width: 28px; height: 28px; border-radius: 8px; flex: none;
  display: grid; place-items: center; font-size: var(--t-xs); font-weight: 680;
  background: linear-gradient(145deg, var(--indigo), var(--violet)); color: #fff;
}
.user-name { font-size: var(--t-xs); font-weight: 560; line-height: 1.25; }
.user-role { font-size: var(--t-xs); color: var(--ink-3); text-transform: capitalize; }

/* ---------------------------------------------------------------- main */
main { flex: 1; display: flex; flex-direction: column; min-width: 0; }

.topbar {
  height: 48px; flex: none; display: flex; align-items: center; gap: var(--s-2);
  padding: 0 var(--s-3h); border-bottom: 1px solid var(--line-soft);
  background: color-mix(in srgb, var(--surface) 72%, var(--ground));
  backdrop-filter: blur(8px); -webkit-app-region: drag;
}
/* Breadcrumb: where you are, always. */
.crumbs { display: flex; align-items: center; gap: var(--s-1h); min-width: 0; }
.crumb-root { font-size: var(--t-xs); color: var(--ink-3); font-weight: 600; }
.crumb-sep { display: inline-flex; color: var(--ink-3); opacity: .6; }
.crumb-here { font-size: var(--t-xs); font-weight: 700; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 220px; }

/* The search field look: an input, because that is what enterprise hands
   reach for — clicking it opens the command palette. */
.tb-search {
  display: flex; align-items: center; gap: var(--s-2);
  width: min(420px, 36vw); height: 32px; padding: 0 var(--s-2h);
  margin-left: var(--s-3);
  border: 1px solid transparent; border-radius: var(--r);
  background: var(--surface-3); color: var(--ink-3);
  font: inherit; font-size: var(--t-xs); cursor: text; text-align: left;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.tb-search:hover, .tb-search:focus-visible {
  border-color: var(--indigo);
  box-shadow: 0 0 0 3px var(--indigo-ghost);
}
.tb-search svg { flex: none; }
.tb-search-hint { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.tb-search kbd { flex: none; }
.tb-divider { width: 1px; height: 20px; background: var(--line-soft); margin: 0 var(--s-1); }
@media (max-width: 900px) { .tb-search-hint { display: none; } .tb-search { width: auto; } .crumbs { display: none; } }
.topbar > * { -webkit-app-region: no-drag; }
/* The page header lives in the content column now — a slim topbar cannot
   carry a real title, and a real title is what makes a screen feel owned.
   It scrolls away with the page, the way Linear and Stripe do it. */
.page-head {
  display: flex; align-items: flex-end; gap: var(--s-4);
  padding: var(--s-4) 0 var(--s-4h);
}
.page-head > div:first-child { flex: 1; min-width: 0; }
.page-head .page-title {
  font-size: calc(23px * var(--ui-scale)); font-weight: 600; letter-spacing: -.01em;
}
.page-head .page-sub {
  font-size: var(--t-sm); color: var(--ink-3); margin-top: var(--s-1);
  max-width: 78ch;
}
.topbar-spacer { flex: 1; }

.content {
  flex: 1; overflow-y: auto; padding: var(--s-4h);
  background: var(--ground);
}
/* content width lives in type.css */

/* ---------------------------------------------------------------- atoms */
.card {
  background: var(--surface); border: 1px solid var(--line-soft);
  border-radius: var(--r-lg); padding: var(--s-4);
  box-shadow: 0 1px 2px color-mix(in srgb, var(--ink) 4%, transparent);
}
.card.pad-0 { padding: 0; overflow: hidden; }
.card-head { display: flex; align-items: center; gap: var(--s-2h); margin-bottom: var(--s-3h); }
.card-title { font-size: 13px; font-weight: 620; letter-spacing: -.005em; }
.card-sub { font-size: var(--t-xs); color: var(--ink-3); }

.grid { display: grid; gap: var(--s-3h); }
/* Count follows the space, rather than the space being forced into a count.
   Measured at 1440: four fixed columns gave 187px cards; auto-fit gives three
   at ~250px, and four only once there is room for them. */
.g2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.g3 { grid-template-columns: repeat(auto-fit, minmax(265px, 1fr)); }
.g4 { grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }
/* The 1080px and 760px breakpoints these grids used lived on no scale and
   collided with the 900/640 ones in system.css, which won on specificity and
   made the 760 rule dead. Both now sit on the shared scale — see system.css. */

.row { display: flex; align-items: center; gap: var(--s-2h); }
.col { display: flex; flex-direction: column; gap: var(--s-2h); }
.spacer { flex: 1; }
.muted { color: var(--ink-3); }
.dim { color: var(--ink-2); }
.small { font-size: 12px; }
/* The smallest text the product is allowed to set. It was 11px. */
.tiny { font-size: var(--t-xs); }

.btn {
  display: inline-flex; align-items: center; gap: var(--s-2); justify-content: center;
  padding: var(--s-2) var(--s-3h); border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--line);
  color: var(--ink); font-size: var(--t-xs); font-weight: 560; cursor: pointer;
  transition: background var(--t-fast), border-color var(--t-fast), transform .06s;
}
.btn:hover { background: var(--surface-3); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary {
  /* The second stop leans toward the theme's surface, so in dark mode the
     button stays light-violet under dark text (AA), and in light mode it
     deepens under white text (AA). One rule, both themes honest. */
  background: var(--indigo);
  border-color: transparent; color: var(--accent-contrast); font-weight: 600;
  box-shadow: 0 1px 2px rgba(10, 20, 40, .12);
}
.btn-primary:hover { background: color-mix(in srgb, var(--indigo) 88%, var(--ink)); }
.btn-danger { background: transparent; border-color: var(--coral); color: var(--coral); }
.btn-danger:hover { background: var(--coral-ghost); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--ink-2); }
.btn-ghost:hover { background: var(--surface-2); color: var(--ink); }
.btn-sm { padding: var(--s-1) var(--s-2h); font-size: var(--t-xs); }
.btn-icon { padding: var(--s-1h); }

.badge {
  display: inline-flex; align-items: center; gap: var(--s-1h);
  padding: var(--s-0) var(--s-2); border-radius: 100px; font-size: var(--t-xs); font-weight: 620;
  letter-spacing: .01em; background: var(--surface-3); color: var(--ink-2);
  border: 1px solid transparent; white-space: nowrap;
}
.badge.green  { background: var(--signal-ghost); color: var(--signal); }
.badge.amber  { background: var(--amber-ghost);  color: var(--amber); }
.badge.coral  { background: var(--coral-ghost);  color: var(--coral); }
.badge.indigo { background: var(--indigo-ghost); color: var(--indigo); }

.pill-p0 { background: var(--coral-ghost); color: var(--coral); }
.pill-p1 { background: var(--amber-ghost); color: var(--amber); }
.pill-p2 { background: var(--surface-3);   color: var(--ink-2); }
.pill-p3 { background: var(--surface-3);   color: var(--ink-3); }

/* severity stripe — state readable at a glance, not only as a number */
.stripe { border-left: 3px solid var(--line); padding-left: var(--s-3); }
.stripe.high { border-left-color: var(--coral); }
.stripe.warn { border-left-color: var(--amber); }
.stripe.info { border-left-color: var(--indigo); }
.stripe.good { border-left-color: var(--signal); }

/* ---------------------------------------------------------------- stat */
.stat { display: flex; flex-direction: column; gap: var(--s-1); }
.stat-label { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .07em; color: var(--ink-3); font-weight: 620; }
.stat-value { font-family: var(--mono); font-size: 27px; font-weight: 600; letter-spacing: -.03em; line-height: 1.1; }
.stat-meta { font-size: var(--t-xs); color: var(--ink-3); }
.stat-value.green { color: var(--signal); }
.stat-value.amber { color: var(--amber); }
.stat-value.coral { color: var(--coral); }

/* ---------------------------------------------------------------- table */
table { width: 100%; border-collapse: collapse; }
.table-wrap { overflow-x: auto; }
th {
  text-align: left; font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .07em;
  color: var(--ink-3); font-weight: 620; padding: var(--s-2h) var(--s-3);
  border-bottom: 1px solid var(--line-soft); white-space: nowrap;
  position: sticky; top: 0; background: var(--surface-2); z-index: 1;
}
td { padding: var(--s-2h) var(--s-3); border-bottom: 1px solid var(--line-soft); font-size: 13px; vertical-align: middle; }
tbody tr { transition: background .1s; }
tbody tr:hover { background: var(--surface-2); }
tbody tr:last-child td { border-bottom: none; }
td.num, th.num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }

/* Row ergonomics: hover marks the row under the cursor, headers sit on a
   quiet band, and dense numeric columns stay tabular. */
tbody tr:hover > td { background: color-mix(in srgb, var(--indigo-ghost) 45%, transparent); }
tbody tr.sec-row:hover > td, tr.pd-group:hover > td { background: transparent; }
thead th { font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .05em;
  color: var(--ink-3); font-weight: 640; }

/* Table toolbar: search + filter chips above any large sheet. */
.tbl-toolbar { display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  margin-bottom: var(--s-2h); }
.tbl-filter { display: flex; align-items: center; gap: var(--s-1h);
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface);
  padding: 0 var(--s-2); height: 32px; min-width: 210px; }
.tbl-filter input { border: none; outline: none; background: transparent; font: inherit;
  font-size: var(--t-xs); color: var(--ink); flex: 1; min-width: 0; }
.tbl-filter:focus-within { border-color: var(--indigo); box-shadow: 0 0 0 3px var(--indigo-ghost); }
.chip-row { display: flex; gap: var(--s-1); flex-wrap: wrap; }
.f-chip { border: 1px solid var(--line); background: var(--surface); color: var(--ink-2);
  font: inherit; font-size: var(--t-xs); font-weight: 600; border-radius: 99px;
  padding: 4px 11px; cursor: pointer;
  transition: all var(--t-fast) var(--ease); }
.f-chip:hover { border-color: var(--indigo); color: var(--ink); }
.f-chip[aria-pressed="true"] { background: var(--indigo); border-color: var(--indigo);
  color: var(--accent-contrast); }
.tbl-count { font-size: var(--t-xs); color: var(--ink-3); margin-left: auto; }

/* ---------------------------------------------------------------- forms */
.field { display: flex; flex-direction: column; gap: var(--s-1h); }
.label { font-size: var(--t-xs); font-weight: 600; color: var(--ink-2); letter-spacing: .01em; }
input[type=text], input[type=email], input[type=password], input[type=number],
input[type=date], input[type=time], select, textarea {
  background: var(--surface-2); border: 1px solid var(--line);
  border-radius: var(--r-sm); padding: var(--s-2) var(--s-2h); font-size: 13px; width: 100%;
  transition: border-color var(--t-fast), background var(--t-fast);
}
input:focus, select:focus, textarea:focus { border-color: var(--indigo); background: var(--surface); outline: none; }
textarea { resize: vertical; min-height: 72px; font-family: inherit; }
select { cursor: pointer; }

.switch { position: relative; width: 38px; height: 21px; flex: none; cursor: pointer; }
.switch input { opacity: 0; width: 0; height: 0; position: absolute; }
.switch-track {
  position: absolute; inset: 0; background: var(--surface-3);
  border-radius: 100px; transition: background var(--t-fast); border: 1px solid var(--line);
}
.switch-thumb {
  position: absolute; top: 3px; left: 3px; width: 15px; height: 15px;
  background: var(--ink-2); border-radius: 50%; transition: transform var(--t-fast), background var(--t-fast);
}
.switch input:checked ~ .switch-track { background: var(--signal-dim); border-color: var(--signal-dim); }
.switch input:checked ~ .switch-thumb { transform: translateX(17px); background: #fff; }

/* segmented control — the consent dial (E-3) */
.segmented { display: inline-flex; background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-sm); padding: var(--s-0); gap: var(--s-0); }
.segmented button {
  padding: var(--s-1) var(--s-3); border: none; background: none; border-radius: 5px;
  font-size: var(--t-xs); font-weight: 580; color: var(--ink-3); cursor: pointer; transition: all var(--t-fast);
}
.segmented button:hover { color: var(--ink); }
.segmented button.on { background: var(--surface-3); color: var(--ink); }
.segmented button.on[data-level="full"] { background: var(--signal-ghost); color: var(--signal); }
.segmented button.on[data-level="aggregate"] { background: var(--amber-ghost); color: var(--amber); }
.segmented button.on[data-level="off"] { background: var(--surface-3); color: var(--ink-2); }

/* ---------------------------------------------------------------- viz */
.bar-track { height: 7px; background: var(--surface-3); border-radius: 100px; overflow: hidden; }
.bar-fill { height: 100%; border-radius: 100px; background: var(--signal-dim); transition: width var(--t-base) cubic-bezier(.2,.8,.3,1); }
.bar-fill.amber { background: var(--amber); }
.bar-fill.coral { background: var(--coral); }
.bar-fill.indigo { background: var(--indigo); }

.spark { display: block; width: 100%; height: 40px; }
.chart { display: block; width: 100%; }

/* activity ribbon — one cell per tracked minute */
.ribbon { display: flex; gap: var(--s-0); height: 34px; align-items: flex-end; overflow: hidden; }
.ribbon i { flex: 1 1 auto; min-width: 1px; border-radius: 1px; background: var(--surface-3); transition: opacity var(--t-fast); }
.ribbon i.ide           { background: var(--signal); }
.ribbon i.terminal      { background: var(--signal-dim); }
.ribbon i.browser_docs  { background: var(--indigo); }
.ribbon i.meeting       { background: var(--violet); }
.ribbon i.chat          { background: var(--amber); }
.ribbon i.design        { background: var(--violet); }
.ribbon i.office        { background: var(--amber); }
.ribbon i.browser_other { background: var(--ink-3); }
.ribbon i.other         { background: var(--ink-3); }
.ribbon i.locked        { background: var(--surface-3); }

.legend { display: flex; flex-wrap: wrap; gap: var(--s-3); font-size: var(--t-xs); color: var(--ink-3); }
.legend span { display: inline-flex; align-items: center; gap: var(--s-1h); }
.legend i { width: 8px; height: 8px; border-radius: 2px; display: inline-block; }

/* gauge ring */
.gauge { position: relative; display: grid; place-items: center; }
.gauge-value { position: absolute; text-align: center; }

/* ---------------------------------------------------------------- kanban */
.kanban { display: grid; grid-template-columns: repeat(5, minmax(190px, 1fr)); gap: var(--s-3); align-items: start; }
.kcol { background: var(--surface-2); border-radius: var(--r); padding: var(--s-2h); min-height: 120px; border: 1px solid transparent; transition: border-color var(--t-fast), background .15s; }
.kcol.dragover { border-color: var(--signal-dim); background: var(--signal-ghost); }
.kcol-head { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-2h); padding: 0 var(--s-0); }
.kcol-title { font-size: var(--t-xs); font-weight: 640; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-2); }
.kcol-count { font-size: var(--t-xs); color: var(--ink-3); font-family: var(--mono); }
.kcard {
  background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-sm);
  padding: var(--s-2h); margin-bottom: var(--s-2); cursor: grab; transition: border-color var(--t-fast), transform .08s, box-shadow var(--t-fast);
}
.kcard:hover { border-color: var(--line); box-shadow: var(--shadow); }

/* Interactive cards answer the cursor: a 2px ion hairline ignites across the
   top and the card lifts on a soft azure glow. Decoration only — layout and
   copy never move. */
.card.lift, button.card { position: relative; overflow: hidden; }
.card.lift::before, button.card::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: var(--indigo);
  opacity: 0; transition: opacity var(--t-fast) var(--ease);
  pointer-events: none;
}
.card.lift:hover, button.card:hover {
  border-color: color-mix(in srgb, var(--indigo) 45%, var(--line));
  box-shadow: 0 8px 26px -10px color-mix(in srgb, var(--indigo) 45%, transparent);
  transform: translateY(-1px);
}
.card.lift:hover::before, button.card:hover::before { opacity: 1; }
.kcard:active { cursor: grabbing; }
.kcard.dragging { opacity: .4; }
.kcard-title { font-size: var(--t-xs); font-weight: 540; line-height: 1.35; margin-bottom: var(--s-2); }
.kcard-meta { display: flex; align-items: center; gap: var(--s-1h); flex-wrap: wrap; }

/* ---------------------------------------------------------------- modal */
/* Pop-ups are full-screen workspaces, not floating cards: every modal fills
   the viewport, its body gets the whole height, and content inside sizes in
   vh instead of fixed pixels. The dim ring is gone because there is nothing
   left to dim. */
.modal-back {
  position: fixed; inset: 0; background: var(--ground);
  display: flex; z-index: 100; padding: 0;
  animation: modal-back-in var(--t-base) var(--ease);
}
@keyframes modal-back-in { from { opacity: 0; } }
@keyframes modal-in { from { opacity: 0; transform: translateY(14px); } }
@media (prefers-reduced-motion: reduce) {
  .modal-back, .modal { animation: none; }
}
.modal {
  background: var(--surface);
  border: none;
  border-radius: 0; box-shadow: none;
  width: 100%; height: 100%; max-height: none; display: flex; flex-direction: column;
  animation: modal-in var(--t-slow) var(--ease);
}
.modal.wide { width: 100%; }
.modal-head {
  /* The head is a hero band, not a strip: deep navy with an azure bloom,
     white type, full-bleed. Local tokens re-skin whatever sits inside it —
     the same trick the rail uses. */
  --surface: #004578; --surface-2: #005A9E; --surface-3: #106EBE;
  --line: #2B88D8; --line-soft: #005A9E;
  --ink: #FFFFFF; --ink-2: #DEECF9; --ink-3: #C7E0F4;
  max-width: none; width: 100%; margin: 0;
  background: #004578;   /* Fluent communication-blue shade, flat */
  color: var(--ink);
  border-bottom: none;
  display: flex; align-items: center; gap: var(--s-2h);
  padding: var(--s-4h) max(var(--s-5), calc((100% - 1280px) / 2));
}

.modal-head .modal-title { color: #F4F8FE; }
.modal-title { font-weight: 640; }
.modal-body { flex: 1; overflow-y: auto; max-width: none; width: 100%; margin: 0;
  padding: var(--s-5) max(var(--s-4h), calc((100% - 1280px) / 2)) var(--s-4h); }
.modal-foot { max-width: none; width: 100%; margin: 0;
  border-top: 1px solid var(--line-soft); display: flex; gap: var(--s-2); justify-content: flex-end;
  padding: var(--s-3h) max(var(--s-4h), calc((100% - 1280px) / 2)); }

/* ------------------------------------------------------------- scrollbars */
::-webkit-scrollbar { width: 9px; height: 9px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--indigo) 30%, var(--surface-3));
  border-radius: 99px; border: 2px solid var(--ground);
}
::-webkit-scrollbar-thumb:hover { background: color-mix(in srgb, var(--indigo) 55%, var(--surface-3)); }

/* -------------------------------------------------- fluent density pass */
td, th { padding-top: 7px; padding-bottom: 7px; }
.card { box-shadow: 0 1.6px 3.6px rgba(0, 0, 0, .06); }
.badge { border-radius: 3px; }
kbd { border-radius: 3px; }

/* ------------------------------------------------------ motion & rhythm */
/* Every screen ENTERS: the mounted view's root fades up 10px. innerHTML
   replacement means the node is new on every navigation, so pure CSS does
   the whole job — no timers to leak, nothing to clean up. */
#view > :first-child { animation: view-in .28s var(--ease) both; }
@keyframes view-in { from { opacity: 0; transform: translateY(10px); } }

/* Charts draw themselves in rather than popping. */
svg.chart, .plot svg { animation: chart-in .5s var(--ease) both; }
@keyframes chart-in { from { opacity: 0; transform: scale(.985); } }

/* Fluent control rhythm: 32px standard, 28px small — one height everywhere. */
.btn { min-height: 32px; }
.btn-sm { min-height: 28px; }
.btn-icon { min-height: 0; }
/* Single-line control height lives in type.css (which loads last and holds
   the type scale); here we only keep the search field on the same rhythm. */

/* A dialog form is a column to read down, not a banner to read across —
   whatever the viewport, form bodies hold a sane measure. */
.modal-body .field, .modal-body .grid.g2 { max-width: 760px; }

/* Press feedback: buttons acknowledge the click. */
.btn:active:not(:disabled) { transform: scale(.97); }
.btn { transition: transform var(--t-fast) var(--ease), background var(--t-fast) var(--ease),
       border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease); }

/* Nav icons lean toward their destination on hover. */
.nav-item svg { transition: transform var(--t-fast) var(--ease); }
.nav-item:hover svg { transform: translateX(2px); }

@media (prefers-reduced-motion: reduce) {
  #view > :first-child, svg.chart, .plot svg { animation: none; }
  .btn:active:not(:disabled) { transform: none; }
  .nav-item:hover svg { transform: none; }
}

/* ---------------------------------------------------------------- toast */
.toasts { position: fixed; bottom: 18px; right: 18px; display: flex; flex-direction: column; gap: var(--s-2); z-index: 200; max-width: 380px; }
.toast {
  background: var(--surface-2); border: 1px solid var(--line);
  border-left: 3px solid var(--signal); border-radius: var(--r);
  padding: var(--s-3) var(--s-3h); box-shadow: var(--shadow); animation: slide-in var(--t-base) cubic-bezier(.2,.9,.3,1);
}
.toast.error { border-left-color: var(--coral); }
.toast.warn  { border-left-color: var(--amber); }
.toast-title { font-size: var(--t-xs); font-weight: 620; margin-bottom: var(--s-0); }
.toast-body { font-size: 12px; color: var(--ink-2); }
@keyframes slide-in { from { transform: translateX(16px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---------------------------------------------------------------- login */
.login-shell { display: grid; place-items: center; height: 100vh; width: 100%; flex: 1; background:
  radial-gradient(1100px 520px at 15% -10%, var(--signal-ghost), transparent 60%),
  radial-gradient(900px 480px at 100% 110%, var(--indigo-ghost), transparent 60%),
  var(--ground); }
.login-card { width: min(400px, 92vw); }
.login-logo { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-5); }

/* ---------------------------------------------------------------- misc */
.empty { text-align: center; padding: var(--s-7) var(--s-4h); color: var(--ink-3); }
.empty-icon { opacity: .35; margin-bottom: var(--s-2h); }
.kbd {
  font-family: var(--mono); font-size: var(--t-xs); padding: var(--s-0) var(--s-1h);
  background: var(--surface-3); border: 1px solid var(--line);
  border-bottom-width: 2px; border-radius: 4px; color: var(--ink-2);
}
.divider { height: 1px; background: var(--line-soft); margin: var(--s-3h) 0; }
.scroll-y { overflow-y: auto; }
.skeleton { background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 50%, var(--surface-2) 75%);
  background-size: 200% 100%; animation: shimmer 1.6s var(--ease) infinite; border-radius: var(--r-sm); }
@keyframes shimmer { to { background-position: -200% 0; } }
code { font-family: var(--mono); font-size: 12px; background: var(--surface-2); padding: var(--s-0) var(--s-1h); border-radius: 4px; }
pre { font-family: var(--mono); font-size: var(--t-xs); background: var(--surface-2); padding: var(--s-3); border-radius: var(--r-sm); overflow-x: auto; border: 1px solid var(--line-soft); }
a { color: var(--indigo); }
h1,h2,h3,h4 { margin: 0; font-weight: 620; letter-spacing: -.01em; text-wrap: balance; }
p { margin: 0 0 var(--s-2h); }
