/* ============================================================================
   LogRite Downtime Tracker — stylesheet
   ----------------------------------------------------------------------------
   Ported onto the LogRite design system that ops/management/static/style.css
   defines, so the tracker and the management console read as one product. The
   token names, the `.lr-*` component vocabulary, the outlined-card treatment,
   the 3px severity stripe, the rotate-90 close button and the modal system are
   all the same; only the app-specific `.dt-*` layer below is new.

   Rules this file obeys:

   1. NO external resources. No @font-face, no @import, no url(http...). The
      only url() values are inline `data:image/svg+xml` control glyphs.
   2. #E64100 is a FILL, never text. Orange text is --accent-orange-text.
   3. Cards are OUTLINED, not raised: card background == page background, with
      a 1px border and a near-invisible lift.
   4. Both themes are authored, neither is an inversion of the other. LIGHT is
      the base; `@media (prefers-color-scheme: dark)` supplies dark; and
      `:root[data-theme="light"]` / `:root[data-theme="dark"]` override the
      media query in BOTH directions so the in-page toggle always wins.
   5. The page body never scrolls sideways. Every wide thing — tables, charts,
      command strings — scrolls inside its own container.
   ========================================================================== */

/* ============================================================
   1. TOKENS — LIGHT is the base
   ============================================================ */
:root {
  color-scheme: light;

  --bg-primary:   #FFFFFF;
  --bg-secondary: #F8F9FA;
  --bg-tertiary:  #F3F4F6;
  --bg-hover:     #E5E7EB;
  --bg-active:    #D1D5DB;

  --border-primary:   #E5E7EB;
  --border-secondary: #D1D5DB;
  --border-tertiary:  #E5E7EB;
  --border-hover:     #E64100;

  --text-primary:   #111827;
  --text-secondary: #374151;
  --text-tertiary:  #6B7280;
  --text-muted:     #9CA3AF;

  --accent-orange:        #E64100;
  --accent-orange-light:  #FF8B5B;
  --accent-orange-text:   #BF3D00;   /* #E64100 as text on white is 4.10:1 — FAILS */
  --accent-orange-hover:  #B33300;
  --accent-orange-bg:     #FFF1EA;
  --accent-orange-border: #F5B79A;

  --accent-blue:   #2E90FA;
  --accent-green:  #10B981;
  --accent-red:    #EF4444;
  --accent-yellow: #F79009;
  --status-success: #17B26A;
  --status-warning: #F79009;
  --status-error:   #F04438;
  --status-info:    #2E90FA;

  --shadow-sm:    0 1px 2px 0 rgba(10,13,18,.05);
  --shadow-md:    0 4px 6px -1px rgba(0,0,0,.1);
  --shadow-lg:    0 10px 15px -3px rgba(0,0,0,.1);
  --shadow-modal: 0 25px 50px -12px rgba(0,0,0,.18);
  --shadow-menu:  0 4px 12px rgba(0,0,0,.12);

  --scrim: rgba(20,18,15,.55);
  --sheen: rgba(0,0,0,.02);

  --radius-sm:  4px;
  --radius-md:  6px;
  --radius-lg:  8px;
  --radius-xl:  12px;
  --radius-2xl: 16px;
  --radius-full: 9999px;

  --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji",
               "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --fs-micro: 10px;
  --fs-nano:  11px;
  --fs-xs:    .75rem;
  --fs-sm:    .875rem;
  --fs-base:  1rem;
  --fs-lg:    1.125rem;
  --fs-xl:    1.25rem;
  --fs-2xl:   1.5rem;
  --fs-3xl:   1.875rem;

  /* Spacing scale. New and rewritten layout uses `gap` off this scale
     rather than per-element margins, so the rhythm is one decision in
     one place instead of a margin argument at every call site.
     Identical to ops/management/static/style.css. */
  --sp-1: 4px;
  --sp-2: 6px;
  --sp-3: 10px;
  --sp-4: 14px;
  --sp-5: 16px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 48px;

  --dur-fast: 150ms;
  --dur-base: 200ms;
  --dur-slow: 300ms;
  --ease:        cubic-bezier(.4,0,.2,1);
  --ease-out:    cubic-bezier(0,0,.2,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);

  /* Severity ramp. `unset` is deliberately NOT a sixth hue: it is a dashed
     outline, so "nobody recorded a value" is told apart by SHAPE. */
  --sev-error-fg: #B91C1C; --sev-error-bd: #FECACA; --sev-error-bg: #FEF2F2;
  --sev-warn-fg:  #B45309; --sev-warn-bd:  #FDE68A; --sev-warn-bg:  #FFFBEB;
  --sev-info-fg:  #15803D; --sev-info-bd:  #BBF7D0; --sev-info-bg:  #F0FDF4;
  --sev-debug-fg: #1D4ED8; --sev-debug-bd: #BFDBFE; --sev-debug-bg: #EFF6FF;
  --sev-trace-fg: #0E7490; --sev-trace-bd: #A5F3FC; --sev-trace-bg: #ECFEFF;
  --sev-none-fg:  #6B7280; --sev-none-bd:  #D1D5DB; --sev-none-bg:  transparent;
  --sev-violet-fg:#6D28D9; --sev-violet-bd:#DDD6FE; --sev-violet-bg:#F5F3FF;

  --chart-1: #E64100;
  --chart-2: #17B26A;
  --chart-3: #2563EB;
  --chart-4: #F79009;
  --chart-5: #8B5CF6;
  --chart-mem:   #E64100;
  --chart-load:  #2563EB;
  --chart-grid:  #EDF0F3;
  --chart-ink:   #6B7280;
  --chart-track: #E5E7EB;
  --chart-up:    #17B26A;
  --chart-down:  #F04438;
  --chart-none:  #E5E7EB;
  --chart-area:  rgba(230,65,0,.12);

  /* Heatmap ramp — five steps, quietest to loudest, plus a "no data" step
     that is a dashed outline rather than a sixth colour. */
  --hm-perfect: #17B26A;
  --hm-good:    #75E0A7;
  --hm-warn:    #FEC84B;
  --hm-poor:    #FD853A;
  --hm-bad:     #F04438;
  --hm-empty:   transparent;

  /* ---- DENSITY + BREAKPOINTS -------------------------------------------
     The spacing scale above says what the steps ARE; these say which step a
     given kind of seam gets, so "how much air does a card get" is one
     decision rather than a px argument at every call site. They are also the
     only values that change with viewport: the @media blocks below restate
     THESE, never per-component padding, which is what stopped the console
     being responsive in more than three places.

     ⚠ The breakpoints are Logrite-UI's own (src/responsive.css), which are
     Tailwind's: 640 / 768 / 1024 / 1280. This console used to mix in 460,
     720, 980, 1100 and 1279 — five extra tiers nothing else in the product
     shares, so a layout that reflowed correctly in the app reflowed at a
     different width here. CSS cannot read a custom property inside a media
     QUERY, so the scale cannot be enforced by var() — `test_design_parity.js`
     greps every @media in both stylesheets and fails on a width off-scale. */
  --gap-page:    var(--sp-6);   /* between top-level cards on a page */
  --gap-card:    var(--sp-5);   /* inside a card, between its blocks */
  --gap-control: var(--sp-3);   /* between controls on one toolbar row */
  --gap-inline:  var(--sp-2);   /* icon-to-label, chip-to-chip */
  --pad-card:    var(--sp-5);
  --pad-page:    var(--sp-6);

  /* Grid tracks. A card grid states its MINIMUM column, never a count —
     a count has to be restated at every breakpoint and drifts from the
     container it actually sits in. */
  --col-svc:  20.5rem;
  --col-stat: 15rem;

  /* Logrite-UI's own shell geometry (useSidebar.js:69-70), which the
     management console already carried. This file had 268/60 — a 12px
     narrower rail and a 4px shorter header than the other surface of the
     same product, one click away. Nothing failed; the two pages just did not
     line up when you moved between them. */
  --sidebar-width: 280px;
  --sidebar-collapsed: 68px;
  --mobile-header: 64px;
}

/* ============================================================
   1b. TOKENS — DARK
   The media query is the default signal; the [data-theme] rules below
   override it in BOTH directions so the toggle always wins.
   ============================================================ */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg-primary:   #0C0E12;
    --bg-secondary: #13161B;
    --bg-tertiary:  #1A1D24;
    --bg-hover:     #22262F;
    --bg-active:    #2A2E37;

    --border-primary:   #2A2A2A;
    --border-secondary: #373A41;
    --border-tertiary:  #22262F;

    --text-primary:   #FFFFFF;
    --text-secondary: #CECFD2;
    --text-tertiary:  #94979C;
    --text-muted:     #6B7280;

    --accent-orange-text:   #FF8B5B;
    --accent-orange-bg:     #2A150C;
    --accent-orange-border: #7A3113;

    --shadow-md:    0 4px 6px -1px rgba(0,0,0,.3);
    --shadow-lg:    0 10px 15px -3px rgba(0,0,0,.3);
    --shadow-modal: 0 25px 50px -12px rgba(0,0,0,.6);
    --shadow-menu:  0 4px 12px rgba(0,0,0,.3);

    --scrim: rgba(0,0,0,.6);
    --sheen: rgba(255,255,255,.03);

    --sev-error-fg: #FDA29B; --sev-error-bd: #912018; --sev-error-bg: #55160C;
    --sev-warn-fg:  #FEC84B; --sev-warn-bd:  #93370D; --sev-warn-bg:  #4E1D09;
    --sev-info-fg:  #75E0A7; --sev-info-bd:  #085D3A; --sev-info-bg:  #053321;
    --sev-debug-fg: #84CAFF; --sev-debug-bd: #1849A9; --sev-debug-bg: #102A56;
    --sev-trace-fg: #67E3F9; --sev-trace-bd: #155B75; --sev-trace-bg: #0D2D3A;
    --sev-none-fg:  #94979C; --sev-none-bd:  #373A41; --sev-none-bg:  transparent;
    --sev-violet-fg:#C3B5FD; --sev-violet-bd:#5B21B6; --sev-violet-bg:#2E1065;

    --chart-grid:  #22262F;
    --chart-ink:   #94979C;
    --chart-track: #22262F;
    --chart-none:  #22262F;
    --chart-area:  rgba(230,65,0,.16);

    --hm-good:    #085D3A;
    --hm-warn:    #93370D;
  }
}

/* Explicit dark — wins over a light OS preference. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg-primary:   #0C0E12;
  --bg-secondary: #13161B;
  --bg-tertiary:  #1A1D24;
  --bg-hover:     #22262F;
  --bg-active:    #2A2E37;

  --border-primary:   #2A2A2A;
  --border-secondary: #373A41;
  --border-tertiary:  #22262F;

  --text-primary:   #FFFFFF;
  --text-secondary: #CECFD2;
  --text-tertiary:  #94979C;
  --text-muted:     #6B7280;

  --accent-orange-text:   #FF8B5B;
  --accent-orange-bg:     #2A150C;
  --accent-orange-border: #7A3113;

  --shadow-md:    0 4px 6px -1px rgba(0,0,0,.3);
  --shadow-lg:    0 10px 15px -3px rgba(0,0,0,.3);
  --shadow-modal: 0 25px 50px -12px rgba(0,0,0,.6);
  --shadow-menu:  0 4px 12px rgba(0,0,0,.3);

  --scrim: rgba(0,0,0,.6);
  --sheen: rgba(255,255,255,.03);

  --sev-error-fg: #FDA29B; --sev-error-bd: #912018; --sev-error-bg: #55160C;
  --sev-warn-fg:  #FEC84B; --sev-warn-bd:  #93370D; --sev-warn-bg:  #4E1D09;
  --sev-info-fg:  #75E0A7; --sev-info-bd:  #085D3A; --sev-info-bg:  #053321;
  --sev-debug-fg: #84CAFF; --sev-debug-bd: #1849A9; --sev-debug-bg: #102A56;
  --sev-trace-fg: #67E3F9; --sev-trace-bd: #155B75; --sev-trace-bg: #0D2D3A;
  --sev-none-fg:  #94979C; --sev-none-bd:  #373A41; --sev-none-bg:  transparent;
  --sev-violet-fg:#C3B5FD; --sev-violet-bd:#5B21B6; --sev-violet-bg:#2E1065;

  --chart-grid:  #22262F;
  --chart-ink:   #94979C;
  --chart-track: #22262F;
  --chart-none:  #22262F;
  --chart-area:  rgba(230,65,0,.16);

  --hm-good:    #085D3A;
  --hm-warn:    #93370D;
}

/* Explicit light — wins over a dark OS preference. Values repeat the base
   block because `:root` alone would lose to the media query above. */
:root[data-theme="light"] {
  color-scheme: light;

  --bg-primary:   #FFFFFF;
  --bg-secondary: #F8F9FA;
  --bg-tertiary:  #F3F4F6;
  --bg-hover:     #E5E7EB;
  --bg-active:    #D1D5DB;

  --border-primary:   #E5E7EB;
  --border-secondary: #D1D5DB;
  --border-tertiary:  #E5E7EB;

  --text-primary:   #111827;
  --text-secondary: #374151;
  --text-tertiary:  #6B7280;
  --text-muted:     #9CA3AF;

  --accent-orange-text:   #BF3D00;
  --accent-orange-bg:     #FFF1EA;
  --accent-orange-border: #F5B79A;

  --shadow-md:    0 4px 6px -1px rgba(0,0,0,.1);
  --shadow-lg:    0 10px 15px -3px rgba(0,0,0,.1);
  --shadow-modal: 0 25px 50px -12px rgba(0,0,0,.18);
  --shadow-menu:  0 4px 12px rgba(0,0,0,.12);

  --scrim: rgba(20,18,15,.55);
  --sheen: rgba(0,0,0,.02);

  --sev-error-fg: #B91C1C; --sev-error-bd: #FECACA; --sev-error-bg: #FEF2F2;
  --sev-warn-fg:  #B45309; --sev-warn-bd:  #FDE68A; --sev-warn-bg:  #FFFBEB;
  --sev-info-fg:  #15803D; --sev-info-bd:  #BBF7D0; --sev-info-bg:  #F0FDF4;
  --sev-debug-fg: #1D4ED8; --sev-debug-bd: #BFDBFE; --sev-debug-bg: #EFF6FF;
  --sev-trace-fg: #0E7490; --sev-trace-bd: #A5F3FC; --sev-trace-bg: #ECFEFF;
  --sev-none-fg:  #6B7280; --sev-none-bd:  #D1D5DB; --sev-none-bg:  transparent;
  --sev-violet-fg:#6D28D9; --sev-violet-bd:#DDD6FE; --sev-violet-bg:#F5F3FF;

  --chart-grid:  #EDF0F3;
  --chart-ink:   #6B7280;
  --chart-track: #E5E7EB;
  --chart-none:  #E5E7EB;
  --chart-area:  rgba(230,65,0,.12);

  --hm-good:    #75E0A7;
  --hm-warn:    #FEC84B;
}

/* ============================================================
   2. RESET + BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

html {
  scrollbar-width: thin;
  scrollbar-color: var(--border-secondary) transparent;
  scrollbar-gutter: stable;
}
html, body { margin: 0; padding: 0; min-height: 100%; }
body {
  background-color: var(--bg-primary);
  color: var(--text-primary);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  line-height: 1.25rem;
  -webkit-font-smoothing: antialiased;
  /* the page body must never scroll sideways — wide content scrolls in its
     own container instead */
  overflow-x: hidden;
}
h1, h2, h3, h4, h5, h6 { margin: 0; font-weight: 600; color: var(--text-primary); }
p, dl, dd, dt, ul, ol, figure { margin: 0; }
a { color: var(--accent-orange-text); text-decoration: none; }
a:hover { text-decoration: underline; }
button, input, select, textarea { font: inherit; color: inherit; }
code, pre, .lr-mono { font-family: var(--font-mono); }
img, svg { max-width: 100%; }
table { border-collapse: collapse; }

:focus-visible {
  outline: 2px solid var(--accent-orange);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
:focus:not(:focus-visible) { outline: none; }

::selection { background: rgba(230,65,0,.32); }

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; border-radius: 10px; }
::-webkit-scrollbar-thumb { background: var(--border-secondary); border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: var(--accent-orange); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

.lr-skip {
  position: absolute; left: -9999px; top: 0; z-index: 10050;
  background: var(--bg-secondary); color: var(--text-primary);
  border: 1px solid var(--accent-orange);
  padding: 10px 16px; border-radius: 0 0 var(--radius-lg) 0;
  font-weight: 600;
}
.lr-skip:focus { left: 0; text-decoration: none; }

.lr-sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ============================================================
   3. ICONS
   ============================================================ */
.lr-icon     { width: 16px; height: 16px; flex-shrink: 0; display: block; }
.lr-icon--xs { width: 12px; height: 12px; }
.lr-icon--sm { width: 14px; height: 14px; }
.lr-icon--lg { width: 20px; height: 20px; }
.lr-icon--xl { width: 24px; height: 24px; }
.lr-icon--32 { width: 32px; height: 32px; }

/* ============================================================
   4. TYPE HELPERS
   ============================================================ */
.lr-label {
  font-size: var(--fs-micro); font-weight: 500; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-tertiary);
}
.lr-title-page { font-size: var(--fs-2xl); line-height: 2rem;    font-weight: 600; }
.lr-title-card { font-size: var(--fs-lg);  line-height: 1.75rem; font-weight: 600; }
.lr-hint  { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.1rem; }
.lr-muted { color: var(--text-tertiary); }
.lr-num   { font-variant-numeric: tabular-nums; }
.lr-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.lr-wrap-any { overflow-wrap: anywhere; word-break: break-word; }

/* ============================================================
   5. SHELL
   ============================================================ */
.lr-shell { min-height: 100vh; min-height: 100dvh; }

.lr-sidebar {
  position: fixed; left: 0; top: 0; z-index: 50;
  width: var(--sidebar-width);
  height: 100vh; height: 100dvh;
  display: flex; flex-direction: column;
  background: var(--bg-primary);
  border-right: 1px solid var(--border-primary);
  padding: 16px 12px 12px;
  gap: 4px;
  overflow: visible;
  transition: width var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
.lr-sidebar__scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
  display: flex; flex-direction: column; gap: 4px;
  margin: 0 -4px; padding: 0 4px;
}

.lr-main {
  margin-left: var(--sidebar-width);
  min-width: 0;
  min-height: 100vh; min-height: 100dvh;
  display: flex; flex-direction: column;
  transition: margin-left var(--dur-slow) var(--ease);
}

.lr-brand { display: flex; align-items: center; gap: 10px; padding: 2px 6px 12px; min-width: 0; }
.lr-brand__mark { width: 32px; height: 32px; flex-shrink: 0; display: block; color: var(--accent-orange); }
.lr-brand__text { display: flex; flex-direction: column; line-height: 1.2; min-width: 0; }
.lr-brand__text b { font-size: var(--fs-sm); font-weight: 600; letter-spacing: .01em; }
.lr-brand__text span {
  font-size: var(--fs-micro); color: var(--text-tertiary);
  text-transform: uppercase; letter-spacing: .09em; font-weight: 500;
}

.lr-nav { display: flex; flex-direction: column; gap: 2px; }
.lr-nav-item {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 8px 12px; border-radius: var(--radius-lg);
  background: none; border: 0; cursor: pointer; text-align: left;
  color: var(--text-secondary); font-size: var(--fs-sm); font-weight: 600;
  text-decoration: none;
  transition: background-color var(--dur-slow) var(--ease);
}
.lr-nav-item:hover { background: var(--bg-hover); text-decoration: none; }
.lr-nav-item[aria-current="page"] { background: var(--bg-hover); color: var(--text-primary); }
.lr-nav-item:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: -2px; }
.lr-nav-item__icon {
  width: 20px; height: 20px; flex-shrink: 0; color: var(--text-tertiary);
  transition: color var(--dur-slow) var(--ease), filter var(--dur-slow) var(--ease),
              transform var(--dur-slow) var(--ease);
}
/* The active state is a GLOWING COLOURED ICON, not an indicator bar. */
.lr-nav-item[aria-current="page"] .lr-nav-item__icon {
  color: var(--accent-orange);
  filter: drop-shadow(0 0 8px rgba(230,65,0,.5));
}
.lr-nav-item:hover .lr-nav-item__icon { color: var(--accent-orange); transform: scale(1.08); }
.lr-nav-item__label { transition: transform var(--dur-slow) var(--ease); min-width: 0; }
.lr-nav-item:hover .lr-nav-item__label { transform: translateX(4px); }
.lr-nav-item__count {
  margin-left: auto; flex-shrink: 0;
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 600;
  color: var(--text-tertiary);
  background: var(--bg-secondary);
  border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-full); padding: 1px 7px;
}
.lr-nav-item__count.is-bad  { color: var(--sev-error-fg); border-color: var(--sev-error-bd); }
.lr-nav-item__count.is-warn { color: var(--sev-warn-fg);  border-color: var(--sev-warn-bd); }
.lr-nav-item__kbd {
  margin-left: auto; flex-shrink: 0;
  font-family: var(--font-mono); font-size: var(--fs-micro);
  color: var(--text-muted);
  border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-sm); padding: 0 5px;
}

.lr-sidebar.is-collapsed { width: var(--sidebar-collapsed); }
.lr-sidebar.is-collapsed .lr-nav-item {
  width: 40px; height: 40px; justify-content: center; padding: 0; margin: 0 auto 1px; gap: 0;
}
.lr-sidebar.is-collapsed .lr-nav-item__label,
.lr-sidebar.is-collapsed .lr-nav-item__count,
.lr-sidebar.is-collapsed .lr-nav-item__kbd,
.lr-sidebar.is-collapsed .lr-brand__text,
.lr-sidebar.is-collapsed .lr-side-label,
.lr-sidebar.is-collapsed .lr-envmeta,
.lr-sidebar.is-collapsed .lr-sidefoot__text,
.lr-sidebar.is-collapsed .lr-segmented { display: none; }
.lr-sidebar.is-collapsed .lr-brand { justify-content: center; padding-left: 0; padding-right: 0; }
.lr-sidebar.is-collapsed .lr-sidefoot { align-items: center; }

.lr-side-label {
  font-size: var(--fs-micro); font-weight: 600; text-transform: uppercase;
  letter-spacing: .09em; color: var(--text-tertiary);
  padding: 14px 8px 6px;
}

/* Segmented environment switcher — the console's host switcher. */
.lr-segmented {
  display: flex; gap: 2px; padding: 3px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-lg);
}
.lr-segmented button {
  flex: 1 1 0; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  padding: 5px 8px; border: 0; border-radius: var(--radius-md);
  background: none; color: var(--text-tertiary);
  font-size: var(--fs-xs); font-weight: 600; cursor: pointer;
  transition: background-color var(--dur-slow) var(--ease), color var(--dur-slow) var(--ease);
}
.lr-segmented button:hover { background: var(--bg-hover); color: var(--text-secondary); }
.lr-segmented button[aria-pressed="true"] { background: var(--accent-orange); color: #fff; }
.lr-segmented button:disabled { opacity: .5; cursor: not-allowed; }
.lr-segmented button .lr-icon { width: 13px; height: 13px; }

/* Environment metadata under the switcher */
.lr-envmeta { display: flex; flex-direction: column; gap: 4px; margin-top: 8px; }
.lr-envmeta-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 10px; border-radius: var(--radius-lg);
  background: var(--bg-secondary); border: 1px solid var(--border-tertiary);
  font-size: var(--fs-xs); min-width: 0;
}
.lr-envmeta-row b { font-weight: 600; color: var(--text-secondary); }
.lr-envmeta-row > span:last-child {
  margin-left: auto; color: var(--text-tertiary);
  font-family: var(--font-mono); font-size: var(--fs-micro);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.lr-sidefoot {
  margin-top: auto; padding-top: 10px;
  display: flex; flex-direction: column; gap: 8px; position: relative;
}
.lr-sidefoot__text { font-size: var(--fs-micro); color: var(--text-muted); padding: 0 4px; line-height: 1.5; }

/* host chip: dev vs prod told apart by shape too — prod is filled, dev dashed */
.lr-host-tag {
  display: inline-flex; align-items: center; flex-shrink: 0;
  padding: 1px 7px; border-radius: var(--radius-full);
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase;
  border: 1px solid var(--border-secondary); color: var(--text-tertiary);
  background: none;
}
.lr-host-tag.is-prod { background: var(--accent-orange); border-color: var(--accent-orange); color: #fff; }
.lr-host-tag.is-dev  { background: none; border-style: dashed; color: var(--text-tertiary); }

/* ============================================================
   6. TOPBAR
   ============================================================ */
.lr-topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
  padding: 14px 24px;
  border-bottom: 1px solid var(--border-tertiary);
  background: var(--bg-primary);
}
@supports (backdrop-filter: blur(8px)) {
  .lr-topbar { background: color-mix(in srgb, var(--bg-primary) 92%, transparent); backdrop-filter: blur(8px); }
}
.lr-topbar__left  { display: flex; align-items: center; gap: 12px; min-width: 0; }
.lr-topbar__right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lr-topbar__titles { min-width: 0; }
.lr-topbar__titles h1 { font-size: var(--fs-xl); line-height: 1.7rem; font-weight: 600; }
.lr-topbar__titles p  { font-size: var(--fs-xs); color: var(--text-tertiary); margin-top: 1px; }

.lr-freshness {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 5px 10px; border-radius: var(--radius-full);
  border: 1px solid var(--border-tertiary); background: var(--bg-secondary);
  font-size: var(--fs-xs); color: var(--text-tertiary); white-space: nowrap;
}

/* status dot — SHAPE carries the state as well as colour:
   live = circle, stale = diamond, dead = square, idle = dashed ring. */
.lr-dot {
  width: 8px; height: 8px; flex-shrink: 0; border-radius: var(--radius-full);
  background: var(--text-muted); display: inline-block;
}
.lr-dot.is-live  { background: var(--status-success); }
.lr-dot.is-stale { background: var(--status-warning); border-radius: 1px; transform: rotate(45deg); }
.lr-dot.is-dead  { background: var(--status-error); border-radius: 1px; }
.lr-dot.is-idle  { background: none; border: 1.5px dashed var(--sev-none-bd); }
.lr-dot.is-pulse { animation: dt-pulse 2s var(--ease) infinite; }
@keyframes dt-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(23,178,106,.5); }
  50%      { box-shadow: 0 0 0 4px rgba(23,178,106,0); }
}

/* ============================================================
   7. BUTTONS
   ============================================================ */
.lr-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  flex-shrink: 0;
  padding: 8px 16px; border-radius: var(--radius-lg);
  font-size: var(--fs-sm); font-weight: 600; line-height: 1.25rem;
  border: 1px solid transparent; cursor: pointer;
  background: none; color: var(--text-secondary);
  white-space: nowrap;
  transition: background-color var(--dur-slow) var(--ease),
              border-color var(--dur-slow) var(--ease),
              color var(--dur-slow) var(--ease);
}
.lr-btn:disabled { opacity: .5; cursor: not-allowed; }
.lr-btn:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 2px; }

.lr-btn--primary {
  background: var(--accent-orange); color: #fff;
  border: 2px solid rgba(255,255,255,.12);
  box-shadow: var(--shadow-sm);
}
.lr-btn--primary:hover:not(:disabled) { background: var(--accent-orange-hover); }

.lr-btn--secondary {
  background: var(--bg-secondary); color: var(--text-secondary);
  border: 1px solid var(--border-secondary); box-shadow: var(--shadow-sm);
}
.lr-btn--secondary:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--accent-orange); }

.lr-btn--ghost { padding: 8px 12px; font-weight: 500; color: var(--text-secondary); }
.lr-btn--ghost:hover:not(:disabled) { background: var(--bg-hover); color: var(--text-primary); }

.lr-btn--danger { background: #D92D20; color: #fff; border-color: rgba(255,255,255,.12); }
.lr-btn--danger:hover:not(:disabled) { background: #B42318; }

.lr-btn--sm { padding: 5px 10px; font-size: var(--fs-xs); }
.lr-btn--block { width: 100%; }
.lr-btn-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }

.lr-iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  flex-shrink: 0; padding: 6px; border-radius: var(--radius-md);
  background: none; border: 1px solid transparent; cursor: pointer;
  color: var(--text-tertiary);
  transition: color var(--dur-slow) var(--ease), background-color var(--dur-slow) var(--ease);
}
.lr-iconbtn:hover:not(:disabled) { color: var(--accent-orange); background: var(--bg-hover); }
.lr-iconbtn:disabled { opacity: .5; cursor: not-allowed; }
.lr-iconbtn--danger:hover:not(:disabled) { color: var(--status-error); }
.lr-iconbtn.is-copied { color: var(--status-success); }

/* The house close button: rotate-90 on hover. */
.lr-close {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 4px; border-radius: var(--radius-lg);
  background: none; border: 0; cursor: pointer; color: var(--text-tertiary);
  transition: color var(--dur-slow) var(--ease), background-color var(--dur-slow) var(--ease);
}
.lr-close:hover { color: var(--text-primary); background: var(--bg-hover); }
.lr-close .lr-icon { width: 20px; height: 20px; transition: transform var(--dur-slow) var(--ease); }
.lr-close:hover .lr-icon { transform: rotate(90deg); }

.lr-collapse-btn {
  padding: 6px; border-radius: var(--radius-lg);
  background: rgba(230,65,0,.15); color: var(--accent-orange);
  border: 0; cursor: pointer; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  transition: background-color var(--dur-slow) var(--ease);
}
.lr-collapse-btn:hover { background: rgba(230,65,0,.25); }

/* ============================================================
   8. INPUTS, SEARCH, SELECT, TABS, CHIPS
   ============================================================ */
.lr-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.lr-field > label, .lr-field-label {
  font-size: var(--fs-sm); font-weight: 500; color: var(--text-tertiary);
}

/* 2px border AT REST so the control does not jump 1px on focus. */
.lr-input, .lr-select {
  width: 100%; min-width: 0;
  padding: 8px 12px; border-radius: var(--radius-lg);
  font-size: var(--fs-sm); line-height: 1.25rem;
  background: var(--bg-secondary); color: var(--text-primary);
  border: 2px solid var(--border-secondary);
  transition: border-color var(--dur-slow) var(--ease);
}
.lr-input::placeholder { color: var(--text-muted); }
.lr-input:hover:not(:disabled), .lr-select:hover:not(:disabled) { border-color: var(--accent-orange); }
.lr-input:focus-visible, .lr-select:focus-visible {
  border-color: var(--accent-orange); outline: 2px solid rgba(230,65,0,.35); outline-offset: 1px;
}
.lr-input:disabled, .lr-select:disabled { opacity: .55; cursor: not-allowed; }
.lr-select {
  cursor: pointer; padding-right: 30px; appearance: none;
  background-repeat: no-repeat; background-position: right 8px center; background-size: 14px 14px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .lr-select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394979C' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  }
}
:root[data-theme="dark"] .lr-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394979C' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
:root[data-theme="light"] .lr-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
.lr-select option { background: var(--bg-secondary); color: var(--text-primary); }
/* Kept in step with the console's copy even though this site no longer
   builds a native <select> — a shared rule left at a value the other sheet
   does not have is the first step of the two files meaning different
   things. .lr-dd--sm is what actually renders here. */
.lr-select--sm { padding: 3px 8px; font-size: var(--fs-xs); }

.lr-search {
  display: flex; align-items: center; gap: 8px; min-width: 0;
  padding: 7px 10px; border-radius: var(--radius-lg);
  background: var(--bg-secondary);
  border: 1px solid var(--border-secondary);
  transition: border-color var(--dur-slow) var(--ease);
}
.lr-search:hover, .lr-search:focus-within { border-color: var(--accent-orange); }
.lr-search:focus-within { outline: 2px solid rgba(230,65,0,.35); outline-offset: 1px; }
.lr-search > .lr-icon { color: var(--text-muted); }
.lr-search input {
  flex: 1 1 auto; min-width: 0;
  background: none; border: 0; outline: none;
  font-size: var(--fs-sm); color: var(--text-secondary);
}
.lr-search input::placeholder { color: var(--text-muted); }
.lr-search input::-webkit-search-cancel-button { -webkit-appearance: none; }

.lr-tabs {
  display: flex; align-items: center; gap: 4px; flex-wrap: nowrap;
  overflow-x: auto; padding: 4px; margin: 0;
  background: var(--bg-secondary); border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-xl);
  scrollbar-width: none;
}
.lr-tabs::-webkit-scrollbar { display: none; }
.lr-tab {
  display: inline-flex; align-items: center; gap: 6px; flex-shrink: 0;
  white-space: nowrap; padding: 6px 14px; border-radius: var(--radius-lg);
  border: 0; background: none; cursor: pointer;
  font-size: var(--fs-sm); font-weight: 500; color: var(--text-secondary);
  transition: background-color var(--dur-slow) var(--ease), color var(--dur-slow) var(--ease);
}
.lr-tab:hover { background: var(--bg-hover); }
.lr-tab[aria-selected="true"] { background: var(--accent-orange); color: #fff; }
.lr-tab[aria-selected="true"] .lr-tab__count { background: rgba(255,255,255,.22); color: #fff; }
.lr-tab .lr-icon { width: 14px; height: 14px; }
.lr-tab__count {
  font-size: var(--fs-micro); font-family: var(--font-mono);
  padding: 0 5px; border-radius: var(--radius-full);
  background: var(--bg-hover); color: var(--text-tertiary);
}

.lr-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 12px; font-size: var(--fs-xs); border-radius: var(--radius-full);
  border: 1px solid var(--border-secondary);
  background: var(--bg-hover); color: var(--text-tertiary);
  transition: border-color var(--dur-slow) var(--ease), color var(--dur-slow) var(--ease);
  text-decoration: none; cursor: pointer;
}
a.lr-chip:hover, button.lr-chip:hover { border-color: var(--accent-orange); color: var(--text-secondary); text-decoration: none; }
.lr-chip[aria-pressed="true"], .lr-chip.is-on {
  background: var(--accent-orange); border-color: var(--accent-orange); color: #fff;
}
.lr-chip--static { cursor: default; }
.lr-chip--static:hover { border-color: var(--border-secondary); color: var(--text-tertiary); }

.lr-check {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer;
  font-size: var(--fs-sm); color: var(--text-secondary); user-select: none;
  padding: 2px 0; white-space: nowrap;
}
.lr-check input[type="checkbox"] {
  width: 15px; height: 15px; flex-shrink: 0;
  border-radius: .25em; appearance: none; -webkit-appearance: none;
  cursor: pointer; margin: 0;
  border: 2px solid var(--border-secondary);
  background-color: var(--bg-secondary);
  transition: all .2s ease-in-out;
}
.lr-check input[type="checkbox"]:checked {
  background-color: var(--accent-orange); border-color: var(--accent-orange);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='none' stroke='%23ffffff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3E%3C/svg%3E");
  background-size: 100% 100%; background-position: center; background-repeat: no-repeat;
}
.lr-check input[type="checkbox"]:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 2px; }

/* ============================================================
   9. BADGES + STATE PILLS
   ============================================================ */
.lr-badge {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  width: fit-content; padding: 2px 6px;
  border-radius: var(--radius-md);
  font-size: var(--fs-xs); font-weight: 600;
  border: 1px solid var(--sev-none-bd); color: var(--sev-none-fg);
  background: var(--bg-secondary);
}
.lr-badge--error  { color: var(--sev-error-fg);  border-color: var(--sev-error-bd);  background: var(--sev-error-bg); }
.lr-badge--warn   { color: var(--sev-warn-fg);   border-color: var(--sev-warn-bd);   background: var(--sev-warn-bg); }
.lr-badge--ok     { color: var(--sev-info-fg);   border-color: var(--sev-info-bd);   background: var(--sev-info-bg); }
.lr-badge--info   { color: var(--sev-debug-fg);  border-color: var(--sev-debug-bd);  background: var(--sev-debug-bg); }
.lr-badge--trace  { color: var(--sev-trace-fg);  border-color: var(--sev-trace-bd);  background: var(--sev-trace-bg); }
.lr-badge--violet { color: var(--sev-violet-fg); border-color: var(--sev-violet-bd); background: var(--sev-violet-bg); }
.lr-badge--brand  { color: var(--accent-orange-text); border-color: var(--accent-orange-border);
                    background: var(--accent-orange-bg); }
/* "Nobody recorded a value here" — NOT a severity. Told apart by SHAPE. */
.lr-badge--unset  { color: var(--sev-none-fg); border-color: var(--sev-none-bd);
                    background: transparent; border-style: dashed; }
.lr-badge--sm { font-size: var(--fs-micro); padding: 1px 5px; }

.lr-state {
  display: inline-flex; align-items: center; gap: 6px; white-space: nowrap;
  padding: 2px 8px 2px 6px; border-radius: var(--radius-full);
  font-size: var(--fs-xs); font-weight: 600;
  border: 1px solid var(--sev-none-bd); color: var(--sev-none-fg); background: transparent;
}
.lr-state--up   { color: var(--sev-info-fg);  border-color: var(--sev-info-bd);  background: var(--sev-info-bg); }
.lr-state--warn { color: var(--sev-warn-fg);  border-color: var(--sev-warn-bd);  background: var(--sev-warn-bg); }
.lr-state--down { color: var(--sev-error-fg); border-color: var(--sev-error-bd); background: var(--sev-error-bg); }
.lr-state--idle { border-style: dashed; }
.lr-state .lr-dot { width: 7px; height: 7px; background: currentColor; }
.lr-state--warn .lr-dot { border-radius: 1px; transform: rotate(45deg); }
.lr-state--down .lr-dot { border-radius: 1px; }
.lr-state--idle .lr-dot { background: none; border: 1.5px dashed currentColor; }

/* ============================================================
   10. CARDS, PAGE, GRIDS, KPI TILES
   ============================================================ */
.lr-card {
  background: var(--bg-primary);
  border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-sm);
  min-width: 0;
}
.lr-card__head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--gap-control); flex-wrap: wrap;
  padding: var(--sp-4) var(--pad-card); border-bottom: 1px solid var(--border-tertiary);
}
.lr-card__head-left { display: flex; align-items: center; gap: 10px; min-width: 0; flex-wrap: wrap; }
.lr-card__head-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.lr-card__body { padding: var(--pad-card); min-width: 0; }
.lr-card__body--flush { padding: 0; }
.lr-card__foot {
  padding: 10px 16px; border-top: 1px solid var(--border-tertiary);
  font-size: var(--fs-xs); color: var(--text-tertiary);
}
.lr-card__icon {
  width: 40px; height: 40px; flex-shrink: 0; border-radius: var(--radius-lg);
  border: 1px solid var(--border-secondary);
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-secondary); color: var(--accent-orange);
}
.lr-card__icon--sm { width: 32px; height: 32px; }

/* Same rhythm as the management console, off the same scale. */
.lr-page {
  padding: var(--pad-page) var(--pad-page) var(--sp-8);
  display: flex; flex-direction: column; gap: var(--gap-page); min-width: 0;
}
.lr-page:focus { outline: none; }

/* A VIEW is a page's content, not a page. `.lr-page` owns the shell's padding;
   the seven views nested inside it each carried
   `style="padding:0;gap:20px"` — seven copies of "undo my parent, and here is
   the gap again", which is how the gap ends up different on one of them. */
.lr-view {
  display: flex; flex-direction: column; gap: var(--gap-page);
  min-width: 0; padding: 0;
}
.lr-view[hidden] { display: none; }
@media (max-width: 767px) { .lr-view { gap: var(--sp-5); } }
/* Off the scale, like everything else here — a literal 16 is the one value
   that cannot be moved from the token block at the top of this file, which
   is the whole reason the token block exists.

   ⚠ `min(100%, …)` on every track. A bare `minmax(340px, 1fr)` cannot go
   below 340px, so on a 360px phone with 12px gutters the grid is wider than
   its container and the PAGE scrolls sideways — the child refuses to shrink
   and the overflow surfaces two levels up, where nothing names the grid. */
.lr-grid { display: grid; gap: var(--gap-card); }
.lr-grid--2   { grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); }
.lr-grid--3   { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }
.lr-grid--kpi { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--col-stat)), 1fr)); }
/* Tiles get the next step up. A card with a border and a status stripe
   needs a gutter bigger than the rhythm inside it, or a grid of them reads
   as one ruled table rather than as a set of objects. */
@media (min-width: 768px) {
  .lr-grid--2, .lr-grid--3 { gap: var(--sp-6); }
}

.lr-kpi {
  position: relative; overflow: hidden;
  background: var(--bg-secondary);
  border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-xl);
  padding: 14px 16px 14px 18px;
  box-shadow: var(--shadow-sm);
  min-width: 0;
}
/* severity STRIPE, so the tile's state survives a greyscale print */
.lr-kpi::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--border-tertiary);
}
.lr-kpi.is-ok::before    { background: var(--status-success); }
.lr-kpi.is-warn::before  { background: var(--status-warning); }
.lr-kpi.is-bad::before   { background: var(--status-error); }
.lr-kpi.is-brand::before { background: var(--accent-orange); }
.lr-kpi.is-unset::before { background: repeating-linear-gradient(
  to bottom, var(--sev-none-bd) 0 3px, transparent 3px 6px); }
.lr-kpi__top {
  display: flex; align-items: center; gap: 6px;
  font-size: var(--fs-micro); font-weight: 600; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-tertiary);
}
.lr-kpi__top .lr-icon { width: 13px; height: 13px; }
.lr-kpi__val {
  font-size: var(--fs-2xl); line-height: 2rem; font-weight: 600;
  color: var(--text-primary); margin-top: 6px;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.lr-kpi.is-warn  .lr-kpi__val { color: var(--sev-warn-fg); }
.lr-kpi.is-bad   .lr-kpi__val { color: var(--sev-error-fg); }
.lr-kpi.is-ok    .lr-kpi__val { color: var(--sev-info-fg); }
.lr-kpi.is-brand .lr-kpi__val { color: var(--accent-orange-text); }
.lr-kpi.is-unset .lr-kpi__val { color: var(--text-muted); }
.lr-kpi__sub { font-size: var(--fs-xs); color: var(--text-tertiary); margin-top: 2px; overflow-wrap: anywhere; }

/* Meters */
.lr-meters { display: flex; flex-direction: column; gap: 10px; }
.lr-meter__label {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  font-size: var(--fs-xs); color: var(--text-tertiary); margin-bottom: 4px;
}
.lr-meter__label b {
  color: var(--text-secondary); font-weight: 600;
  font-family: var(--font-mono); font-size: var(--fs-nano);
}
.lr-bar { height: 6px; border-radius: var(--radius-full); background: var(--chart-track); overflow: hidden; }
.lr-bar > span {
  display: block; height: 100%; background: var(--status-success);
  border-radius: var(--radius-full); transition: width var(--dur-slow) var(--ease);
}
.lr-bar > span.is-warn { background: var(--status-warning); }
.lr-bar > span.is-bad  { background: var(--status-error); }
/* A meter that has overflowed its own track gets a hatched cap rather than a
   width over 100%, which would just spill out of the rounded corner. */
.lr-bar > span.is-over {
  background: repeating-linear-gradient(45deg,
    var(--status-error) 0 5px, #B42318 5px 10px);
}

/* ============================================================
   11. TABLES
   ============================================================ */
.lr-table-scroll {
  width: 100%; max-width: 100%;
  overflow-x: auto; overflow-y: visible;
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  /* Stops a horizontal flick inside the table turning into a browser
     back-navigation on trackpads and touch. Losing the page you were reading
     is a far worse outcome than not scrolling. */
  overscroll-behavior-x: contain;
  scrollbar-width: thin;
}
/* Charts scroll for the same reason and need the same containment: they carry
   a 560px minimum below which the axis labels collide. */
.dt-chart-scroll { overscroll-behavior-x: contain; }
.lr-table { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
.lr-table thead th {
  position: sticky; top: 0; z-index: 10;
  padding: 10px 16px; text-align: left; white-space: nowrap;
  font-size: var(--fs-nano); font-weight: 600;
  text-transform: uppercase; letter-spacing: .025em;
  color: var(--text-tertiary);
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border-tertiary);
}
.lr-table th.is-num, .lr-table td.is-num { text-align: right; font-variant-numeric: tabular-nums; }
.lr-table td {
  padding: 9px 16px; color: var(--text-secondary);
  border-bottom: 1px solid var(--border-tertiary);
  vertical-align: middle;
}
.lr-table tbody tr { transition: background-color var(--dur-base) var(--ease); }
.lr-table tbody tr:nth-child(odd)  { background: var(--bg-secondary); }
.lr-table tbody tr:nth-child(even) { background: var(--bg-primary); }
.lr-table tbody tr.is-clickable:hover { background: var(--bg-hover); cursor: pointer; }
.lr-table tbody tr:last-child td { border-bottom: 0; }
/* the row's own severity stripe */
.lr-table tbody tr td:first-child { position: relative; padding-left: 19px; }
.lr-table tbody tr td:first-child::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: transparent;
}
.lr-table tbody tr.is-sick td:first-child::before  { background: var(--status-warning); }
.lr-table tbody tr.is-dead td:first-child::before  { background: var(--status-error); }
.lr-table tbody tr.is-ok   td:first-child::before  { background: var(--status-success); }
.lr-table tbody tr.is-unset td:first-child::before {
  background: repeating-linear-gradient(to bottom, var(--sev-none-bd) 0 3px, transparent 3px 6px);
}

.lr-th-sort {
  display: inline-flex; align-items: center; gap: 5px; margin: 0;
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit;
  transition: color var(--dur-base) var(--ease);
}
.lr-table th.is-num .lr-th-sort { flex-direction: row-reverse; }
.lr-th-sort:hover { color: var(--accent-orange-text); }
.lr-th-sort:focus-visible {
  outline: 2px solid var(--accent-orange-text); outline-offset: 2px; border-radius: 3px;
}
.lr-th-sort.is-active { color: var(--accent-orange-text); }
.lr-table th[aria-sort="ascending"] .lr-th-sort,
.lr-table th[aria-sort="descending"] .lr-th-sort { color: var(--accent-orange-text); }

/* The idle ↕ stays visible on every sortable column rather than appearing on
   hover: a control you can only find by accident is one most people never
   find, and half this page's tables gained sorting at once. */
.lr-th-sort .lr-arrow { font-size: 9px; line-height: 1; opacity: .4; }
.lr-th-sort:hover .lr-arrow { opacity: .8; }
.lr-th-sort.is-active .lr-arrow { opacity: 1; }

.lr-empty-row { text-align: center; color: var(--text-muted); padding: 32px 16px !important; }
.lr-empty-row::before { display: none !important; }

.lr-toolbar {
  display: flex; align-items: center; gap: var(--gap-control); flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5); border-bottom: 1px solid var(--border-tertiary);
  min-width: 0;
}
.lr-toolbar .lr-search { flex: 1 1 260px; }
.lr-toolbar--plain { border-bottom: 0; }
.lr-count-note {
  font-size: var(--fs-xs); color: var(--text-tertiary); white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.lr-spacer { flex: 1 1 auto; min-width: 0; }

.lr-mono-cell {
  font-family: var(--font-mono); font-size: var(--fs-nano); color: var(--text-tertiary);
  white-space: nowrap;
}
.lr-commit {
  font-family: var(--font-mono); font-size: var(--fs-nano);
  padding: 1px 6px; border-radius: var(--radius-sm);
  background: var(--bg-hover); color: var(--text-secondary);
  border: 1px solid var(--border-tertiary);
  text-decoration: none;
}
a.lr-commit:hover { border-color: var(--accent-orange); text-decoration: none; }
.lr-row-actions { display: inline-flex; gap: 2px; justify-content: flex-end; }

/* two-tier time cell: time on top, date beneath */
.lr-timecell { display: flex; flex-direction: column; line-height: 1.3; }
.lr-timecell b {
  font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-primary); font-variant-numeric: tabular-nums;
}
/* The DATE, not just the time. It was 10px tertiary — the lightest, smallest
   text in the table — under a bold time, so scanning an outage list for "which
   day was this?" meant reading the least legible thing on the row. Both halves
   of the cell answer a question somebody actually asks, so both are weighted
   and sized to be read. Tabular numerals keep the column aligned now that the
   date is heavier and no longer visually recedes. */
.lr-timecell span {
  font-size: var(--fs-xs); font-weight: 600;
  color: var(--text-secondary); font-variant-numeric: tabular-nums;
}

/* ============================================================
   12. EMPTY / LOADING / NOTE STATES
   ============================================================ */
.lr-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 48px 16px; text-align: center; gap: 4px;
}
.lr-empty__icon {
  width: 64px; height: 64px; border-radius: var(--radius-full);
  background: var(--bg-hover); color: var(--text-muted);
  display: flex; align-items: center; justify-content: center; margin-bottom: 12px;
}
.lr-empty__title { font-size: var(--fs-lg); font-weight: 600; color: var(--text-primary); }
.lr-empty__desc  { font-size: var(--fs-sm); color: var(--text-tertiary); max-width: 30rem; line-height: 1.5; }
.lr-empty__actions { margin-top: 14px; }

.lr-note {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--radius-lg);
  border: 1px solid var(--sev-none-bd); color: var(--text-secondary);
  background: var(--bg-secondary); font-size: var(--fs-sm);
  min-width: 0;
}
.lr-note--warn  { border-color: var(--sev-warn-bd);  background: var(--sev-warn-bg);  color: var(--sev-warn-fg); }
.lr-note--error { border-color: var(--sev-error-bd); background: var(--sev-error-bg); color: var(--sev-error-fg); }
.lr-note--info  { border-color: var(--sev-debug-bd); background: var(--sev-debug-bg); color: var(--sev-debug-fg); }
.lr-note--ok    { border-color: var(--sev-info-bd);  background: var(--sev-info-bg);  color: var(--sev-info-fg); }
.lr-note .lr-icon { margin-top: 2px; flex-shrink: 0; }
.lr-note__body { min-width: 0; flex: 1 1 auto; }
.lr-note__body b { display: block; margin-bottom: 2px; }
.lr-note__body p { line-height: 1.5; }

/* The border-spinner and the skeleton-shimmer that used to live here are
   GONE, along with `.lr-iconbtn.is-spinning`. There is exactly one wait
   affordance on this site now — `.lr-loading` / `.lr-loader`, defined at the
   foot of this file — because two of them means a wait looks like the product
   in some places and like a generic web page in others. */

/* ============================================================
   13. KEY/VALUE LISTS
   ============================================================ */
.lr-kv { display: grid; grid-template-columns: minmax(120px, 190px) minmax(0, 1fr); gap: 0; }
.lr-kv dt {
  padding: 8px 12px 8px 0; font-size: var(--fs-xs); color: var(--text-tertiary);
  border-bottom: 1px solid var(--border-tertiary); font-weight: 500;
}
.lr-kv dd {
  padding: 8px 0; border-bottom: 1px solid var(--border-tertiary);
  color: var(--text-secondary); min-width: 0;
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  word-break: break-word;
}
.lr-kv dt:last-of-type, .lr-kv dd:last-of-type { border-bottom: 0; }

.lr-section { display: flex; flex-direction: column; gap: 10px; }
.lr-section + .lr-section { margin-top: 20px; }
.lr-section__head {
  display: flex; align-items: center; gap: 8px;
  font-size: var(--fs-micro); font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; color: var(--text-tertiary);
  padding-bottom: 6px; border-bottom: 1px solid var(--border-tertiary);
}
.lr-section__head .lr-icon { width: 13px; height: 13px; }

/* ============================================================
   14. LOG / COMMAND OUTPUT
   ============================================================ */
.lr-pre {
  margin: 0; padding: 12px 14px;
  background: var(--bg-secondary);
  border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-lg);
  font-family: var(--font-mono); font-size: var(--fs-nano); line-height: 1.55;
  color: var(--text-secondary);
  white-space: pre-wrap; word-break: break-word;
  max-height: 46vh; overflow: auto;
  tab-size: 4;
}
.lr-pre:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: -2px; }

/* A copyable command: the string scrolls inside its own box, never the page. */
.lr-cmd {
  display: flex; align-items: stretch; gap: 0;
  border: 1px solid var(--border-secondary); border-radius: var(--radius-lg);
  background: var(--bg-secondary); overflow: hidden; min-width: 0;
}
.lr-cmd > code {
  flex: 1 1 auto; min-width: 0; padding: 11px 12px;
  font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--text-primary);
  overflow-x: auto; white-space: pre; line-height: 1.5;
}
.lr-cmd > button {
  flex-shrink: 0; border: 0; border-left: 1px solid var(--border-secondary);
  background: var(--bg-tertiary); color: var(--text-secondary);
  padding: 0 14px; cursor: pointer; font-size: var(--fs-xs); font-weight: 600;
  display: inline-flex; align-items: center; gap: 6px;
  transition: background-color var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.lr-cmd > button:hover { background: var(--bg-hover); color: var(--accent-orange-text); }
.lr-cmd > button.is-copied { color: var(--status-success); }

/* ============================================================
   15. MODAL SYSTEM — one implementation, every dialog
   ============================================================ */
.lr-modal-backdrop { position: fixed; inset: 0; z-index: 10000; background: var(--scrim); }
@supports (backdrop-filter: blur(4px)) {
  .lr-modal-backdrop { backdrop-filter: blur(4px); }
}
.lr-modal-container {
  position: fixed; inset: 0; z-index: 10001;
  display: flex; align-items: center; justify-content: center;
  padding: 16px; overflow-y: auto;
}
.lr-modal {
  display: flex; flex-direction: column;
  width: 100%; max-width: 36rem; max-height: 90vh;
  background: var(--bg-primary);
  border: 1px solid var(--border-tertiary);
  border-radius: var(--radius-2xl);
  box-shadow: var(--shadow-modal);
  overflow: hidden;
  animation: lr-fade-in .3s var(--ease-out);
}
.lr-modal--wide   { max-width: 62rem; }
.lr-modal--narrow { max-width: 30rem; }
.lr-modal__header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px 24px; border-bottom: 1px solid var(--border-tertiary);
  background: linear-gradient(to right, var(--sheen), transparent, var(--sheen));
  flex-shrink: 0;
}
.lr-modal__head-left  { display: flex; align-items: center; gap: 12px; min-width: 0; }
.lr-modal__head-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; flex-wrap: wrap; }
.lr-modal__titles { min-width: 0; }
.lr-modal__eyebrow {
  font-size: var(--fs-micro); font-weight: 600; text-transform: uppercase;
  letter-spacing: .08em; color: var(--text-tertiary); display: block;
}
.lr-modal__title { font-size: var(--fs-xl); font-weight: 600; min-width: 0; line-height: 1.6rem; }
.lr-modal__sub {
  font-size: var(--fs-xs); color: var(--text-tertiary); font-family: var(--font-mono);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block;
}
.lr-modal__body { flex: 1 1 0%; overflow-y: auto; padding: 16px 24px; min-height: 0; }
.lr-modal__body > * + * { margin-top: 14px; }
.lr-modal__footer {
  display: flex; align-items: center; justify-content: flex-end; gap: 12px;
  padding: 16px 24px; border-top: 1px solid var(--border-tertiary); flex-shrink: 0;
}
/* A dialog wrapper is boxless: its children are position:fixed. */
.lr-dialog { display: contents; }
.lr-dialog--top .lr-modal-backdrop  { z-index: 10010; }
.lr-dialog--top .lr-modal-container { z-index: 10011; }

@keyframes lr-fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ============================================================
   16. TOASTS
   ============================================================ */
.lr-toasts {
  position: fixed; right: 16px; top: 16px; z-index: 10020;
  display: flex; flex-direction: column; gap: 8px;
  width: min(420px, calc(100vw - 32px));
  pointer-events: none;
}
.lr-toast {
  padding: 12px 14px; padding-left: 16px; border-radius: var(--radius-lg);
  background: var(--bg-secondary);
  border: 1px solid var(--border-secondary);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-sm); color: var(--text-secondary);
  animation: lr-fade-in .3s var(--ease-out);
  position: relative; overflow: hidden; pointer-events: auto;
}
.lr-toast::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--border-secondary);
}
.lr-toast.is-ok::before   { background: var(--status-success); }
.lr-toast.is-bad::before  { background: var(--status-error); }
.lr-toast.is-warn::before { background: var(--status-warning); }
.lr-toast b { color: var(--text-primary); font-weight: 600; display: block; }
.lr-toast pre {
  margin: 8px 0 0; padding: 8px; max-height: 180px; overflow: auto;
  background: var(--bg-primary); border-radius: var(--radius-md);
  font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--text-tertiary);
  white-space: pre-wrap; word-break: break-word;
}

/* ============================================================
   17. TOOLTIP (singleton, data-tip driven)
   ============================================================ */
.lr-tip {
  position: fixed; z-index: 10030; pointer-events: none;
  max-width: min(340px, calc(100vw - 24px));
  padding: 9px 11px; border-radius: var(--radius-lg);
  background: var(--bg-primary);
  border: 1px solid var(--border-secondary);
  box-shadow: var(--shadow-menu);
  font-size: var(--fs-xs); color: var(--text-secondary); line-height: 1.45;
  animation: lr-fade-in .12s var(--ease-out);
}
.lr-tip--danger { border-color: var(--sev-error-bd); }
.lr-tip__title {
  font-weight: 600; color: var(--text-primary); font-size: var(--fs-xs);
  display: flex; align-items: center; gap: 6px; margin-bottom: 5px;
}
.lr-tip__rows { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 2px 10px; }
.lr-tip__k { color: var(--text-tertiary); white-space: nowrap; }
.lr-tip__v { color: var(--text-secondary); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.lr-tip__v.is-up   { color: var(--sev-info-fg); }
.lr-tip__v.is-down { color: var(--sev-error-fg); }
.lr-tip__v.is-warn { color: var(--sev-warn-fg); }
.lr-tip__foot {
  margin-top: 6px; padding-top: 5px; border-top: 1px solid var(--border-tertiary);
  color: var(--text-muted); font-size: var(--fs-micro);
}
.lr-tip__text { overflow-wrap: anywhere; }

/* ============================================================
   18. PAGINATION — one implementation for every table
   ============================================================ */
.lr-pager {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-5); border-top: 1px solid var(--border-tertiary);
}
.lr-pager__count { font-size: var(--fs-xs); color: var(--text-tertiary); font-variant-numeric: tabular-nums; }
.lr-pager__ctrls { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.lr-pg {
  min-width: 30px; height: 30px; padding: 0 8px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-tertiary); border-radius: var(--radius-md);
  background: var(--bg-secondary); color: var(--text-secondary);
  font-size: var(--fs-xs); font-weight: 600; cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background-color var(--dur-base) var(--ease), border-color var(--dur-base) var(--ease);
}
.lr-pg:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--accent-orange); }
.lr-pg:disabled { opacity: .4; cursor: not-allowed; }
.lr-pg[aria-current="page"] {
  background: var(--accent-orange); border-color: var(--accent-orange); color: #fff;
}
.lr-pg--gap { border: 0; background: none; cursor: default; color: var(--text-muted); }
.lr-pg--gap:hover { background: none; }

/* ============================================================
   19. MOBILE HEADER + DRAWER
   ============================================================ */
.lr-mobile-header {
  display: none;
  position: fixed; top: 0; left: 0; width: 100%; height: var(--mobile-header);
  z-index: 45;
  align-items: center; justify-content: space-between; gap: var(--sp-4);
  padding: 0 var(--sp-5);
  background: var(--bg-primary); border-bottom: 1px solid var(--border-primary);
}
.lr-mobile-header__title { display: flex; align-items: center; gap: 9px; min-width: 0; }
.lr-mobile-header__title b { font-size: var(--fs-sm); font-weight: 600; }
.lr-scrim { display: none; position: fixed; inset: 0; z-index: 44; background: rgba(0,0,0,.5); border: 0; }

@media (max-width: 1023px) {
  .lr-mobile-header { display: flex; }
  /* the drawer is always full width — --sidebar-width may be the collapsed
     68px from the desktop rail, which would give a 68px drawer */
  .lr-sidebar { transform: translateX(-100%); width: 280px; }
  .lr-sidebar.is-open { transform: translateX(0); }
  .lr-sidebar.is-collapsed { width: 280px; }
  .lr-sidebar.is-collapsed .lr-nav-item {
    width: 100%; height: auto; justify-content: flex-start; padding: 8px 12px; gap: 12px; margin: 0;
  }
  .lr-sidebar.is-collapsed .lr-nav-item__label,
  .lr-sidebar.is-collapsed .lr-nav-item__count,
  .lr-sidebar.is-collapsed .lr-nav-item__kbd,
  .lr-sidebar.is-collapsed .lr-brand__text,
  .lr-sidebar.is-collapsed .lr-side-label,
  .lr-sidebar.is-collapsed .lr-envmeta,
  .lr-sidebar.is-collapsed .lr-sidefoot__text,
  .lr-sidebar.is-collapsed .lr-segmented { display: revert; }
  .lr-sidebar.is-collapsed .lr-brand { justify-content: flex-start; }
  .lr-scrim.is-open { display: block; }
  .lr-main { margin-left: 0; padding-top: var(--mobile-header); }
  .lr-topbar { top: var(--mobile-header); }
  .lr-rail-btn { display: none; }
}

@media (max-width: 767px) {
  .lr-page { padding: var(--sp-5) var(--sp-4) var(--sp-7); gap: var(--sp-5); }
  .lr-topbar { padding: var(--sp-3) var(--sp-4); }
  .lr-kv { grid-template-columns: minmax(0,1fr); }
  .lr-kv dt { border-bottom: 0; padding-bottom: 0; }
  .lr-modal__header, .lr-modal__body, .lr-modal__footer { padding-left: var(--sp-5); padding-right: var(--sp-5); }
  .lr-grid--kpi { grid-template-columns: repeat(auto-fit, minmax(min(100%, 148px), 1fr)); }
  .lr-card__head { padding: var(--sp-3) var(--sp-4); }
  .lr-card__body { padding: var(--sp-4); }
  .lr-card__head-right { flex: 1 1 100%; }
  /* iOS ZOOM PREVENTION, and it must stay 16px literal.
     Safari zooms the whole page when a focused field's text is under 16px,
     and it does not zoom back out — so one tap on a filter leaves the
     operator on a page they have to pinch to read. This is the one place a
     raw px value is correct: the threshold is the browser's, not ours, so a
     token would imply it moves with our type scale. */
  input, select, textarea { font-size: 16px !important; }
}
@media (max-width: 767px) {
  /* Tighter gutters buy about 14px per column — the difference between a
     table fitting a phone and scrolling. Matches the management console. */
  .lr-table thead th { padding: var(--sp-2) var(--sp-3); position: static; }
  .lr-table td { padding: var(--sp-2) var(--sp-3); }
}
@media (max-width: 479px) {
  .lr-page { padding: var(--sp-4) var(--sp-3) var(--sp-7); }
}

/* ============================================================================
   ============================  APP LAYER  ===================================
   Everything below is specific to the downtime tracker. It is built from the
   tokens above and adds no new colour values of its own.
   ========================================================================== */

/* ============================================================
   21. DONUT + CHART PANEL
   ============================================================ */
.dt-chart-grid {
  display: grid; grid-template-columns: 230px minmax(0, 1fr);
  gap: 20px; align-items: start;
}
.dt-donut-wrap {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 4px 0;
}
.dt-donut-cap {
  font-size: var(--fs-micro); font-weight: 600; text-transform: uppercase;
  letter-spacing: .07em; color: var(--text-tertiary); text-align: center;
}
.dt-donut-cap.is-selected { color: var(--accent-orange-text); }
.dt-donut { position: relative; width: 190px; height: 190px; }
.dt-donut svg { width: 190px; height: 190px; display: block; transform: rotate(-90deg); }
.dt-donut-track { fill: none; stroke: var(--chart-track); stroke-width: 18; }
.dt-donut-arc {
  fill: none; stroke-width: 18; stroke-linecap: butt;
  transition: stroke-dasharray var(--dur-slow) var(--ease);
}
.dt-donut-arc.up   { stroke: var(--chart-up); }
.dt-donut-arc.down { stroke: var(--chart-down); }
.dt-donut-center {
  position: absolute; inset: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; text-align: center; padding: 0 22px;
}
.dt-donut-pct {
  font-size: var(--fs-3xl); line-height: 2.1rem; font-weight: 600;
  color: var(--sev-info-fg); font-variant-numeric: tabular-nums;
}
.dt-donut-pct.warn { color: var(--sev-warn-fg); }
.dt-donut-pct.bad  { color: var(--sev-error-fg); }
.dt-donut-pct.unset { color: var(--text-muted); font-size: var(--fs-2xl); }
.dt-donut-lbl {
  font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .09em;
  color: var(--text-tertiary); font-weight: 600;
}
.dt-donut-elapsed { font-size: var(--fs-micro); color: var(--text-muted); margin-top: 2px; }
.dt-donut-times {
  display: flex; gap: 12px; flex-wrap: wrap; justify-content: center;
  font-size: var(--fs-micro); font-variant-numeric: tabular-nums;
}
.dt-donut-times .t { display: inline-flex; align-items: center; gap: 5px; color: var(--text-tertiary); }
.dt-donut-times .t::before {
  content: ""; width: 9px; height: 3px; border-radius: 2px; display: inline-block; flex-shrink: 0;
}
.dt-donut-times .t.up::before   { background: var(--chart-up); }
.dt-donut-times .t.down::before { background: var(--chart-down); }

.dt-chart-right { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.dt-chart-area { min-width: 0; width: 100%; }
.dt-chart-area svg { display: block; width: 100%; height: auto; }
.dt-chart-scroll { width: 100%; overflow-x: auto; overflow-y: hidden; }

.dt-legend {
  display: flex; gap: 14px; flex-wrap: wrap;
  font-size: var(--fs-micro); color: var(--text-tertiary);
}
.dt-legend > span { display: inline-flex; align-items: center; gap: 5px; }
.dt-legend i { width: 10px; height: 3px; border-radius: 2px; display: inline-block; flex-shrink: 0; }
.dt-legend i.up   { background: var(--chart-up); }
.dt-legend i.down { background: var(--chart-down); }
.dt-legend i.none { background: none; border: 1.5px dashed var(--sev-none-bd); height: 8px; border-radius: 2px; }

/* SVG chart internals */
.dt-axis { fill: var(--chart-ink); font-size: 10px; font-family: var(--font-sans); }
.dt-grid { stroke: var(--chart-grid); stroke-width: 1; }
.dt-seg-up   { fill: var(--chart-up); }
.dt-seg-down { fill: var(--chart-down); }
.dt-seg-none { fill: var(--chart-none); }
.dt-line     { fill: none; stroke: var(--chart-1); stroke-width: 2;
               stroke-linejoin: round; stroke-linecap: round; }
.dt-line-fill { fill: var(--chart-area); }
.dt-dot      { fill: var(--chart-1); stroke: var(--bg-primary); stroke-width: 2; }
.dt-area-up   { fill: var(--chart-up); opacity: .75; }
.dt-area-down { fill: var(--chart-down); opacity: .8; }
.dt-pie-up    { fill: var(--chart-up); }
.dt-pie-down  { fill: var(--chart-down); }

.dt-drillable { cursor: pointer; }
.dt-drillable:focus { outline: none; }
.dt-drillable:focus-visible rect, .dt-drillable:focus-visible circle {
  stroke: var(--accent-orange); stroke-width: 2;
}
.dt-hit { fill: transparent; }
.dt-drillable:hover .dt-seg-up,
.dt-drillable:hover .dt-seg-down { opacity: .82; }

/* Heatmap */
.dt-heatmap { display: flex; flex-direction: column; gap: 14px; }
.dt-hm-cell { rx: 2.5; ry: 2.5; cursor: pointer; }
.dt-hm-perfect { fill: var(--hm-perfect); }
.dt-hm-good    { fill: var(--hm-good); }
.dt-hm-warn    { fill: var(--hm-warn); }
.dt-hm-poor    { fill: var(--hm-poor); }
.dt-hm-bad     { fill: var(--hm-bad); }
/* "no data" is a dashed outline, not a sixth colour — told apart by SHAPE */
.dt-hm-empty   { fill: none; stroke: var(--sev-none-bd); stroke-width: 1; stroke-dasharray: 2 2; }
.dt-hm-today   { stroke: var(--accent-orange); stroke-width: 1.5; }
.dt-hm-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(126px, 1fr)); gap: 10px;
}
.dt-hm-stat {
  padding: 9px 11px; border-radius: var(--radius-lg);
  border: 1px solid var(--border-tertiary); background: var(--bg-secondary);
}
.dt-hm-stat-lbl { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .05em;
                  color: var(--text-tertiary); font-weight: 600; }
.dt-hm-stat-val { font-size: var(--fs-base); font-weight: 600; margin-top: 3px;
                  font-variant-numeric: tabular-nums; color: var(--text-primary); }
.dt-hm-stat-val.is-up   { color: var(--sev-info-fg); }
.dt-hm-stat-val.is-warn { color: var(--sev-warn-fg); }
.dt-hm-stat-val.is-down { color: var(--sev-error-fg); }
.dt-hm-scale { display: flex; align-items: center; gap: 6px; font-size: var(--fs-micro); color: var(--text-tertiary); }
.dt-hm-scale i { width: 12px; height: 12px; border-radius: 2.5px; display: inline-block; }

/* ============================================================
   22. REASON CHIPS — the events table's most important column
   ============================================================ */
.dt-reason { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }
.dt-reason-code {
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap;
  padding: 2px 7px; border-radius: var(--radius-md);
  font-size: var(--fs-micro); font-weight: 700;
  text-transform: uppercase; letter-spacing: .03em;
  border: 1px solid var(--sev-none-bd); color: var(--sev-none-fg); background: var(--bg-secondary);
  cursor: help;
}
.dt-reason-http     { color: var(--sev-error-fg);  border-color: var(--sev-error-bd);  background: var(--sev-error-bg); }
.dt-reason-net      { color: var(--sev-warn-fg);   border-color: var(--sev-warn-bd);   background: var(--sev-warn-bg); }
.dt-reason-host     { color: var(--sev-debug-fg);  border-color: var(--sev-debug-bd);  background: var(--sev-debug-bg); }
.dt-reason-outage   { color: var(--sev-error-fg);  border-color: var(--sev-error-bd);  background: var(--sev-error-bg); }
.dt-reason-platform { color: var(--sev-violet-fg); border-color: var(--sev-violet-bd); background: var(--sev-violet-bg); }
.dt-reason-network  { color: var(--sev-warn-fg);   border-color: var(--sev-warn-bd);   background: var(--sev-warn-bg); }
.dt-reason-monitor  { color: var(--sev-trace-fg);  border-color: var(--sev-trace-bd);  background: var(--sev-trace-bg); }
.dt-reason-incident { color: var(--accent-orange-text); border-color: var(--accent-orange-border);
                      background: var(--accent-orange-bg); }
/* "no data" is a hole in the record, not a severity — dashed, like `unset`. */
.dt-reason-nodata   { color: var(--sev-none-fg); border-color: var(--sev-none-bd);
                      background: transparent; border-style: dashed; }
.dt-reason-msg {
  font-size: var(--fs-xs); color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.dt-desc {
  font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2;
  -webkit-box-orient: vertical; overflow: hidden;
  max-width: 44ch;
}
.dt-desc-empty { color: var(--text-muted); }

/* A row that does not count toward downtime is told apart by SHAPE: dashed
   left stripe + a dimmed duration, so a blind spot never reads as an outage. */
.lr-table tbody tr.dt-uncounted td { opacity: .78; }
.lr-table tbody tr.dt-uncounted td:first-child::before {
  background: repeating-linear-gradient(to bottom, var(--sev-none-bd) 0 3px, transparent 3px 6px);
}

.dt-flash { animation: dt-flash 1.4s var(--ease-out); }
@keyframes dt-flash {
  0%   { box-shadow: 0 0 0 0 rgba(230,65,0,.45); }
  100% { box-shadow: 0 0 0 14px rgba(230,65,0,0); }
}

/* ============================================================
   23. SERVICE PICKER + SERVICE DETAIL
   ============================================================ */
.dt-svcbar { display: flex; align-items: center; gap: var(--gap-control); flex-wrap: wrap; min-width: 0; }
/* The picker is `.lr-dd` now, not a native <select>. `.lr-dd--block` makes
   it `display: flex; width: 100%`, which in a wrapping flex row would take
   the whole line and push the status chips beneath it on every viewport —
   so the width is stated HERE, where the row's layout is decided, rather
   than left to the component's own default. */
.dt-svcbar .lr-dd { flex: 0 1 auto; width: auto; min-width: 230px; max-width: 100%; }
.dt-svcmeta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; min-width: 0; }

.dt-detail-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; }

/* ============================================================
   24. NOTIFICATION CARDS
   ============================================================ */
.dt-notif-list { display: flex; flex-direction: column; }
.dt-notif {
  position: relative; padding: 13px 16px 13px 19px;
  border-bottom: 1px solid var(--border-tertiary);
  min-width: 0;
}
.dt-notif:last-child { border-bottom: 0; }
.dt-notif::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--border-tertiary);
}
.dt-notif__head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.dt-notif__title { font-weight: 600; color: var(--text-primary); min-width: 0; overflow-wrap: anywhere; }
.dt-notif__time { margin-left: auto; font-size: var(--fs-micro); color: var(--text-muted);
                  font-variant-numeric: tabular-nums; white-space: nowrap; }
.dt-notif__desc { font-size: var(--fs-xs); color: var(--text-tertiary); margin-top: 5px; line-height: 1.5;
                  white-space: pre-wrap; overflow-wrap: anywhere; }
.dt-notif__fields {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 6px 14px; margin-top: 9px;
}
.dt-notif__field { min-width: 0; }
.dt-notif__field dt { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .05em;
                      color: var(--text-muted); font-weight: 600; }
.dt-notif__field dd { font-size: var(--fs-xs); color: var(--text-secondary); overflow-wrap: anywhere;
                      white-space: pre-wrap; }
.dt-notif details { margin-top: 9px; }
.dt-notif summary {
  cursor: pointer; font-size: var(--fs-micro); color: var(--text-tertiary);
  text-transform: uppercase; letter-spacing: .05em; font-weight: 600;
  list-style: none; display: inline-flex; align-items: center; gap: 5px;
}
.dt-notif summary::-webkit-details-marker { display: none; }
.dt-notif summary:hover { color: var(--accent-orange-text); }
.dt-notif details[open] summary { margin-bottom: 7px; }

/* ============================================================
   25. ZELLIJ / ZOMBIES / CLAUDE SHARED BITS
   ============================================================ */
.dt-statrow {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px;
}
.dt-pidchips { display: flex; flex-wrap: wrap; gap: 5px; }
.dt-pidchip {
  font-family: var(--font-mono); font-size: var(--fs-micro);
  padding: 2px 6px; border-radius: var(--radius-sm);
  background: var(--bg-hover); color: var(--text-secondary);
  border: 1px solid var(--border-tertiary);
}
.dt-person { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.dt-person b { font-weight: 600; color: var(--text-primary); }
.dt-person span { font-size: var(--fs-micro); color: var(--text-muted); font-family: var(--font-mono); }
.dt-fresh {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 11px; border-radius: var(--radius-lg);
  border: 1px solid var(--border-tertiary); background: var(--bg-secondary);
  font-size: var(--fs-xs); color: var(--text-tertiary);
}
.dt-fresh.is-stale { border-color: var(--sev-warn-bd); background: var(--sev-warn-bg); color: var(--sev-warn-fg); }

.dt-devlist { display: flex; flex-direction: column; gap: 8px; }
.dt-dev {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 9px 12px; border-radius: var(--radius-lg);
  border: 1px solid var(--border-tertiary); background: var(--bg-secondary);
  min-width: 0;
}
.dt-dev.is-clamping { border-color: var(--sev-warn-bd); background: var(--sev-warn-bg); }
.dt-dev__body { flex: 1 1 200px; min-width: 0; }
.dt-remedy {
  display: flex; gap: 11px; padding: 11px 13px;
  border-radius: var(--radius-lg); border: 1px solid var(--border-tertiary);
  background: var(--bg-secondary); min-width: 0;
}
.dt-remedy__rank {
  flex-shrink: 0; width: 22px; height: 22px; border-radius: var(--radius-full);
  background: var(--accent-orange); color: #fff;
  display: flex; align-items: center; justify-content: center;
  font-size: var(--fs-micro); font-weight: 700;
}
.dt-remedy--last .dt-remedy__rank { background: var(--text-muted); }
.dt-remedy__body { min-width: 0; flex: 1 1 auto; }
.dt-remedy__body b { display: block; color: var(--text-primary); margin-bottom: 3px; }
.dt-remedy__body p { font-size: var(--fs-xs); color: var(--text-tertiary); line-height: 1.5; }
.dt-remedy__body .lr-cmd { margin-top: 8px; }

/* ============================================================
   26. SERVER SNAPSHOT / RESOURCE BREAKDOWN
   ============================================================ */
/* min() so a track can never exceed its own container — a bare minmax on a
   320px phone lays out a wider column than the page and scrolls it sideways. */
.dt-snapgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 160px), 1fr)); gap: var(--sp-4); }
.dt-snap {
  padding: 12px 14px; border-radius: var(--radius-xl);
  border: 1px solid var(--border-tertiary); background: var(--bg-secondary);
  text-align: left; width: 100%;
  display: flex; flex-direction: column; gap: 3px;
}
button.dt-snap { cursor: pointer; transition: border-color var(--dur-base) var(--ease); }
button.dt-snap:hover { border-color: var(--accent-orange); }
.dt-snap__k { font-size: var(--fs-micro); text-transform: uppercase; letter-spacing: .05em;
              color: var(--text-tertiary); font-weight: 600;
              display: flex; align-items: center; gap: 5px; }
.dt-snap__v { font-size: var(--fs-xl); font-weight: 600; color: var(--text-primary);
              font-variant-numeric: tabular-nums; }
.dt-snap__n { font-size: var(--fs-micro); color: var(--text-muted); }

.dt-proclist { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 10px; }
.dt-proc {
  padding: 10px 12px; border-radius: var(--radius-lg);
  border: 1px solid var(--border-tertiary); background: var(--bg-secondary); min-width: 0;
}
.dt-proc__name { font-weight: 600; color: var(--text-primary); font-family: var(--font-mono);
                 font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dt-proc__args { font-size: var(--fs-micro); color: var(--text-muted); font-family: var(--font-mono);
                 overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 1px; }
.dt-proc__meta { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 6px;
                 font-size: var(--fs-micro); color: var(--text-tertiary);
                 font-variant-numeric: tabular-nums; }

.dt-svcrow {
  display: grid; grid-template-columns: minmax(140px, 1.1fr) minmax(0, 2fr) minmax(170px, auto);
  gap: 12px; align-items: center;
  padding: 8px 0; border-bottom: 1px solid var(--border-tertiary); min-width: 0;
}
.dt-svcrow:last-child { border-bottom: 0; }
.dt-svcrow__name { font-weight: 600; color: var(--text-secondary); min-width: 0;
                   overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dt-svcrow__val { font-size: var(--fs-xs); color: var(--text-tertiary);
                  overflow-wrap: anywhere; text-align: right;
                  font-variant-numeric: tabular-nums; }

/* ============================================================
   27. RESPONSIVE — app layer
   ============================================================ */
@media (max-width: 1023px) {
  .dt-chart-grid { grid-template-columns: minmax(0, 1fr); }
  .dt-donut-wrap { margin: 0 auto; }
}
@media (max-width: 767px) {
  .dt-svcrow { grid-template-columns: minmax(0,1fr); gap: 4px; }
  .dt-svcrow__val { text-align: left; }
  .dt-desc { max-width: none; -webkit-line-clamp: 3; line-clamp: 3; }
  .dt-notif__time { margin-left: 0; width: 100%; }
  .lr-cmd { flex-direction: column; }
  .lr-cmd > button { border-left: 0; border-top: 1px solid var(--border-secondary); padding: 9px 14px; justify-content: center; }
}
@media (max-width: 479px) {
  .dt-donut { width: 160px; height: 160px; }
  .dt-donut svg { width: 160px; height: 160px; }
  .dt-donut-pct { font-size: var(--fs-2xl); }
  .lr-grid--kpi { grid-template-columns: minmax(0, 1fr); }
  .dt-statrow   { grid-template-columns: minmax(0, 1fr); }
}

/* Print: the record should survive a greyscale printout. */
@media print {
  .lr-sidebar, .lr-mobile-header, .lr-topbar__right, .lr-pager, .lr-toasts { display: none !important; }
  .lr-main { margin-left: 0; }
  .lr-card { break-inside: avoid; }
}

/* ============================================================
   LOGRITE LOADER — the product's own wait mark
   ------------------------------------------------------------
   A faithful vanilla port of the React component at
   frontend/src/components/common/LogriteLoader.jsx, size='xl'.

   The component is six small squares, each rotate(45deg), laid out to
   draw a checkmark above a two-square base, all driven by ONE shared
   2s ease-in-out infinite keyframe with a 0.15s stagger. The six
   positions, the five keyframe percentages and both colour ramps are
   copied verbatim; only the Tailwind class names become real CSS,
   because there is no Tailwind on these pages.

     xl  =  container w-20 h-20 (5rem)  ·  square w-4 h-4 (1rem)

   Size is one custom property. The square is size/5 and every position
   is a percentage of the container, so the mark scales exactly: the
   default IS xl, and --lr-loader-size is only ever reduced where 5rem
   physically cannot fit (inside a submit button, inside a table cell).

   Colour comes from tokens, never from literals in the component rules,
   so the ramp swaps with the theme like everything else.
   ============================================================ */

:root {
  /* LIGHT ramp. The dark-theme maroon reads muddy on a white surface, so
     light uses a brighter ramp whose lightest shade still holds contrast. */
  --lr-loader-1: #B33300;
  --lr-loader-2: #B33300;
  --lr-loader-3: #B33300;
  --lr-loader-4: #E64100;
  --lr-loader-5: #FF7F4D;
  --lr-loader-6: #FFA07A;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --lr-loader-1: #802400;
    --lr-loader-2: #802400;
    --lr-loader-3: #802400;
    --lr-loader-4: #B33300;
    --lr-loader-5: #FF7F4D;
    --lr-loader-6: #FFBFA6;
  }
}

:root[data-theme="dark"] {
  --lr-loader-1: #802400;
  --lr-loader-2: #802400;
  --lr-loader-3: #802400;
  --lr-loader-4: #B33300;
  --lr-loader-5: #FF7F4D;
  --lr-loader-6: #FFBFA6;
}

:root[data-theme="light"] {
  --lr-loader-1: #B33300;
  --lr-loader-2: #B33300;
  --lr-loader-3: #B33300;
  --lr-loader-4: #E64100;
  --lr-loader-5: #FF7F4D;
  --lr-loader-6: #FFA07A;
}

.lr-loader {
  --lr-loader-size: 5rem;          /* xl: w-20 */
  position: relative;
  /* inline-block, and built from <span>/<i>, so the mark is phrasing content
     and is legal inside a <button> as well as on its own in a panel. */
  display: inline-block;
  width: var(--lr-loader-size);
  height: var(--lr-loader-size);
  flex: 0 0 auto;
  vertical-align: middle;
}

.lr-loader > i {
  position: absolute;
  display: block;
  width: calc(var(--lr-loader-size) / 5);    /* xl: w-4 = 1rem */
  height: calc(var(--lr-loader-size) / 5);
  opacity: 0;
  transform: rotate(45deg);
  /* LONGHANDS, deliberately — NOT the `animation:` shorthand.
     `.lr-loader > i` is (0,1,1) and `.lr-loader__s1` is (0,1,0), so this
     rule WINS on specificity for every property it sets. The shorthand
     sets all eight longhands, including `animation-delay: 0s`, which beat
     the per-square delays below and made all six squares pulse in unison:
     the mark blinked as one logo instead of building block by block. The
     React component has no such collision because its delay is an inline
     style. Never reintroduce the shorthand here. */
  animation-name: logrite-sequence;
  animation-duration: 2s;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}

/* The one keyframe the component defines, percentage for percentage. The
   1.3 overshoot at 20% is what closes the gaps between the squares; 1.15
   is where they settle and stay connected. */
@keyframes logrite-sequence {
  0%   { opacity: 0; transform: rotate(45deg) scale(0.9); }
  20%  { opacity: 1; transform: rotate(45deg) scale(1.3); }
  30%  {             transform: rotate(45deg) scale(1.15); }
  80%  { opacity: 1; transform: rotate(45deg) scale(1.15); }
  100% { opacity: 0; transform: rotate(45deg) scale(1.15); }
}

/* Sequence order: bottom pair, then the checkmark left-to-right.
   Explicit index classes rather than :nth-child, so the mark survives a
   caller appending anything to the container. */
.lr-loader__s1 { top: 85%; left: 23%; background: var(--lr-loader-1); animation-delay: 0s;    }
.lr-loader__s2 { top: 85%; left: 50%; background: var(--lr-loader-2); animation-delay: .15s;  }
.lr-loader__s3 { top: 28%; left: 22%; background: var(--lr-loader-3); animation-delay: .30s;  }
.lr-loader__s4 { top: 42%; left: 36%; background: var(--lr-loader-4); animation-delay: .45s;  }
.lr-loader__s5 { top: 28%; left: 50%; background: var(--lr-loader-5); animation-delay: .60s;  }
.lr-loader__s6 { top: 14%; left: 64%; background: var(--lr-loader-6); animation-delay: .75s;  }

/* ============================================================
   THE ROUND SPINNER — for buttons, note rows and status strips
   ------------------------------------------------------------
   This replaces the shrunken LogriteLoader variants that used to live here
   (1.75rem inline, 1.25rem in a button and in the status strip). The reason
   is not taste: at 1.25rem each of the mark's six squares is FOUR PIXELS, so
   the checkmark it draws at 5rem degrades into a few dots blinking on and
   off at random. It carried the product's name without its effect.

   Logrite-UI does not shrink the mark either — it has a separate centralised
   round effect for these places (`src/index.css` .loading-effect /
   .animate-spin), whose inline form is
       w-4 h-4 rounded-full border-2 border-current border-t-transparent
       animate-spin
   which is exactly what this is. currentColor means it inherits whatever
   colour the control already uses, so there is no second palette to keep in
   step with the theme.

   The LogriteLoader keeps every place it fits: the page, a panel, a card.
   ============================================================ */
.lr-spin {
  display: inline-block;
  flex: 0 0 auto;
  width: 1rem;                       /* w-4 */
  height: 1rem;
  border: 2px solid currentColor;    /* border-2 border-current */
  border-top-color: transparent;     /* border-t-transparent */
  border-radius: 9999px;             /* rounded-full */
  animation: lr-spin 1s linear infinite;
  vertical-align: middle;
}
.lr-spin--sm { width: .875rem; height: .875rem; }
.lr-spin--lg { width: 1.25rem; height: 1.25rem; }

/* The product's keyframe, verbatim. */
@keyframes lr-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  /* A frozen spinner is indistinguishable from a broken icon, and rotation
     is the only thing here saying "working". Kept, and slowed. */
  .lr-spin {
    animation: lr-spin 2s linear infinite !important;
    animation-duration: 2s !important;
    animation-iteration-count: infinite !important;
  }
}

/* The wait block: mark above its sentence, centred, laid out with gap. */
.lr-loading {
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-4);
  min-height: 10rem;
  color: var(--text-tertiary);
  font-size: var(--fs-sm);
  text-align: center;
}
.lr-loading__text { max-width: 34ch; line-height: 1.5; }

/* The whole-page first paint. The console IS a wait until its first payload
   lands, so the mark gets real vertical room rather than sitting in a corner
   of an otherwise empty page. */
.lr-loading--page { min-height: min(60vh, 28rem); }

/* Inline variant: mark beside the sentence, for a note row or a toolbar. */
.lr-loading--inline {
  flex-direction: row; gap: var(--sp-3);
  padding: 0; min-height: 0; text-align: left;
}
.lr-loading--inline .lr-loading__text { max-width: none; }

/* A wait inside a table body, so the columns do not collapse behind it. */
.lr-loading-cell { padding: var(--sp-6) var(--sp-4) !important; text-align: center; }
.lr-loading-cell .lr-loading { padding: 0; min-height: 0; }

/* REDUCED MOTION.
   The global reduce block above sets animation-iteration-count:1 and
   animation-duration:.01ms with !important, which would land every square
   on the 100% frame — opacity 0 — and leave an INVISIBLE loader. So the
   mark is made static and fully visible here, and the only movement left
   is a slow breath on the container. Later in the file and !important, so
   it beats the global rule. */
@media (prefers-reduced-motion: reduce) {
  /* The global reduce block clamps every animation to .01ms and one
     iteration, which lands all six squares on the 100% frame — opacity 0,
     an INVISIBLE loader. That has to be answered; the question is with what.

     It used to be answered with a DIFFERENT animation: static squares and a
     slow breath on the container. That fixed the invisibility and introduced
     a worse problem — this site and the console became the only surfaces in
     the product showing a mark nobody else has. LogriteLoader.jsx has no
     reduced-motion branch, so the product's loader sequences for everyone.

     So the mark is exempted from the clamp and runs the identical sequence.
     It is a 2s opacity/scale cycle on six 1rem squares: no travel, no
     parallax, and it never crosses 3Hz. */
  .lr-loader > i {
    animation-name: logrite-sequence !important;
    animation-duration: 2s !important;
    animation-timing-function: ease-in-out !important;
    animation-iteration-count: infinite !important;
  }
  .lr-loader__s1 { animation-delay: 0s    !important; }
  .lr-loader__s2 { animation-delay: .15s  !important; }
  .lr-loader__s3 { animation-delay: .30s  !important; }
  .lr-loader__s4 { animation-delay: .45s  !important; }
  .lr-loader__s5 { animation-delay: .60s  !important; }
  .lr-loader__s6 { animation-delay: .75s  !important; }
}
}

/* ============================================================
   NARROW PHONES + the sideways-scroll backstop.
   Character-for-character the same rules ops/management/static/style.css
   carries, so a 360px phone reads the same on both sites.
   ============================================================ */
@media (max-width: 479px) {
  .lr-btn-row { flex-wrap: wrap; }
  .lr-btn-row > .lr-btn { flex: 1 1 auto; justify-content: center; }
  .lr-loading { padding: var(--sp-5) var(--sp-3); }
  /* The mark does NOT shrink here. LogriteLoader at size='xl' is w-20 (5rem)
     at every viewport width; a site-only breakpoint making it 4rem is how
     one loader comes to look like two. Only the padding responds. */
  .lr-stat-row { gap: var(--sp-2); }
}

/* Every wide thing here already scrolls inside its own container; this makes
   sure a long unbroken token — a container name, a commit subject, a mount
   path — cannot be the one that gets through and takes the body with it. */
.lr-page, .lr-card, .lr-card__body, .lr-modal__body { min-width: 0; }
.lr-cell-main, .lr-cell-sub, .lr-hint, .lr-count-note,
.lr-stat__value, .lr-loading__text { overflow-wrap: anywhere; }


/* ============================================================
   FIRST-LOAD OVERLAY
   ------------------------------------------------------------
   Byte-for-byte the management console's treatment, because the two sites
   are one product and a wait that looks different reads as a different
   application. Previously this site had no page-level wait at all: the whole
   shell painted immediately and every card showed its own small loader, so
   the first second looked like a dashboard reporting nothing rather than a
   dashboard still reading.
   ============================================================ */
.lr-boot {
  position: fixed;
  background: var(--bg-primary);   /* fallback; the color-mix below wins */
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Not fully opaque: the blurred shell behind should stay readable AS a
     shape, so the page reads as "loading" and not as "navigated away". */
  background: color-mix(in srgb, var(--bg-primary) 62%, transparent);
}
.lr-boot[hidden] { display: none; }
.lr-boot__inner {
  display: flex; flex-direction: column; align-items: center; gap: 18px;
  text-align: center; padding: 24px;
}
.lr-boot__text {
  margin: 0; font-size: var(--fs-sm); color: var(--text-secondary);
  max-width: 34ch;
}

body.is-booting .lr-shell {
  filter: blur(5px);
  /* A blurred control is still clickable and still focusable, which is how
     someone tabs into a button they cannot read and fires an action against a
     host that has not loaded. Both are closed here, not just the visual. */
  pointer-events: none;
  user-select: none;
}
body.is-booting .lr-shell * { pointer-events: none !important; }

/* The blur is a transition, not a state to be endured: a reduced-motion
   reader gets the dimming without the focus pull of a blur. */
@media (prefers-reduced-motion: reduce) {
  body.is-booting .lr-shell { filter: none; opacity: .5; }
}

@supports (backdrop-filter: blur(2px)) {
  .lr-boot { backdrop-filter: blur(2px); }
}

/* ============================================================
   LOGRITE DATE PICKER — a dependency-free port of Logrite-UI's
   src/components/common/LogriteDatePicker.jsx.

   The app gets this look from react-datepicker plus ~120 lines of override.
   These consoles have no build step and no React, so the calendar is built
   by hand — but every value below is lifted from that component rather than
   re-chosen, because "looks close" is how two surfaces of one product drift
   apart. Selected day #E64100 / white, today bold orange, hover
   .375rem-radius, header on --bg-secondary, popover on --shadow-lg.

   ⚠ It replaces `<input type="date">`, whose popup is UA chrome: it cannot
   be themed, and Safari, Chrome and Firefox each render a different one.
   That is why this exists rather than a restyled native field — the native
   control looked right until it was opened.
   ============================================================ */

.lr-dp { position: relative; display: inline-flex; min-width: 0; }
.lr-dp__field {
  display: inline-flex; align-items: center; gap: var(--gap-inline);
  min-width: 0;
  padding: 7px var(--sp-3) 7px var(--sp-3);
  border: 1px solid var(--border-secondary); border-radius: var(--radius-lg);
  background: var(--bg-primary); color: var(--text-primary);
  font: inherit; font-size: var(--fs-sm); text-align: left; cursor: pointer;
  transition: border-color var(--dur-base) var(--ease),
              box-shadow var(--dur-base) var(--ease);
}
/* Filling the container is the WRAPPER's decision, not the field's. As a
   blanket `width:100%` this stretched every standalone field to the width of
   whatever flex row it was dropped into. */
.lr-dp > .lr-dp__field { width: 100%; }
.lr-dp__field:hover { border-color: var(--border-secondary); }
.lr-dp__field:focus-visible,
.lr-dp.is-open .lr-dp__field {
  outline: none;
  border-color: var(--accent-orange);
  box-shadow: 0 0 0 1px var(--accent-orange);
}
.lr-dp__icon { color: var(--text-tertiary); flex: none; }
/* The VALUE and the PLACEHOLDER are different colours — an empty bound and a
   set one must not look alike, because "no lower bound" and "the 1st" return
   very different row counts and the table gives no other clue which it used. */
.lr-dp__value { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.lr-dp__value.is-empty { color: var(--text-muted); }
/* Clear sits INSIDE the field: a bound you cannot unset without retyping is
   how a filter ends up permanently narrowed. */
.lr-dp__clear {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px; padding: 0; margin-right: -2px;
  border: 0; border-radius: var(--radius-full);
  background: none; color: var(--text-muted); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lr-dp__clear:hover { background: var(--bg-hover); color: var(--text-primary); }
.lr-dp__clear:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 1px; }

.lr-dp--sm .lr-dp__field { padding: 5px var(--sp-2); font-size: var(--fs-xs); }
/* The same size, applied to the FIELD itself. `.lr-dp--sm` is a modifier on
   the wrapper and reaches the field by descent, so a call site that renders a
   bare field with no wrapper — the tracker's date-range triggers do — gets
   the class and none of its effect. */
.lr-dp__field--sm { padding: 5px var(--sp-2); font-size: var(--fs-xs); }

/* ---- the popover ---- */
.lr-dp__pop {
  position: absolute; z-index: 60; top: calc(100% + 6px); left: 0;
  min-width: 17.5rem;
  background: var(--bg-primary);
  border: 1px solid var(--border-tertiary); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: var(--sp-3);
  animation: lr-dp-in var(--dur-fast) var(--ease-out);
}
/* Right-aligned when the field sits near the viewport edge — set in JS, not
   guessed here, because the edge depends on the sidebar's collapsed state. */
.lr-dp__pop.is-right { left: auto; right: 0; }
.lr-dp__pop[hidden] { display: none; }
@keyframes lr-dp-in { from { opacity: 0; transform: translateY(-4px); } }
@media (prefers-reduced-motion: reduce) { .lr-dp__pop { animation: none; } }

.lr-dp__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--gap-inline); padding-bottom: var(--sp-3);
}
.lr-dp__month {
  font-size: var(--fs-sm); font-weight: 600; color: var(--text-primary);
}
.lr-dp__nav {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0;
  border: 1px solid transparent; border-radius: var(--radius-md);
  background: none; color: var(--text-tertiary); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lr-dp__nav:hover:not(:disabled) { background: var(--bg-hover); color: var(--text-primary); }
.lr-dp__nav:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 1px; }
.lr-dp__nav:disabled { opacity: .35; cursor: not-allowed; }

.lr-dp__grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px;
}
.lr-dp__dow {
  font-size: var(--fs-micro); font-weight: 600; color: var(--text-tertiary);
  text-align: center; padding: var(--sp-1) 0;
}
.lr-dp__day {
  display: inline-flex; align-items: center; justify-content: center;
  height: 30px; padding: 0; border: 0; border-radius: .375rem;
  background: none; color: var(--text-secondary);
  font: inherit; font-size: var(--fs-xs); font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lr-dp__day:hover:not(:disabled):not([aria-selected="true"]) {
  background: var(--bg-hover); color: var(--text-primary);
}
.lr-dp__day:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: -2px; }
.lr-dp__day.is-outside { color: var(--text-muted); opacity: .55; }
.lr-dp__day.is-today { font-weight: 700; color: var(--accent-orange-text); }
.lr-dp__day[aria-selected="true"] {
  background: var(--accent-orange); color: #fff; font-weight: 600;
}
/* A day outside the allowed window is disabled, never hidden — a calendar
   that silently omits dates reads as a rendering fault. */
.lr-dp__day:disabled { color: var(--text-muted); opacity: .4; cursor: not-allowed; }
.lr-dp__day.is-today[aria-selected="true"] { color: #fff; }

.lr-dp__foot {
  display: flex; flex-wrap: wrap; gap: var(--sp-2);
  margin-top: var(--sp-3); padding-top: var(--sp-3);
  border-top: 1px solid var(--border-tertiary);
}
.lr-dp__preset {
  flex: 1 1 auto; padding: 5px var(--sp-2);
  border: 1px solid var(--border-tertiary); border-radius: var(--radius-md);
  background: var(--bg-secondary); color: var(--text-secondary);
  font: inherit; font-size: var(--fs-micro); font-weight: 600; cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.lr-dp__preset:hover {
  background: var(--accent-orange-bg); color: var(--accent-orange-text);
  border-color: var(--accent-orange-border);
}
.lr-dp__preset:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 1px; }

/* On a phone the popover is a centred sheet rather than an anchored card:
   17.5rem anchored to a field near the right edge overflows a 360px screen,
   and `overflow-x` on the page would let the whole console slide sideways. */
@media (max-width: 639px) {
  .lr-dp { display: flex; width: 100%; }
  .lr-dp__pop {
    position: fixed; top: 50%; left: 50%; right: auto;
    transform: translate(-50%, -50%);
    width: min(20rem, calc(100vw - 2rem));
    box-shadow: var(--shadow-modal);
  }
  .lr-dp__pop.is-right { left: 50%; right: auto; }
  .lr-dp__day { height: 34px; }
}

/* ---- the tracker's own popover shell ----
   The calendar inside is the shared `.lr-dp__*` layer; only the container
   differs, because this one is positioned by positionDatePicker() rather
   than anchored by CSS. It therefore must NOT take `.lr-dp__pop`, whose
   `position:absolute` and phone-sheet rules would fight the JS coordinates. */
.lr-datepop {
  position: fixed; z-index: 10030;
  width: 276px; padding: var(--sp-3);
  background: var(--bg-primary);
  border: 1px solid var(--border-tertiary); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  animation: lr-fade-in .12s var(--ease-out);
}
.lr-datepop[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) { .lr-datepop { animation: none; } }

/* The month/year heading doubles as the year-mode toggle: it reads as a
   title and behaves as a button. */
.lr-dp__title {
  border: 0; background: none; cursor: pointer;
  padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-md);
  font: inherit; font-size: var(--fs-sm); font-weight: 600;
  color: var(--text-primary);
  transition: background var(--dur-fast) var(--ease);
}
.lr-dp__title:hover { background: var(--bg-hover); }
.lr-dp__title:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: 1px; }

.lr-dp__years { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); }
.lr-dp__year {
  height: 34px; border: 0; border-radius: .375rem;
  background: none; color: var(--text-secondary);
  font: inherit; font-size: var(--fs-xs); font-weight: 600; cursor: pointer;
  font-variant-numeric: tabular-nums;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.lr-dp__year:hover:not([aria-selected="true"]) { background: var(--bg-hover); color: var(--text-primary); }
.lr-dp__year[aria-selected="true"] { background: var(--accent-orange); color: #fff; }
.lr-dp__year:focus-visible { outline: 2px solid var(--accent-orange); outline-offset: -2px; }

/* This file marks the chosen day with `aria-current="page"`; the management
   console uses `aria-selected`. Both are honoured so the one stylesheet block
   serves both call sites — the alternative is a day that is selected in the
   model and unmarked on screen. */
.lr-dp__day[aria-current="page"] {
  background: var(--accent-orange); color: #fff; font-weight: 600;
}
.lr-dp__day.is-today[aria-current="page"] { color: #fff; }

/* ============================================================
   CUSTOM DROPDOWN (.lr-dd) — SHARED WITH management.logrite.ai.
   ------------------------------------------------------------
   The same component, duplicated on purpose: the two sites have no
   build step and no shared import, so a design layer is kept in step
   by a test rather than by a module. test_design_parity.js compares
   both stylesheets.

   Why it exists at all: `appearance: none` restyles the CLOSED box of
   a <select> and nothing else. The open list is an operating-system
   menu — it ignores the theme, the radius, the type scale and the
   focus ring, so on a dark console macOS drew a light popup in a
   different font. This site's two pickers (the table filters and the
   16-entry service registry) were the last native chrome left.
   ============================================================ */
.lr-dd { position: relative; display: inline-flex; min-width: 0; }
.lr-dd--block { display: flex; width: 100%; }

/* The trigger mirrors .lr-input exactly — same 2px resting border, so a
   dropdown and a text box on one toolbar row are the same height to the
   pixel. They were not before: the select's own arrow box added 2px. */
.lr-dd__btn {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  width: 100%; min-width: 0;
  padding: 8px 12px; border-radius: var(--radius-lg);
  font: inherit; font-size: var(--fs-sm); line-height: 1.25rem; font-weight: 500;
  text-align: left;
  background: var(--bg-secondary); color: var(--text-primary);
  border: 2px solid var(--border-secondary); cursor: pointer;
  transition: border-color var(--dur-slow) var(--ease),
              background-color var(--dur-slow) var(--ease);
}
.lr-dd__btn:hover:not(:disabled) { border-color: var(--accent-orange); }
.lr-dd__btn:focus-visible {
  border-color: var(--accent-orange);
  outline: 2px solid rgba(230,65,0,.35); outline-offset: 1px;
}
.lr-dd__btn:disabled { opacity: .55; cursor: not-allowed; }
.lr-dd.is-open .lr-dd__btn { border-color: var(--accent-orange); }
.lr-dd__value { flex: 1 1 auto; min-width: 0; overflow: hidden;
                text-overflow: ellipsis; white-space: nowrap; }
.lr-dd__value.is-placeholder { color: var(--text-muted); font-weight: 400; }
.lr-dd__caret {
  flex: 0 0 auto; color: var(--text-muted);
  transition: transform var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.lr-dd.is-open .lr-dd__caret { transform: rotate(180deg); color: var(--accent-orange); }

.lr-dd--sm .lr-dd__btn { padding: 3px 8px; font-size: var(--fs-xs); gap: var(--sp-1); }

/* The popup. Fixed-positioned and placed by script, for the same reason
   the combobox list is: a toolbar with `overflow: hidden` anywhere in its
   ancestry clips an absolutely-positioned menu, and the clip is invisible
   until the one row you need is the one that got cut. */
.lr-dd__pop {
  position: fixed; z-index: 90; min-width: 9rem;
  max-height: 17rem; overflow-y: auto; overscroll-behavior: contain;
  padding: var(--sp-1); margin: 0;
  list-style: none;
  background: var(--bg-primary);
  border: 1px solid var(--border-secondary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-menu);
  animation: lr-dd-in var(--dur-fast) var(--ease-out);
  scrollbar-width: thin;
}
@keyframes lr-dd-in { from { opacity: 0; transform: translateY(-4px); } }
.lr-dd__opt {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 7px var(--sp-3); border-radius: var(--radius-md);
  font-size: var(--fs-sm); color: var(--text-secondary);
  cursor: pointer; white-space: nowrap;
}
.lr-dd__opt:hover, .lr-dd__opt.is-active {
  background: var(--bg-tertiary); color: var(--text-primary);
}
.lr-dd__opt[aria-selected="true"] {
  color: var(--accent-orange-text); font-weight: 600;
  background: var(--accent-orange-bg);
}
.lr-dd__opt[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
/* The tick reserves its width whether or not it is drawn, so choosing a
   different option does not shift every label 20px sideways. */
.lr-dd__tick { flex: 0 0 auto; width: 14px; height: 14px; opacity: 0; }
.lr-dd__opt[aria-selected="true"] .lr-dd__tick { opacity: 1; }
.lr-dd__label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.lr-dd__empty {
  padding: var(--sp-3); font-size: var(--fs-xs); color: var(--text-muted);
  text-align: center;
}
@media (prefers-reduced-motion: reduce) {
  .lr-dd__pop { animation: none; }
  .lr-dd__caret { transition: none; }
}

/* GROUP HEADINGS. The service picker is a registry grouped by category —
   an <optgroup> in a native select, and the one piece of native chrome
   this listbox has to REPRODUCE rather than merely restyle. Marked
   presentational because a heading is not a selectable option: counted as
   one, the arrow keys would stop on it and a screen reader would announce
   "option, Infrastructure" as something you can choose. */
.lr-dd__group {
  padding: var(--sp-3) var(--sp-3) var(--sp-1);
  font-size: var(--fs-nano); font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--text-tertiary);
}
.lr-dd__group:first-child { padding-top: var(--sp-1); }
