@layer tokens, reset, base, components, utilities, responsive;

@layer reset {

html {
    background: var(--sp-bg-base);
    color: var(--sp-text-primary);
}

html,
body {
    margin: 0;
    font-family: var(--sp-font-family);
}

[hidden] {
    display: none;
}

}

@layer tokens {

/* Identity colour is a wheel spun from the brand accent, not a palette of its
   own: every tone keeps the accent's lightness band and rotates its hue by a
   fixed step, so a white-label theme that moves --sp-accent moves all twelve
   tones with it and they still read as one family. The lightness is pinned
   to the value --sp-accent-fill measured at 5.3:1 under --sp-text-on-accent,
   so the monogram clears AA on every hue; chroma is held below the accent's
   so no tone outshouts the brand red it sits beside. */
:root {
    --sp-avatar-tone-0:  oklch(from var(--sp-accent) 0.535 0.135 h);
    --sp-avatar-tone-1:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 30));
    --sp-avatar-tone-2:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 60));
    --sp-avatar-tone-3:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 90));
    --sp-avatar-tone-4:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 120));
    --sp-avatar-tone-5:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 150));
    --sp-avatar-tone-6:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 180));
    --sp-avatar-tone-7:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 210));
    --sp-avatar-tone-8:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 240));
    --sp-avatar-tone-9:  oklch(from var(--sp-accent) 0.535 0.135 calc(h + 270));
    --sp-avatar-tone-10: oklch(from var(--sp-accent) 0.535 0.135 calc(h + 300));
    --sp-avatar-tone-11: oklch(from var(--sp-accent) 0.535 0.135 calc(h + 330));
}

}

@layer tokens {
:root {
    --sp-chart-purple: oklch(0.55 0.22 295);
    --sp-chart-blue:   oklch(0.62 0.18 260);
    --sp-chart-green:  oklch(0.69 0.17 165);
    --sp-chart-amber:  oklch(0.76 0.16 75);
    --sp-chart-red:    oklch(0.63 0.21 25);
    --sp-chart-cyan:   oklch(0.72 0.12 200);
    --sp-chart-indigo: oklch(0.57 0.18 280);

    --sp-progress-green-from: oklch(0.69 0.17 165);
    --sp-progress-green-to:   oklch(0.78 0.16 165);
    --sp-progress-amber-from: oklch(0.76 0.16 75);
    --sp-progress-amber-to:   oklch(0.83 0.16 85);
    --sp-progress-red-from:   oklch(0.63 0.21 25);
    --sp-progress-red-to:     oklch(0.70 0.17 20);

    /* Sidebar group labels sit on --sp-sidebar-bg at 11px uppercase, so every
       one of them is body text for contrast purposes and clears 4.5:1 there. */
    --sp-nav-label-1: oklch(0.535 0.130 52);
    --sp-nav-label-2: oklch(0.535 0.110 300);
    --sp-nav-label-3: oklch(0.520 0.095 255);
    --sp-nav-label-4: oklch(0.515 0.115 160);
    --sp-nav-label-5: oklch(0.530 0.105 85);
    --sp-nav-label-6: oklch(0.525 0.110 200);

    --sp-feed-purple: oklch(0.55 0.22 295);
    --sp-feed-cyan:   oklch(0.72 0.12 200);
    --sp-feed-indigo: oklch(0.57 0.18 280);
    --sp-feed-gold:   oklch(0.76 0.16 75);
    --sp-badge-purple: oklch(0.68 0.16 295);
    --sp-badge-purple-dim: color-mix(in oklch, oklch(0.68 0.16 295) 15%, transparent);

    --sp-rank-tier-1-color: oklch(0.72 0.03 250);
    --sp-rank-tier-1-bg:    oklch(0.50 0.03 250);
    --sp-rank-tier-2-color: oklch(0.70 0.14 250);
    --sp-rank-tier-2-bg:    oklch(0.55 0.14 250);
    --sp-rank-tier-3-color: oklch(0.78 0.16 165);
    --sp-rank-tier-3-bg:    oklch(0.58 0.16 165);
    --sp-rank-tier-4-color: oklch(0.68 0.16 295);
    --sp-rank-tier-4-bg:    oklch(0.55 0.16 295);
    --sp-rank-tier-5-color: oklch(0.76 0.16 75);
    --sp-rank-tier-5-bg:    oklch(0.56 0.16 75);
    --sp-rank-tier-6-color: oklch(0.65 0.20 345);
    --sp-rank-tier-6-bg:    oklch(0.52 0.18 345);
    --sp-rank-tier-7-color: oklch(0.70 0.18 45);
    --sp-rank-tier-7-bg:    oklch(0.55 0.18 45);
    --sp-rank-tier-8-color: oklch(0.55 0.22 295);
    --sp-rank-tier-8-bg:    oklch(0.45 0.20 295);
    --sp-rank-tier-9-color: oklch(0.72 0.12 200);
    --sp-rank-tier-9-bg:    oklch(0.52 0.14 200);
    --sp-rank-tier-10-color: oklch(0.82 0.17 95);
    --sp-rank-tier-10-bg:    oklch(0.58 0.17 95);

    --sp-rank-1-color: var(--sp-rank-tier-1-color);
    --sp-rank-2-color: var(--sp-rank-tier-1-color);
    --sp-rank-3-color: var(--sp-rank-tier-2-color);
    --sp-rank-4-color: var(--sp-rank-tier-2-color);
    --sp-rank-5-color: var(--sp-rank-tier-3-color);
    --sp-rank-6-color: var(--sp-rank-tier-3-color);
    --sp-rank-7-color: var(--sp-rank-tier-4-color);
    --sp-rank-8-color: var(--sp-rank-tier-5-color);
    --sp-rank-9-color: var(--sp-rank-tier-6-color);
    --sp-rank-10-color: var(--sp-rank-tier-7-color);
    --sp-rank-1-bg: var(--sp-rank-tier-1-bg);
    --sp-rank-2-bg: var(--sp-rank-tier-1-bg);
    --sp-rank-3-bg: var(--sp-rank-tier-2-bg);
    --sp-rank-4-bg: var(--sp-rank-tier-2-bg);
    --sp-rank-5-bg: var(--sp-rank-tier-3-bg);
    --sp-rank-6-bg: var(--sp-rank-tier-3-bg);
    --sp-rank-7-bg: var(--sp-rank-tier-4-bg);
    --sp-rank-8-bg: var(--sp-rank-tier-5-bg);
    --sp-rank-9-bg: var(--sp-rank-tier-6-bg);
    --sp-rank-10-bg: var(--sp-rank-tier-7-bg);
    --sp-rank-1-ladder-bg: var(--sp-rank-tier-1-bg);
    --sp-rank-3-ladder-bg: var(--sp-rank-tier-2-bg);
    --sp-rank-5-ladder-bg: var(--sp-rank-tier-3-bg);
    --sp-rank-7-ladder-bg: var(--sp-rank-tier-4-bg);
    --sp-rank-10-ladder-bg: var(--sp-rank-tier-7-bg);

    --sp-rarity-epic-bg: color-mix(in oklch, oklch(0.60 0.20 295) 15%, transparent);
    --sp-rarity-epic-fg: oklch(0.65 0.20 295);

    --sp-badge-accent-bg: color-mix(in oklch, var(--sp-accent) 8%, var(--sp-bg-surface));
    --sp-badge-accent-fg: var(--sp-accent-hover);
    --sp-badge-warning-bg: color-mix(in oklch, var(--sp-warning) 8%, var(--sp-bg-surface));
    --sp-badge-warning-fg: oklch(0.52 0.10 80);
    --sp-badge-danger-bg: color-mix(in oklch, var(--sp-danger) 8%, var(--sp-bg-surface));
    --sp-badge-danger-fg: oklch(0.48 0.12 20);
}
}

@layer tokens {

/* Compact is the default because this is an operations console: the target is
   roughly 24 table rows on a 900px viewport with the page header, KPI row and
   toolbar all still above the fold. html[data-density="comfortable"] is
   reserved for a future per-user preference and changes nothing else. */

:root {
    --sp-gutter: var(--sp-space-6);

    --sp-density-row: 2rem;
    --sp-density-cell-y: 0.375rem;
    /* The line box inside a data cell. Every inline control in a row is sized
       to it, so a row is padding plus one line and nothing else. */
    --sp-density-cell-line: 1.25rem;
    --sp-density-cell-x: 0.75rem;
    --sp-density-tile: 0.75rem;
    --sp-density-tile-h: 4.75rem;
    /* The ceiling on a text cell. Wide enough that a name or a description is
       usually whole, narrow enough that one long value cannot take the table. */
    --sp-table-cell-max: 22ch;
    --sp-density-gap: 0.75rem;
    --sp-density-section: 1.25rem;

    --sp-z-sticky: 1;
    --sp-z-sticky-header: 3;
    /* Raised sits above sibling page blocks (an open filter pill panel) but
       below the topbar, so an in-page popover never covers the bar's menus. */
    --sp-z-raised: 5;
    --sp-z-topbar: 10;
    --sp-z-sidebar: 900;
    --sp-z-sidebar-drawer: 950;
    --sp-z-dropdown: 1000;
    --sp-z-panel: 1100;
    --sp-z-modal-backdrop: 1400;
    --sp-z-modal: 1500;
    --sp-z-lightbox: 2000;
    --sp-z-toast: 2500;

    --sp-overlay-light:  color-mix(in oklch, var(--sp-shadow-color) 30%, transparent);
    --sp-overlay-medium: color-mix(in oklch, var(--sp-shadow-color) 50%, transparent);
    --sp-overlay-heavy:  color-mix(in oklch, var(--sp-shadow-color) 70%, transparent);
}

html[data-density="comfortable"] {
    --sp-density-row: 2.5rem;
    --sp-density-cell-y: 0.625rem;
    --sp-density-cell-line: 1.5rem;
    --sp-density-cell-x: 1rem;
    --sp-density-tile: 1rem;
    --sp-density-tile-h: 5.5rem;
    --sp-table-cell-max: 28ch;
    --sp-density-gap: 1rem;
    --sp-density-section: 1.75rem;
}

@media (max-width: 64rem) {
    :root { --sp-gutter: var(--sp-space-4); }
}

/* Phones get taller rows and looser cell lines because a thumb, not a
   pointer, is the input: 44px targets and wrapped values need the room, and
   the desktop fold budget no longer applies once tables become cards. */
@media (max-width: 48rem) {
    :root {
        --sp-gutter: var(--sp-space-3);
        --sp-density-row: 2.75rem;
        --sp-density-cell-y: 0.5rem;
        --sp-density-cell-line: 1.5rem;
        --sp-density-tile-h: 5.25rem;
        --sp-density-gap: 0.5rem;
        --sp-density-section: 1rem;
    }
}

}

@layer tokens {

/* The brand and warm ramps are the only literal colours in the product. Every
   accent, surface, border and status value elsewhere is a color-mix() on one of
   them, so a white-label theme moves the whole system by reassigning this file. */

:root {
  --sp-primitive-brand-50:  oklch(0.985 0 0);
  --sp-primitive-brand-100: oklch(0.970 0 0);
  --sp-primitive-brand-200: oklch(0.922 0 0);
  --sp-primitive-brand-300: oklch(0.870 0 0);
  --sp-primitive-brand-400: oklch(0.715 0 0);
  --sp-primitive-brand-500: oklch(0.439 0 0);
  --sp-primitive-brand-600: oklch(0.371 0 0);
  --sp-primitive-brand-700: oklch(0.187 0.110 269.0);
  --sp-primitive-brand-800: oklch(0.165 0.095 269.5);
  --sp-primitive-brand-900: oklch(0.145 0.081 270.4);
  --sp-primitive-brand-950: oklch(0.110 0.060 270.4);

  --sp-primitive-warm-50:  var(--sp-primitive-brand-50);
  --sp-primitive-warm-100: var(--sp-primitive-brand-100);
  --sp-primitive-warm-200: var(--sp-primitive-brand-200);
  --sp-primitive-warm-300: var(--sp-primitive-brand-300);
  --sp-primitive-warm-400: var(--sp-primitive-brand-300);
  --sp-primitive-warm-500: var(--sp-primitive-brand-400);
  --sp-primitive-warm-600: var(--sp-primitive-brand-500);
  --sp-primitive-warm-700: var(--sp-primitive-brand-600);
  --sp-primitive-warm-800: var(--sp-primitive-brand-700);
  --sp-primitive-warm-900: var(--sp-primitive-brand-700);
  --sp-primitive-warm-950: var(--sp-primitive-brand-900);

  --sp-primitive-accent-navy: oklch(0.265 0.183 264.4);
  --sp-primitive-accent-purple: oklch(0.490 0.263 298.9);
  --sp-primitive-white: oklch(1 0 0);
  --sp-primitive-black: oklch(0 0 0);

  --sp-primitive-green-500:  oklch(0.727 0.194 149);
  --sp-primitive-green-400:  oklch(0.78 0.16 165);
  --sp-primitive-green-300:  oklch(0.80 0.18 155);
  --sp-primitive-amber-500:  oklch(0.823 0.157 82);
  --sp-primitive-amber-400:  oklch(0.76 0.16 75);
  --sp-primitive-red-500:    oklch(0.637 0.208 25);
  --sp-primitive-red-400:    oklch(0.70 0.17 20);
  --sp-primitive-blue-500:   oklch(0.623 0.214 259);
  --sp-primitive-blue-400:   oklch(0.70 0.14 250);

  --sp-primitive-accent-blue:         oklch(0.70 0.14 250);
  --sp-primitive-accent-blue-light:   oklch(0.78 0.10 255);
  --sp-primitive-accent-purple:       oklch(0.552 0.277 302.4);
  --sp-primitive-accent-purple-light: oklch(0.80 0.12 300);
  --sp-primitive-accent-green:        oklch(0.80 0.18 155);
  --sp-primitive-accent-green-light:  oklch(0.88 0.14 155);
  --sp-primitive-accent-pink:         oklch(0.70 0.17 350);
  --sp-primitive-accent-pink-light:   oklch(0.80 0.12 350);
  --sp-primitive-accent-cyan:         oklch(0.79 0.13 200);
  --sp-primitive-accent-cyan-light:   oklch(0.87 0.10 200);
}

}

@layer tokens {

/* The data tier (2xs/sm) is sized for tables and tile labels, not prose: 11px
   uppercase headers and 13px cell text are what keep 24 rows on a 900px
   viewport without the type reading as shrunken body copy. */

:root {
  --sp-text-2xs:  0.6875rem;
  --sp-text-xs:   0.75rem;
  --sp-text-sm:   0.8125rem;
  --sp-text-base: 0.875rem;
  --sp-text-md:   0.9375rem;
  --sp-text-lg:   1.0625rem;
  --sp-text-xl:   1.25rem;
  --sp-text-2xl:  1.5rem;
  --sp-text-3xl:  1.875rem;
  --sp-text-4xl:  2.25rem;
  --sp-text-kpi:  clamp(1.375rem, 1.1rem + 0.9vw, 1.875rem);

  --sp-leading-tight:   1.1;
  --sp-leading-snug:    1.25;
  --sp-leading-normal:  1.45;
  --sp-leading-relaxed: 1.625;

  --sp-tracking-tight:  -0.02em;
  --sp-tracking-normal: 0;
  --sp-tracking-wide:   0.06em;

  --sp-font-normal:   400;
  --sp-font-medium:   500;
  --sp-font-semibold: 600;
  --sp-font-bold:     700;

  --sp-space-05: 0.125rem;
  --sp-space-1:  0.25rem;
  --sp-space-15: 0.375rem;
  --sp-space-2:  0.5rem;
  --sp-space-3:  0.75rem;
  --sp-space-4:  1rem;
  --sp-space-5:  1.25rem;
  --sp-space-6:  1.5rem;
  --sp-space-7:  1.75rem;
  --sp-space-8:  2rem;
  --sp-space-10: 2.5rem;
  --sp-space-12: 3rem;
  --sp-space-16: 4rem;
  --sp-space-20: 5rem;
  --sp-space-24: 6rem;
  --sp-space-32: 8rem;

  --sp-radius-xs:   0.125rem;
  --sp-radius-sm:   0.375rem;
  --sp-radius-md:   0.625rem;
  --sp-radius-lg:   0.875rem;
  --sp-radius-xl:   1.125rem;
  --sp-radius-full: 9999px;

  --sp-corners-sm: var(--sp-radius-sm) calc(var(--sp-radius-sm) / 4) var(--sp-radius-sm) var(--sp-radius-sm);
  --sp-corners-md: var(--sp-radius-md) calc(var(--sp-radius-md) / 4) var(--sp-radius-md) var(--sp-radius-md);
  --sp-corners-lg: var(--sp-radius-lg) calc(var(--sp-radius-lg) / 4) var(--sp-radius-lg) var(--sp-radius-lg);
  --sp-corners-xl: var(--sp-radius-xl) calc(var(--sp-radius-xl) / 4) var(--sp-radius-xl) var(--sp-radius-xl);
  --sp-corners-inner-sm: var(--sp-radius-xs) calc(var(--sp-radius-xs) / 4) var(--sp-radius-xs) var(--sp-radius-xs);
  --sp-corners-inner-md: var(--sp-radius-sm) calc(var(--sp-radius-sm) / 4) var(--sp-radius-sm) var(--sp-radius-sm);
  --sp-corners-inner-lg: var(--sp-radius-md) calc(var(--sp-radius-md) / 4) var(--sp-radius-md) var(--sp-radius-md);

  --sp-duration-instant:  50ms;
  --sp-duration-micro:    80ms;
  --sp-duration-fast:     100ms;
  --sp-duration-normal:   200ms;
  --sp-duration-moderate: 300ms;
  --sp-duration-slow:     400ms;
  --sp-duration-slower:   600ms;

  --sp-ease-default: ease-out;
  --sp-ease-in:      ease-in;
  --sp-ease-out:     ease-out;
  --sp-ease-in-out:  ease-in-out;
  --sp-ease-bounce:  cubic-bezier(0.34, 1.56, 0.64, 1);
  --sp-ease-spring:  cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

/* 11px labels are legible on a desktop monitor at arm's length but not on a
   phone held in the hand, so the smallest tier steps up to 12px there. */
@media (max-width: 48rem) {
  :root { --sp-text-2xs: 0.75rem; }
}

}

@layer tokens {

:root {
    color-scheme: light;

    --sp-font-family: "Readex Pro", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    --sp-font-body: var(--sp-font-family);
    --sp-font-heading: var(--sp-font-family);
    --sp-font-brand: var(--sp-font-family);
    --sp-font-mono: "Roboto Mono", "SF Mono", "Cascadia Code", "Fira Code", monospace;

    --sp-primary-50:  var(--sp-primitive-brand-50);
    --sp-primary-100: var(--sp-primitive-brand-100);
    --sp-primary-200: var(--sp-primitive-brand-200);
    --sp-primary-300: var(--sp-primitive-brand-300);
    --sp-primary-400: var(--sp-primitive-brand-400);
    --sp-primary-500: var(--sp-primitive-brand-500);
    --sp-primary-600: var(--sp-primitive-brand-600);
    --sp-primary-700: var(--sp-primitive-brand-700);
    --sp-primary-800: var(--sp-primitive-brand-800);
    --sp-primary-900: var(--sp-primitive-brand-900);
    --sp-primary-950: var(--sp-primitive-brand-950);

    --sp-warm-50:  var(--sp-primitive-warm-50);
    --sp-warm-100: var(--sp-primitive-warm-100);
    --sp-warm-200: var(--sp-primitive-warm-200);
    --sp-warm-300: var(--sp-primitive-warm-300);
    --sp-warm-400: var(--sp-primitive-warm-400);
    --sp-warm-500: var(--sp-primitive-warm-500);
    --sp-warm-600: var(--sp-primitive-warm-600);
    --sp-warm-700: var(--sp-primitive-warm-700);
    --sp-warm-800: var(--sp-primitive-warm-800);
    --sp-warm-900: var(--sp-primitive-warm-900);
    --sp-warm-950: var(--sp-primitive-warm-950);

    --sp-bg-base:            var(--sp-primitive-brand-100);
    --sp-bg-canvas:          var(--sp-primitive-brand-50);
    --sp-bg-surface:         var(--sp-primitive-white);
    --sp-bg-surface-raised:  var(--sp-primitive-white);
    --sp-bg-surface-overlay: var(--sp-primitive-white);
    --sp-bg-surface-alt:     var(--sp-primitive-brand-50);
    --sp-bg-input:           var(--sp-primitive-white);
    --sp-bg-tertiary:        var(--sp-primitive-brand-100);
    --sp-bg-main:            var(--sp-primitive-brand-100);

    --sp-border-subtle:  color-mix(in oklch, var(--sp-primitive-brand-700) 8%, transparent);
    --sp-border-default: var(--sp-primitive-brand-200);
    --sp-border-strong:  var(--sp-primitive-brand-300);

    /* 4.5:1 body minimum, measured against --sp-bg-base rather than the white
       card: the footer and the muted badge sit on the page ground, and a value
       that clears 4.5 only on white fails everywhere else. On --sp-bg-base
       --sp-text-primary measures 14.5:1, --sp-text-secondary 8.2:1 and
       --sp-text-tertiary 4.8:1. --sp-text-disabled is 2.4:1 and therefore never
       carries meaning on its own.

       The tone text values below are measured the same way: each against its
       own 12-14% tint composited over --sp-bg-base, the darkest ground a badge
       lands on. The lowest in the family is 4.8:1. They are separate from the
       tone fills because a fill that reads well as a 2px bar is far too light
       to be 11px text on a tint of itself. */
    --sp-text-primary:   var(--sp-primitive-brand-700);
    --sp-text-secondary: var(--sp-primitive-brand-500);
    --sp-text-tertiary:  oklch(0.520 0 0);
    --sp-text-disabled:  var(--sp-primitive-brand-300);
    --sp-text-on-accent: var(--sp-primitive-white);
    --sp-text-on-dark:   var(--sp-primitive-brand-50);

    --sp-interactive:   var(--sp-primitive-accent-navy);
    --sp-accent:        var(--sp-primitive-accent-navy);
    --sp-accent-hover:  var(--sp-primitive-accent-purple);
    /* Dynapps CTAs are a navy fill that turns purple on hover; the logo's
       red-orange gradient stays in the mark and never reaches a control. Navy
       clears 4.5:1 as text and behind --sp-text-on-accent on every ground, so
       --sp-accent-text and --sp-accent-fill are the brand value itself. */
    --sp-accent-text:   var(--sp-primitive-accent-navy);
    --sp-accent-fill:   var(--sp-primitive-accent-navy);
    --sp-accent-dim:    color-mix(in oklch, var(--sp-accent) 10%, transparent);
    --sp-accent-strong: color-mix(in oklch, var(--sp-accent) 18%, transparent);
    --sp-accent-surface: color-mix(in oklch, var(--sp-accent) 6%, var(--sp-bg-surface));

    --sp-success: var(--sp-primitive-green-500);
    --sp-success-dim: color-mix(in oklch, var(--sp-success) 14%, transparent);
    --sp-success-strong: oklch(0.480 0.120 149);

    --sp-warning: var(--sp-primitive-amber-500);
    --sp-warning-dim: color-mix(in oklch, var(--sp-warning) 14%, transparent);
    --sp-warning-strong: oklch(0.500 0.100 82);
    --sp-bg-warning: color-mix(in oklch, var(--sp-warning) 10%, var(--sp-bg-surface));

    --sp-info: var(--sp-primitive-blue-500);
    --sp-info-strong: oklch(0.500 0.140 259);
    --sp-danger: var(--sp-primitive-red-500);
    --sp-danger-dim: color-mix(in oklch, var(--sp-danger) 12%, transparent);
    --sp-danger-strong: oklch(0.505 0.140 25);
    --sp-border-primary: color-mix(in oklch, var(--sp-accent) 30%, var(--sp-border-default));

    --sp-focus-ring: color-mix(in oklch, var(--sp-accent) 55%, transparent);

    --sp-sidebar-bg: var(--sp-primitive-brand-50);
    --sp-sidebar-border: var(--sp-primitive-brand-200);
    --sp-sidebar-text: var(--sp-primitive-brand-500);
    --sp-sidebar-text-muted: var(--sp-primitive-brand-400);
    --sp-sidebar-text-hover: var(--sp-primitive-brand-700);
    --sp-sidebar-hover-bg: var(--sp-primitive-brand-100);
    --sp-sidebar-active-bg: color-mix(in oklch, var(--sp-accent) 8%, transparent);
    --sp-sidebar-active-color: var(--sp-accent-text);

    --sp-section-dashboard: var(--sp-accent);
    --sp-section-users:     oklch(0.55 0.22 295);
    --sp-section-plugins:   var(--sp-info);
    --sp-section-skills:    var(--sp-success);
    --sp-section-export:    var(--sp-warning);
    --sp-section-audit:     var(--sp-danger);
    --sp-section-dashboard-dim: color-mix(in oklch, var(--sp-section-dashboard) 14%, transparent);
    --sp-section-users-dim: color-mix(in oklch, var(--sp-section-users) 14%, transparent);
    --sp-section-plugins-dim: color-mix(in oklch, var(--sp-section-plugins) 14%, transparent);
    --sp-section-skills-dim: color-mix(in oklch, var(--sp-section-skills) 14%, transparent);
    --sp-section-export-dim: color-mix(in oklch, var(--sp-section-export) 14%, transparent);
    --sp-section-audit-dim: color-mix(in oklch, var(--sp-section-audit) 14%, transparent);
    --sp-section-color: var(--sp-accent);

    /* The federated-identity button must carry the provider's own brand blue;
       it is the one colour in the product we do not get to choose. */
    --sp-sso-brand: oklch(0.663 0.147 235);
    --sp-sso-brand-hover: color-mix(in oklch, var(--sp-sso-brand) 88%, var(--sp-primitive-black));
}

}

@layer tokens {

/* Every shadow is the same hue at a different opacity. A dark theme changes
   --sp-shadow-color once rather than re-authoring eighteen shadow stacks. */

:root {
    --sp-shadow-color: var(--sp-primitive-brand-700);
    --sp-shadow-a04: color-mix(in oklch, var(--sp-shadow-color) 4%, transparent);
    --sp-shadow-a07: color-mix(in oklch, var(--sp-shadow-color) 7%, transparent);
    --sp-shadow-a10: color-mix(in oklch, var(--sp-shadow-color) 10%, transparent);

    --sp-shadow-xs: 0 1px 2px var(--sp-shadow-a04);
    --sp-shadow-sm: 0 1px 3px var(--sp-shadow-a07), 0 1px 2px var(--sp-shadow-a04);
    --sp-shadow-md: 0 4px 8px var(--sp-shadow-a07), 0 2px 4px var(--sp-shadow-a04);
    --sp-shadow-lg: 0 10px 25px var(--sp-shadow-a10), 0 4px 10px var(--sp-shadow-a07);
    --sp-shadow-xl: 0 20px 40px var(--sp-shadow-a10), 0 8px 16px var(--sp-shadow-a07);
    --sp-shadow-inset-sm: inset 0 1px 2px var(--sp-shadow-a04);
    --sp-shadow-card: 0 1px 2px var(--sp-shadow-a04), 0 0 0 1px var(--sp-shadow-a07);
    --sp-shadow-card-hover: 0 1px 2px var(--sp-shadow-a07), 0 0 0 1px var(--sp-shadow-a10);
    --sp-shadow-elevated: 0 4px 16px var(--sp-shadow-a10), 0 2px 6px var(--sp-shadow-a07), 0 0 1px var(--sp-shadow-a10);
    --sp-shadow-float: 0 12px 40px var(--sp-shadow-a10), 0 4px 12px var(--sp-shadow-a07);
    --sp-shadow-drawer-panel: -8px 0 32px -12px var(--sp-shadow-a10);
    --sp-shadow-login-card: 0 8px 32px var(--sp-shadow-a10), 0 2px 8px var(--sp-shadow-a07);
    --sp-text-shadow-badge: 0 1px 2px var(--sp-shadow-a10);
    --sp-shadow-accent-sm: 0 2px 8px color-mix(in oklch, var(--sp-accent) 16%, transparent);
    --sp-shadow-accent-md: 0 4px 16px color-mix(in oklch, var(--sp-accent) 20%, transparent);
    --sp-shadow-inner-glow: none;
    --sp-shadow-hero: var(--sp-shadow-card);
    --sp-shadow-lift: 0 6px 20px var(--sp-shadow-a10), 0 2px 6px var(--sp-shadow-a07), 0 0 0 1px var(--sp-shadow-a04);
    --sp-shadow-focus-inset: inset 2px 0 0 var(--sp-accent), 0 0 0 1px var(--sp-accent);
}

}

@layer tokens {

:root {
    --sp-bg-surface-gradient: var(--sp-bg-surface);
    --sp-bg-surface-raised-gradient: var(--sp-bg-surface);
    --sp-bg-card-header: var(--sp-primitive-brand-50);
    --sp-bg-accent-wash: linear-gradient(135deg, color-mix(in oklch, var(--sp-accent) 6%, var(--sp-primitive-brand-50)) 0%, var(--sp-primitive-brand-50) 100%);
    --sp-bg-main-gradient: var(--sp-bg-main);
    --sp-bg-main-accent-tl: none;
    --sp-bg-main-accent-br: none;
    --sp-bg-glass: color-mix(in oklch, var(--sp-primitive-white) 78%, transparent);
    --sp-bg-glass-border: var(--sp-border-subtle);
    --sp-bg-hero-gradient: var(--sp-bg-surface);

    --sp-scrollbar-width: 6px;
    --sp-scrollbar-track: transparent;
    --sp-scrollbar-thumb: var(--sp-warm-300);
    --sp-scrollbar-thumb-hover: var(--sp-warm-400);
    --sp-sidebar-control-bg: var(--sp-primitive-brand-200);
    --sp-sidebar-control-bg-hover: var(--sp-primitive-brand-300);
    --sp-sidebar-scrollbar-thumb: var(--sp-primitive-brand-300);
    --sp-sidebar-edge-line: var(--sp-shadow-a04);
    --sp-sidebar-brand-glow: var(--sp-shadow-a04);
    --sp-drawer-overlay: color-mix(in oklch, var(--sp-shadow-color) 32%, transparent);
    --sp-login-glow: var(--sp-accent);
    --sp-toggle-knob: var(--sp-primitive-white);
    --sp-shimmer-from: var(--sp-warm-100);
    --sp-shimmer-via:  var(--sp-warm-50);
    --sp-shimmer-to:   var(--sp-warm-100);

}

}

@layer reset {

*, *::before, *::after { box-sizing: border-box; }

html {
    background: var(--sp-bg-base);
    color: var(--sp-text-primary);
    overflow-x: hidden;
}

html, body {
    margin: 0;
    font-family: var(--sp-font-family);
}

body {
    color: var(--sp-text-primary);
    background: var(--sp-bg-base);
    font-size: var(--sp-text-base);
    line-height: var(--sp-leading-normal);
    /* Clip, not hidden: with the root already clipping sideways overflow, a
       hidden body becomes its own scroll container and the sticky topbar then
       tracks the body instead of the viewport, so it never sticks. */
    overflow-x: clip;
}

[hidden] { display: none; }

:focus-visible {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
}

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

}

@layer components {

.sp-admin-footer {
    padding: var(--sp-space-4) var(--sp-space-10);
    border-top: 1px solid var(--sp-sidebar-border);
    text-align: center;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    flex-shrink: 0;
}

.sp-admin-footer-inner {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-2);
    flex-wrap: wrap;
}

.sp-admin-footer-brand {
    font-weight: 600;
    color: var(--sp-text-secondary);
}

.sp-admin-footer-sep {
    opacity: 0.4;
}

.sp-admin-footer-link {
    color: var(--sp-text-tertiary);
    text-decoration: none;
    transition: color var(--sp-duration-fast);
}

.sp-admin-footer-link:hover {
    color: var(--sp-accent-text);
}

.sp-admin-footer-link:focus-visible {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
    border-radius: var(--sp-radius-sm);
}

@media (max-width: 30rem) {
    .sp-admin-footer {
        padding: var(--sp-space-3) var(--sp-space-4);
        padding-bottom: calc(var(--sp-space-3) + env(safe-area-inset-bottom, 0px));
    }
}

}

@layer responsive {

/* On a phone the topbar is the only way back to navigation and search, so it
   sticks to the top of the document instead of scrolling away. It bleeds to
   the screen edge through the gutter and carries an opaque background, since
   table cards scrolling underneath a transparent bar read as overlapping text.
   The top padding clears the notch when the page runs edge to edge. */
@media (max-width: 48rem) {
    .sp-topbar {
        position: sticky;
        top: 0;
        z-index: var(--sp-z-topbar);
        flex-wrap: wrap;
        row-gap: var(--sp-space-2);
        margin-inline: calc(-1 * var(--sp-gutter));
        padding-inline: var(--sp-gutter);
        padding-top: calc(var(--sp-space-2) + env(safe-area-inset-top));
        padding-bottom: var(--sp-space-2);
        background: var(--sp-bg-main-gradient);
    }

    .sp-topbar__search-toggle {
        display: inline-flex;
    }

    .sp-topbar__actions-toggle {
        width: 44px;
        height: 44px;
    }

    /* A 390px bar cannot hold a menu button, a search form and the kebab on
       one line without squeezing the input to a few characters, so the form
       waits behind its icon and opens as a full-width row under the bar. */
    .sp-topbar__search {
        display: none;
        order: 1;
        flex-basis: 100%;
        max-width: none;
        margin: 0;
        height: 44px;
    }

    .sp-topbar.is-search-open .sp-topbar__search {
        display: flex;
    }
}

}

@layer components {

.sp-topbar__search {
    flex: 1 1 auto;
    max-width: 640px;
    margin: 0 var(--sp-space-4);
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    padding: 0 var(--sp-space-3);
    height: 36px;
    background: var(--sp-bg-surface-raised);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    transition: border-color 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
    position: relative;
}

.sp-topbar__search:focus-within {
    border-color: var(--sp-info);
    box-shadow: 0 0 0 3px color-mix(in oklch, var(--sp-info) 20%, transparent);
    background: var(--sp-bg-surface);
}

.sp-topbar__search--error {
    border-color: var(--sp-danger);
}

.sp-topbar__search--error:focus-within {
    box-shadow: 0 0 0 3px color-mix(in oklch, var(--sp-danger) 20%, transparent);
}

.sp-topbar__search-icon {
    flex: none;
    color: var(--sp-text-tertiary);
    pointer-events: none;
}

.sp-topbar__search-input {
    flex: 1 1 auto;
    min-width: 0;
    background: transparent;
    border: 0;
    outline: 0;
    font: inherit;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
    padding: 0;
    margin: 0;
}

.sp-topbar__search-input::placeholder {
    color: var(--sp-text-tertiary);
}

.sp-topbar__search-input::-webkit-search-cancel-button {
    appearance: none;
}

.sp-topbar__search-hint {
    flex: none;
    font-family: var(--sp-font-mono);
    font-size: 11px;
    line-height: 1;
    padding: var(--sp-space-1) var(--sp-space-2);
    border-radius: 4px;
    color: var(--sp-text-tertiary);
    background: var(--sp-bg-tertiary);
    border: 1px solid var(--sp-border-subtle);
}

.sp-topbar__search-status {
    flex: none;
    font-size: 11px;
    color: var(--sp-text-tertiary);
    white-space: nowrap;
}

.sp-topbar__search--error .sp-topbar__search-status {
    color: var(--sp-danger-strong);
}

.sp-topbar__search--loading .sp-topbar__search-icon {
    animation: admin-header-search-spin 0.9s linear infinite;
}

.sp-topbar__search-list {
    position: absolute;
    top: calc(100% + var(--sp-space-1));
    left: 0;
    right: 0;
    margin: 0;
    padding: var(--sp-space-1);
    list-style: none;
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    box-shadow: var(--sp-shadow-md);
    z-index: var(--sp-z-dropdown);
    max-height: 320px;
    overflow-y: auto;
}

.sp-topbar__search-item {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    padding: var(--sp-space-2) var(--sp-space-3);
    border-radius: 4px;
    font-size: var(--sp-text-sm);
    cursor: pointer;
}

.sp-topbar__search-item:hover,
.sp-topbar__search-item.is-active {
    background: var(--sp-bg-surface-raised);
}

.sp-topbar__search-kind {
    flex: none;
    min-width: 6.5em;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--sp-text-tertiary);
}

.sp-topbar__search-id {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--sp-text-primary);
}

@keyframes admin-header-search-spin {
    from { transform: rotate(0deg); }
    to { transform: rotate(360deg); }
}

@media (max-width: 48rem) {
    .sp-topbar__search {
        max-width: none;
        margin: 0 var(--sp-space-2);
    }
    .sp-topbar__search-hint,
    .sp-topbar__search-status {
        display: none;
    }
}

.sp-topbar {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    z-index: var(--sp-z-topbar);
    padding-block: var(--sp-space-4) var(--sp-space-3);
    margin-bottom: var(--sp-space-2);
    border-bottom: 1px solid var(--sp-border-subtle);
}

/* The icon that stands in for the search form on a phone; the desktop bar
   has room for the whole form, so the toggle only appears in the mobile file. */
.sp-topbar__search-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    background: none;
    border: none;
    border-radius: var(--sp-corners-sm);
    color: var(--sp-text-secondary);
    cursor: pointer;
    flex-shrink: 0;
}

.sp-topbar__search-toggle:hover,
.sp-topbar__search-toggle[aria-expanded="true"] {
    background: var(--sp-accent-dim);
    color: var(--sp-text-primary);
}

.sp-topbar__search-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px var(--sp-accent);
}

.sp-topbar__spacer {
    flex: 1;
    min-height: 1px;
}

}

@layer base {

/* No containment on the main column. `contain: layout` makes an element the
   containing block for its position:fixed descendants, so a drawer parked
   off-canvas at translateX(100%) kept counting toward the column's scroll
   width — and the page then reported a sideways scroll pointing at a table that
   fitted exactly. A fixed panel belongs to the viewport, which is what it was
   written against.

   The gutter is padding on .sp-shell__main itself, not on each child. Putting it on
   the children made every card paint its border and shadow at the full page
   width while its content started a gutter inside, which is what produced the
   mid-block shadow on the governance pages, and it needed a hand-written
   exemption for every child that wanted to bleed. */

.sp-shell {
    display: flex;
    height: 100vh;
    overflow: hidden;
    background: var(--sp-bg-base);
    color: var(--sp-text-primary);
    font-family: var(--sp-font-family);
    font-size: var(--sp-text-base);
    line-height: var(--sp-leading-normal);
}

.sp-shell__main {
    flex: 1;
    min-width: 0;
    overflow-y: auto;
    overflow-x: hidden;
    background: var(--sp-bg-main-gradient);
    position: relative;
    display: flex;
    flex-direction: column;
    padding-inline: var(--sp-gutter);
}

.sp-shell__main > * {
    flex: 0 0 auto;
    position: relative;
    min-width: 0;
    z-index: var(--sp-z-sticky);
}

.sp-shell__main > .sp-admin-footer {
    margin-top: auto;
}

.sp-u-bleed {
    margin-inline: calc(-1 * var(--sp-gutter));
}

}

@layer responsive {

/* On a phone the document scrolls, not the column, and both shell boxes clip
   rather than hide. Any overflow other than visible or clip makes an element a
   scroll container, and a position:sticky topbar sticks to its nearest scroll
   container — which, being height:auto, never scrolls — so the bar would ride
   off the top of the screen with the page. */
@media (max-width: 48rem) {
    .sp-shell {
        display: block;
        height: auto;
        overflow: clip;
    }
    .sp-shell__main {
        overflow: clip;
        max-width: 100vw;
    }
}

}

@layer components {

/* A to-do count beside one sidebar link. Colour is not the only carrier:
   the number is always shown, and the screen-reader text names what it
   counts. */
.sp-nav-attention {
    margin-left: auto;
    min-width: 1.25rem;
    padding: 0 var(--sp-space-1);
    border-radius: var(--sp-corners-sm);
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-semibold);
    font-variant-numeric: tabular-nums;
    text-align: center;
    color: var(--sp-danger-strong);
    background: var(--sp-danger-dim);
}

}

@layer components {

/* A group's body is a one-row grid whose track animates between 0fr and 1fr,
   so the reveal follows the real height of the links without JS measuring
   anything. Before JS owns the state, `:has(.is-active)` opens the group the
   reader is standing in, so a first paint never hides the current page. */
.sp-nav-group {
    margin-block: var(--sp-space-1);
}

.sp-nav-group__items {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--sp-duration-moderate) var(--sp-ease-out);
}

/* The rail hangs from under the heading's first letter (label padding plus
   toggle padding = 20px) and ties the group's rows to their heading. */
.sp-nav-group__inner {
    position: relative;
    min-height: 0;
    overflow: hidden;
    visibility: hidden;
    transition: visibility 0s linear var(--sp-duration-moderate);
}

.sp-nav-group__inner::before {
    content: '';
    position: absolute;
    left: calc(var(--sp-space-2) + var(--sp-space-3));
    top: 0;
    bottom: 0;
    width: 1px;
    background: var(--sp-sidebar-border);
}

.sp-nav-group.is-open .sp-nav-group__items,
.sp-admin-sidebar nav:not([data-nav-ready]) .sp-nav-group:has(.is-active, .is-ancestor) .sp-nav-group__items {
    grid-template-rows: 1fr;
}

.sp-nav-group.is-open .sp-nav-group__inner,
.sp-admin-sidebar nav:not([data-nav-ready]) .sp-nav-group:has(.is-active, .is-ancestor) .sp-nav-group__inner {
    visibility: visible;
    transition-delay: 0s;
}

/* Groups restored from storage must not animate open on page load; JS sets
   `data-nav-motion` after the first paint, and only then do tracks animate. */
.sp-admin-sidebar nav:not([data-nav-motion]) .sp-nav-group__items,
.sp-admin-sidebar nav:not([data-nav-motion]) .sp-nav-group__inner,
.sp-admin-sidebar nav:not([data-nav-motion]) .sp-nav-group__chevron {
    transition: none;
}

.sp-nav-group__toggle {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    width: 100%;
    min-height: 1.75rem;
    padding: var(--sp-space-1) var(--sp-space-3);
    border: none;
    border-radius: var(--sp-corners-sm);
    background: transparent;
    color: inherit;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    text-align: left;
    cursor: pointer;
    transition: color var(--sp-duration-fast) var(--sp-ease-in-out);
}

.sp-nav-group__toggle:focus-visible {
    outline: 2px solid var(--sp-accent-text);
    outline-offset: -2px;
}

.sp-nav-group__title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The count is the collapsed group's promise of what is inside; it steps
   aside once the links themselves are showing. */
.sp-nav-group__count {
    font-variant-numeric: tabular-nums;
    font-weight: 500;
    letter-spacing: 0;
    color: var(--sp-sidebar-text-muted);
    opacity: 0.8;
}

.sp-nav-group__count:empty,
.sp-nav-group.is-open .sp-nav-group__count { display: none; }

.sp-nav-group__chevron {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    color: var(--sp-sidebar-text-muted);
    transition: transform var(--sp-duration-normal) var(--sp-ease-out),
                color var(--sp-duration-fast);
}

.sp-nav-group__toggle:hover .sp-nav-group__chevron,
.sp-nav-group__toggle:hover .sp-nav-group__count {
    color: var(--sp-sidebar-text-hover);
}

.sp-nav-group.is-open .sp-nav-group__chevron,
.sp-admin-sidebar nav:not([data-nav-ready]) .sp-nav-group:has(.is-active, .is-ancestor) .sp-nav-group__chevron {
    transform: rotate(90deg);
}

/* The group holding the current page is locked open: no chevron to invite a
   collapse, no pointer cursor, because hiding where you are is never useful. */
.sp-nav-group:has(.is-active, .is-ancestor) .sp-nav-group__toggle { cursor: default; }

.sp-nav-group:has(.is-active, .is-ancestor) .sp-nav-group__chevron { display: none; }

@media (prefers-reduced-motion: reduce) {
    .sp-nav-group__items,
    .sp-nav-group__inner,
    .sp-nav-group__chevron {
        transition: none;
    }
}

}

@layer base {

.sp-topbar__actions-toggle {
    display: none;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-md);
    background: var(--sp-bg-surface);
    color: var(--sp-text-secondary);
    cursor: pointer;
    flex-shrink: 0;
    transition: color var(--sp-duration-fast), background var(--sp-duration-fast), border-color var(--sp-duration-fast);
}

.sp-topbar__actions-toggle:hover {
    color: var(--sp-text-primary);
    background: var(--sp-bg-surface-raised);
    border-color: var(--sp-border-strong);
}

.sp-topbar__actions-menu {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
}

.sp-user-widget-row {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
}

.sp-topbar__help {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    flex-shrink: 0;
    border-radius: var(--sp-radius-md);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-default);
    color: var(--sp-text-secondary);
    cursor: pointer;
    transition: color var(--sp-duration-fast), background var(--sp-duration-fast), border-color var(--sp-duration-fast);
}

.sp-topbar__help:hover {
    color: var(--sp-text-primary);
    background: var(--sp-bg-surface-raised);
    border-color: var(--sp-border-strong);
}

.sp-topbar__help:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px color-mix(in oklch, var(--sp-accent) 50%, transparent);
}

.sp-topbar__help svg {
    display: block;
}

.sp-shell h1, .sp-shell h2, .sp-shell h3 {
    font-family: var(--sp-font-heading);
}

.sp-shell a {
    color: var(--sp-text-secondary);
    text-decoration: none;
    transition: color var(--sp-duration-fast);
}

.sp-shell a:hover {
    color: var(--sp-text-primary);
}

.sp-shell .sp-table__el a,
.sp-shell .sp-table__row--click a {
    color: var(--sp-text-primary);
    font-weight: 500;
}

.sp-shell .sp-table__el a:hover,
.sp-shell .sp-table__row--click a:hover {
    color: var(--sp-accent-text);
}

[data-section="dashboard"]                          { --sp-section-color: var(--sp-section-dashboard); }

[data-section="users"],  [data-section="user-detail"] { --sp-section-color: var(--sp-section-users); }

[data-section="plugins"],[data-section="plugin-create"],
[data-section="plugin-edit"]                          { --sp-section-color: var(--sp-section-plugins); }

[data-section="skills"], [data-section="skill-edit"]  { --sp-section-color: var(--sp-section-skills); }

[data-section="export"]                               { --sp-section-color: var(--sp-section-export); }

[data-section="audit"]                                { --sp-section-color: var(--sp-section-audit); }

[data-section="agents"], [data-section="agent-edit"]  { --sp-section-color: var(--sp-section-dashboard); }

[data-section="hooks"],  [data-section="hook-edit"]   { --sp-section-color: var(--sp-section-dashboard); }

[data-section="mcp-servers"],[data-section="mcp-edit"]{ --sp-section-color: var(--sp-section-dashboard); }

[data-section="jobs"],   [data-section="events"]      { --sp-section-color: var(--sp-section-users); }

[data-section="leaderboard"],[data-section="achievements"] { --sp-section-color: var(--sp-section-dashboard); }

[data-section="contexts"], [data-section="context-detail"] { --sp-section-color: var(--sp-section-dashboard); }
}



@layer responsive {

@media (max-width: 48rem) {
    .sp-topbar__actions {
        position: relative;
        flex-shrink: 0;
    }
    .sp-topbar__actions-toggle {
        display: flex;
    }
    .sp-topbar__actions-menu {
        display: none;
        position: absolute;
        top: calc(100% + var(--sp-space-2));
        right: 0;
        background: var(--sp-bg-surface);
        border: 1px solid var(--sp-border-default);
        border-radius: var(--sp-radius-md);
        box-shadow: var(--sp-shadow-lg);
        padding: var(--sp-space-2);
        min-width: 200px;
        z-index: var(--sp-z-sticky-header);
        flex-direction: column;
        gap: var(--sp-space-2);
    }
    .sp-topbar__actions.is-open .sp-topbar__actions-menu {
        display: flex;
    }
    .sp-topbar__actions-menu .sp-topbar__help {
        width: 100%;
        height: auto;
        border-radius: var(--sp-radius-sm);
        padding: var(--sp-space-2) var(--sp-space-3);
        justify-content: flex-start;
        gap: var(--sp-space-2);
    }
    .sp-topbar__actions-menu .sp-topbar__help::after {
        content: 'Help';
        font-size: var(--sp-text-sm);
        color: var(--sp-text-secondary);
    }
    .sp-topbar__actions-menu .sp-install-menu {
        width: 100%;
    }
    .sp-topbar__actions-menu .sp-install-trigger {
        width: 100%;
        justify-content: flex-start;
        padding: var(--sp-space-2) var(--sp-space-3);
        gap: var(--sp-space-2);
        border-radius: var(--sp-radius-sm);
        min-height: 40px;
    }
    .sp-topbar__actions-menu .sp-install-trigger::after {
        content: 'Share & Install';
        font-size: var(--sp-text-sm);
        color: var(--sp-text-secondary);
    }
    .sp-topbar__actions-menu .sp-user-widget-row {
        display: flex;
        align-items: center;
        gap: var(--sp-space-2);
        padding: var(--sp-space-2) var(--sp-space-3);
    }
    .sp-topbar__actions-menu .sp-user-widget {
        width: 38px;
        height: 38px;
    }

    .sp-topbar__actions-menu .sp-install-dropdown {
        position: fixed;
        top: auto;
        right: var(--sp-space-3);
        left: var(--sp-space-3);
        width: auto;
    }
}

@media print {
    .sp-shell .sp-admin-sidebar,
    .sp-shell .sp-topbar__nav-toggle,
    .sp-shell .sp-sidebar-overlay,
    .sp-shell .sp-toolbar .sp-btn--primary,
    .sp-shell .sp-pagination,
    .sp-shell .sp-table__cell--actions {
        display: none;
    }
    .sp-shell .sp-shell__main {
        padding: 0;
    }

}
}

@layer components {

.sp-topbar__nav-toggle {
    display: none;
    background: none;
    border: none;
    color: var(--sp-text-secondary);
    cursor: pointer;
    padding: var(--sp-space-2);
    border-radius: var(--sp-corners-sm);
    min-width: 44px;
    min-height: 44px;
    align-items: center;
    justify-content: center;
    transition: color var(--sp-duration-fast), background var(--sp-duration-fast);
    flex-shrink: 0;
}

.sp-topbar__nav-toggle:hover {
    background: var(--sp-accent-dim);
    color: var(--sp-text-primary);
}

.sp-topbar__nav-toggle:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px var(--sp-accent);
}

.sp-sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: transparent;
    z-index: var(--sp-z-sidebar);
    transition: background var(--sp-duration-slow) var(--sp-ease-in-out);
}

.sp-sidebar-overlay.is-open {
    display: block;
    background: var(--sp-overlay-light);
    backdrop-filter: blur(4px);
}

.sp-sidebar-close-btn {
    display: none;
    position: absolute;
    top: var(--sp-space-3);
    right: var(--sp-space-3);
    width: 36px;
    height: 36px;
    border: none;
    background: var(--sp-sidebar-control-bg);
    color: var(--sp-sidebar-text);
    border-radius: var(--sp-corners-sm);
    cursor: pointer;
    font-size: var(--sp-text-md);
    line-height: 1;
    z-index: var(--sp-z-sticky);
    align-items: center;
    justify-content: center;
    transition: background var(--sp-duration-fast), color var(--sp-duration-fast);
}

.sp-sidebar-close-btn:hover {
    background: var(--sp-sidebar-control-bg-hover);
    color: var(--sp-sidebar-text-hover);
}

.sp-sidebar-close-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-sidebar-bg), 0 0 0 4px var(--sp-sidebar-active-color);
}

.sp-admin-sidebar {
    scrollbar-width: thin;
    scrollbar-color: var(--sp-sidebar-scrollbar-thumb) transparent;
}

@media (prefers-reduced-motion: reduce) {
    .sp-sidebar-overlay {
        transition: none;
    }
}

}

@layer components {

.sp-admin-sidebar {
    width: 220px;
    background: var(--sp-sidebar-bg);
    border-right: 1px solid var(--sp-sidebar-border);
    box-shadow: none;
    padding: 0;
    flex-shrink: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}

.sp-admin-sidebar-brand {
    padding: var(--sp-space-6) var(--sp-space-5);
    text-decoration: none;
    display: flex;
    align-items: center;
    border-bottom: 1px solid var(--sp-sidebar-border);
    background: none;
}

.sp-admin-logo {
    width: 160px;
    height: auto;
}

.sp-admin-logo--light { display: inline; }
.sp-admin-logo--dark { display: none; }

.sp-admin-sidebar nav {
    flex: 1;
    padding: var(--sp-space-3) 0;
}

/* The release the page is being served by, ruled off at the foot of the rail.
   `margin-block-start: auto` rather than a fixed offset, so it sits at the
   bottom on a short viewport and directly under the last link on a tall one. */
.sp-nav-version {
    margin: auto 0 0;
    padding: var(--sp-space-3) var(--sp-space-5);
    border-top: 1px solid var(--sp-sidebar-border);
    font-size: var(--sp-text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--sp-sidebar-text-muted);
}

.sp-nav-label {
    margin: 0;
    padding: 0 var(--sp-space-2);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--sp-sidebar-text-muted);
}

/* Each group heading carries its own hue so the rail reads as six zones at
   a glance. The hue is keyed by the group's modifier class, not its position,
   so reordering the groups never recolours a neighbour; the account group
   stays neutral because it is about the reader, not the business. */
.sp-nav-group--activity .sp-nav-group__title { color: var(--sp-nav-label-1); }

.sp-nav-group--farms .sp-nav-group__title { color: var(--sp-nav-label-6); }

.sp-nav-group--people .sp-nav-group__title { color: var(--sp-nav-label-2); }

.sp-nav-group--analysis .sp-nav-group__title { color: var(--sp-nav-label-3); }

.sp-nav-group--governance .sp-nav-group__title { color: var(--sp-nav-label-4); }

.sp-nav-group--platform .sp-nav-group__title { color: var(--sp-nav-label-5); }

/* A row sits one `space-1` clear of the group rail drawn by
   `.sp-nav-group__inner::before`; nothing about it moves on hover, only
   colour changes, so a dense rail stays still under the pointer. */
.sp-admin-sidebar nav a {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    min-height: 2rem;
    padding: var(--sp-space-1) var(--sp-space-2);
    margin: 0 var(--sp-space-2) 0 var(--sp-space-6);
    color: var(--sp-sidebar-text);
    text-decoration: none;
    transition: background var(--sp-duration-fast) var(--sp-ease-in-out),
                color var(--sp-duration-fast) var(--sp-ease-in-out);
    font-size: var(--sp-text-sm);
    font-weight: 500;
    line-height: var(--sp-leading-normal);
    border-radius: var(--sp-corners-sm);
    min-width: 0;
}

.sp-admin-sidebar nav a:hover {
    background: var(--sp-sidebar-hover-bg);
    color: var(--sp-sidebar-text-hover);
}

.sp-admin-sidebar nav a:active {
    background: var(--sp-sidebar-control-bg);
}

.sp-admin-sidebar nav a.is-active {
    background: var(--sp-sidebar-active-bg);
    color: var(--sp-sidebar-active-color);
    font-weight: 600;
}

/* The active bar is drawn over the group rail so the two read as one
   stroke: rail at 20px, bar 3px wide starting 1px before it. */
.sp-admin-sidebar nav a.is-active::before {
    content: '';
    position: absolute;
    left: calc(-1 * var(--sp-space-15) + 1px);
    top: var(--sp-space-1);
    bottom: var(--sp-space-1);
    width: 3px;
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent);
}

.sp-admin-sidebar nav a .sp-icon {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
    opacity: 0.7;
    transition: opacity var(--sp-duration-fast);
}

.sp-admin-sidebar nav a:hover .sp-icon,
.sp-admin-sidebar nav a.is-active .sp-icon { opacity: 1; }

/* Inset ring: the rail clips overflow, so an outset ring would be cut off. */
.sp-admin-sidebar nav a:focus-visible {
    outline: 2px solid var(--sp-accent-text);
    outline-offset: -2px;
}

}



@layer components {

/* The open record sits on an inset branch; only the record is selected. The
   ancestor link is emboldened but carries no background and no bar. */
.sp-admin-sidebar nav a.is-ancestor {
    background: transparent;
    color: var(--sp-sidebar-text-hover);
    font-weight: 600;
}

.sp-admin-sidebar nav a.is-ancestor:hover {
    background: var(--sp-sidebar-hover-bg);
}

.sp-admin-sidebar nav a.is-ancestor .sp-icon { opacity: 1; }

/* The branch hangs off the group rail: a horizontal tick runs from the rail
   (20px) to the row (40px), accent-coloured because the open record is the
   active page. */
.sp-nav-branch {
    position: relative;
    margin: 0 var(--sp-space-2) var(--sp-space-1) var(--sp-space-10);
    min-width: 0;
}

.sp-nav-branch::before {
    content: '';
    position: absolute;
    left: calc(-1 * var(--sp-space-5));
    top: 50%;
    width: var(--sp-space-4);
    height: 1px;
    background: var(--sp-accent);
}

.sp-admin-sidebar nav a.sp-nav-child {
    margin: 0;
    min-height: 2rem;
    padding: var(--sp-space-1) var(--sp-space-2);
}

.sp-admin-sidebar nav a.sp-nav-child.is-active::before {
    content: none;
}

.sp-nav-child__text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-nav-group--account,
.sp-nav-group--developer {
    margin-top: var(--sp-space-4);
    border-top: 1px solid var(--sp-sidebar-border);
    padding-top: var(--sp-space-2);
}

.sp-nav-external {
    margin-left: auto;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}
}

@layer responsive {

/* The drawer stops short of the full width so the dimmed page stays visible as
   the tap target that closes it, and uses dvh so the iOS toolbar cannot hide
   its last links. Overscroll is contained because a flick past the end of the
   nav would otherwise scroll the page underneath. */
@media (max-width: 48rem) {
    .sp-topbar__nav-toggle {
        display: flex;
    }
    .sp-sidebar-close-btn {
        display: flex;
        top: calc(var(--sp-space-3) + env(safe-area-inset-top));
        width: 44px;
        height: 44px;
    }
    .sp-admin-sidebar {
        position: fixed;
        top: 0;
        left: 0;
        width: min(20rem, 85vw);
        height: 100dvh;
        overscroll-behavior: contain;
        z-index: var(--sp-z-sidebar-drawer);
        transform: translateX(-100%);
        transition: transform var(--sp-duration-slow) var(--sp-ease-out);
        box-shadow: none;
        padding-top: env(safe-area-inset-top);
        padding-bottom: env(safe-area-inset-bottom);
    }
    .sp-admin-sidebar.is-open {
        transform: translateX(0);
        box-shadow: var(--sp-shadow-xl);
    }
    .sp-admin-sidebar nav a,
    .sp-admin-sidebar nav a.sp-nav-child {
        min-height: 2.75rem;
        padding: var(--sp-space-2);
    }
    /* Locks the page behind an open drawer so a swipe on the overlay does not
       scroll the content the drawer is covering. */
    html.is-drawer-open {
        overflow: hidden;
    }
}

@media (max-width: 48rem) and (prefers-reduced-motion: reduce) {
    .sp-admin-sidebar {
        transition: none;
    }
}

@media (hover: none) {
    .sp-admin-sidebar nav a:not(.is-active):hover {
        background: transparent;
        color: var(--sp-text-secondary);
    }
}
}

@layer components {

.sp-breadcrumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-1);
    margin-top: var(--sp-space-4);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
}

.sp-breadcrumbs a {
    color: var(--sp-text-secondary);
    text-decoration: none;
}

.sp-breadcrumbs a:hover {
    color: var(--sp-accent-text);
    text-decoration: underline;
}

.sp-breadcrumbs__sep {
    color: var(--sp-text-tertiary);
    user-select: none;
}

.sp-breadcrumbs [aria-current="page"] {
    color: var(--sp-text-primary);
    font-weight: var(--sp-font-medium);
}

}

@layer responsive {

/* The chrome above a page's content on a phone. Rows that hold a variable
   number of controls (header actions, crumbs, tabs, time presets) scroll
   sideways on one line instead of wrapping, because a wrapped row of pills
   pushed the first table row below the fold on every page. */
@media (max-width: 48rem) {
    .sp-page-header {
        flex-direction: column;
        gap: var(--sp-space-3);
        align-items: stretch;
    }

    .sp-page-header__actions {
        flex-shrink: 1;
        min-width: 0;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x proximity;
        scrollbar-width: none;
    }

    .sp-page-header__actions > * {
        flex: 0 0 auto;
        scroll-snap-align: start;
    }

    .sp-page-header__actions > .sp-btn {
        min-height: 44px;
    }

    /* The fade tells the reader the trail continues past the edge; without
       it a clipped crumb looks like the whole path. A mask reads only alpha,
       so any opaque token serves, and the end padding lets the last item
       scroll clear of the fade. */
    .sp-breadcrumbs {
        flex-wrap: nowrap;
        overflow-x: auto;
        white-space: nowrap;
        scrollbar-width: none;
        padding-inline-end: var(--sp-space-8);
        mask-image: linear-gradient(to right, var(--sp-text-primary) calc(100% - var(--sp-space-8)), transparent);
    }

    .sp-tabs {
        overscroll-behavior-x: contain;
        scroll-snap-type: x proximity;
        scrollbar-width: none;
        padding-inline-end: var(--sp-space-8);
        mask-image: linear-gradient(to right, var(--sp-text-primary) calc(100% - var(--sp-space-8)), transparent);
    }

    .sp-tab {
        min-height: 44px;
        scroll-snap-align: start;
    }

    .sp-time-range__presets,
    .sp-scope-filter__ranges {
        max-width: 100%;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
    }

    .sp-scope-filter__ranges {
        margin-left: 0;
    }

    .sp-time-range__btn,
    .sp-scope-filter__ranges .sp-btn {
        flex: 0 0 auto;
        min-height: 44px;
    }

    .sp-time-range__custom,
    .sp-time-range__label,
    .sp-time-range__input {
        width: 100%;
    }

    /* Every toolbar control takes its own full-width row on a phone: a
       select squeezed beside a search box showed three characters of either. */
    .sp-toolbar {
        max-width: 100vw;
    }

    .sp-toolbar > * {
        flex: 1 1 100%;
        max-inline-size: none;
        min-width: 0;
    }

    .sp-toolbar__search,
    .sp-toolbar__filter {
        flex-wrap: wrap;
    }

    .sp-toolbar__filter select,
    .sp-toolbar__field select,
    .sp-toolbar .sp-filter-select,
    .sp-search-input {
        flex: 1 1 auto;
        width: 100%;
        min-width: 0;
        max-inline-size: none;
        min-height: 44px;
    }

    .sp-toolbar__actions {
        margin-left: 0;
    }

    .sp-toolbar__actions > .sp-btn {
        flex: 1 1 0;
        justify-content: center;
    }

    .sp-pagination__controls {
        flex: 1 1 100%;
        justify-content: space-between;
        margin-left: 0;
    }

    .sp-bulk-bar {
        inset-block-end: calc(var(--sp-space-3) + env(safe-area-inset-bottom, 0px));
    }

    .sp-u-grid-2,
    .sp-u-grid-3,
    .sp-u-grid-2col,
    .sp-u-grid-3col {
        grid-template-columns: 1fr;
    }
}

}

@layer components {

.sp-page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--sp-space-6);
    margin-block: var(--sp-space-5) var(--sp-density-section);
    padding-bottom: var(--sp-space-3);
    border-bottom: 1px solid var(--sp-border-subtle);
}

.sp-page-header__title-group {
    flex: 1 1 auto;
    min-width: 0;
}

.sp-page-header__title {
    font-family: var(--sp-font-heading);
    font-size: var(--sp-text-xl);
    font-weight: var(--sp-font-semibold);
    line-height: var(--sp-leading-snug);
    letter-spacing: var(--sp-tracking-tight);
    margin: 0;
    color: var(--sp-text-primary);
}

.sp-page-header__subtitle {
    margin: var(--sp-space-1) 0 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    line-height: var(--sp-leading-normal);
    max-width: 90ch;
}

.sp-page-header__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-1) var(--sp-space-3);
    margin-top: var(--sp-space-2);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-page-header__actions {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    flex-shrink: 0;
}

}

@layer components {

/* One heading treatment for the whole console. The count sits with the title
   because "Requests 1,204" is a single fact, and a reader who has to look in two
   places to learn how much of a thing there is reads the page twice. */

.sp-section {
    margin-top: var(--sp-density-section);
}

/* The partial emits only the head, so the rhythm between one section and the
   next lives on the head itself rather than on a wrapper no template renders. */
.sp-section__head:not(:first-child) {
    margin-top: var(--sp-density-section);
}

.sp-section__head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: var(--sp-space-2) var(--sp-space-3);
    margin-bottom: var(--sp-space-3);
}

.sp-section__title {
    margin: 0;
    font-size: var(--sp-text-md);
    font-weight: var(--sp-font-semibold);
    line-height: var(--sp-leading-snug);
    color: var(--sp-text-primary);
}

.sp-section__count {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    letter-spacing: var(--sp-tracking-wide);
    text-transform: uppercase;
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-section__sub {
    flex-basis: 100%;
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    max-width: 90ch;
}

.sp-section__actions {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin-left: auto;
}

.sp-section__actions:empty { display: none; }

.sp-section__foot {
    margin-top: var(--sp-space-2);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
}

}

@layer components {

.sp-toolbar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-density-gap);
    margin-bottom: var(--sp-space-3);
    min-height: var(--sp-density-row);
}

/* The search group is one row and has a ceiling. Its input carries width:100%
   from the field styles, so without a cap it took the whole toolbar and pushed
   the select and the button onto lines of their own. */
.sp-toolbar__search {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--sp-space-2);
    flex: 1 1 20rem;
    max-width: 34rem;
    min-width: 0;
}

.sp-toolbar__search input,
.sp-toolbar__search select {
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
}

.sp-toolbar__filter {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-toolbar__filter-label,
.sp-toolbar__field-label {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    letter-spacing: var(--sp-tracking-wide);
    text-transform: uppercase;
    color: var(--sp-text-tertiary);
}

.sp-toolbar__field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
}

.sp-toolbar__count {
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-toolbar__notice {
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-secondary);
}

.sp-toolbar__spacer {
    flex: 1 1 auto;
}

.sp-toolbar__actions {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin-left: auto;
}

/* Why: a toolbar whose fields carry an uppercase label above the control is
   two rows tall, and centring a one-row search box or button against it
   floats them mid-stack. Bottom-aligning puts every control on one baseline. */
.sp-toolbar--fields {
    align-items: flex-end;
}

.sp-toolbar--compact {
    gap: var(--sp-space-2);
    margin-bottom: var(--sp-space-2);
}

}

@layer components {

/* One circle carries the judge's verdict; the row's hover card carries the
   words. A filled circle is a link to the verdict, a hollow one means no
   verdict yet, and in manual mode the hollow one is the button that asks. */
.sp-ai-dot {
    display: inline-block;
    width: 0.8rem;
    height: 0.8rem;
    border-radius: var(--sp-radius-full);
    border: 2px solid var(--sp-border-strong);
    background: transparent;
    vertical-align: middle;
    box-shadow: 0 0 0 2px var(--sp-bg-surface);
    padding: 0;
    cursor: default;
}

.sp-ai-dot--ok { border-color: var(--sp-success-strong); background: var(--sp-success-strong); }
.sp-ai-dot--warn { border-color: var(--sp-warning-strong); background: var(--sp-warning-strong); }
.sp-ai-dot--err { border-color: var(--sp-danger-strong); background: var(--sp-danger-strong); }
.sp-ai-dot--muted { border-color: var(--sp-border-strong); background: transparent; }

a.sp-ai-dot {
    cursor: pointer;
    transition: transform var(--sp-duration-fast) var(--sp-ease-out);
}

a.sp-ai-dot:hover,
a.sp-ai-dot:focus-visible,
.sp-ai-dot--button:hover,
.sp-ai-dot--button:focus-visible {
    transform: scale(1.25);
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-surface), 0 0 0 4px var(--sp-accent-dim);
}

.sp-ai-dot--button {
    cursor: pointer;
    border-style: dashed;
}

.sp-ai-dot--button:hover,
.sp-ai-dot--button:focus-visible {
    border-color: var(--sp-accent);
    border-style: solid;
}

.sp-ai-dot--pending {
    border-color: var(--sp-warning-strong);
    animation: sp-ai-dot-pulse 1.6s ease-in-out infinite;
}

@keyframes sp-ai-dot-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.35; }
}

.sp-ai-dot__value {
    margin-inline-start: var(--sp-space-1);
    font-variant-numeric: tabular-nums;
    font-weight: var(--sp-font-semibold);
}

@media (prefers-reduced-motion: reduce) {
    .sp-ai-dot--pending {
        animation: none;
    }
}

}

@layer components {

.sp-avatar {
    --sp-avatar-tone: var(--sp-accent-fill);
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    box-sizing: border-box;
    width: var(--sp-space-8);
    height: var(--sp-space-8);
    border-radius: var(--sp-radius-full);
    /* The highlight is a lit top edge, not a second colour: it keeps a flat
       tone from reading as a dead disc at 20px and stays inside the tone's
       measured contrast because it only mixes toward the text colour. */
    background:
        linear-gradient(160deg, color-mix(in oklch, var(--sp-text-on-accent) 22%, transparent), transparent 55%),
        var(--sp-avatar-tone);
    color: var(--sp-text-on-accent);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    line-height: 1;
    letter-spacing: var(--sp-tracking-normal);
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
    user-select: none;
    overflow: hidden;
    /* The inner hairline is what separates two touching tones in a stack and
       lifts a tone off a surface of nearly the same lightness. */
    box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--sp-text-on-accent) 18%, transparent);
    transition:
        transform var(--sp-duration-fast) var(--sp-ease-spring),
        box-shadow var(--sp-duration-fast) var(--sp-ease-default);
}

.sp-avatar img,
.sp-avatar__img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* The monogram is sized to the disc, not to the text scale: two semibold
   capitals need roughly 65% of the diameter, so each size names the largest
   face that still leaves the letters a clear margin from the edge. */
.sp-avatar--xs { width: var(--sp-space-5); height: var(--sp-space-5); font-size: var(--sp-text-2xs); letter-spacing: var(--sp-tracking-tight); }
.sp-avatar--sm { width: var(--sp-space-6); height: var(--sp-space-6); font-size: var(--sp-text-2xs); }
.sp-avatar--md { width: var(--sp-space-8); height: var(--sp-space-8); font-size: var(--sp-text-sm); }
.sp-avatar--lg { width: var(--sp-space-10); height: var(--sp-space-10); font-size: var(--sp-text-md); }
.sp-avatar--xl { width: var(--sp-space-16); height: var(--sp-space-16); font-size: var(--sp-text-2xl); }

.sp-avatar--tone-0  { --sp-avatar-tone: var(--sp-avatar-tone-0); }
.sp-avatar--tone-1  { --sp-avatar-tone: var(--sp-avatar-tone-1); }
.sp-avatar--tone-2  { --sp-avatar-tone: var(--sp-avatar-tone-2); }
.sp-avatar--tone-3  { --sp-avatar-tone: var(--sp-avatar-tone-3); }
.sp-avatar--tone-4  { --sp-avatar-tone: var(--sp-avatar-tone-4); }
.sp-avatar--tone-5  { --sp-avatar-tone: var(--sp-avatar-tone-5); }
.sp-avatar--tone-6  { --sp-avatar-tone: var(--sp-avatar-tone-6); }
.sp-avatar--tone-7  { --sp-avatar-tone: var(--sp-avatar-tone-7); }
.sp-avatar--tone-8  { --sp-avatar-tone: var(--sp-avatar-tone-8); }
.sp-avatar--tone-9  { --sp-avatar-tone: var(--sp-avatar-tone-9); }
.sp-avatar--tone-10 { --sp-avatar-tone: var(--sp-avatar-tone-10); }
.sp-avatar--tone-11 { --sp-avatar-tone: var(--sp-avatar-tone-11); }

/* A soft avatar is the tone as ink on a tint of itself, for a disc that must
   sit quietly beside a solid one (a pending invite, a system principal). */
.sp-avatar--soft {
    color: var(--sp-avatar-tone);
    background: color-mix(in oklch, var(--sp-avatar-tone) 14%, var(--sp-bg-surface));
    box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--sp-avatar-tone) 30%, transparent);
}

/* The avatar is the hit target's face: when its link or button is hovered or
   keyboard-focused, the ring appears on the disc rather than around the whole
   row, which is where the eye already is. The surface-coloured gap is what
   keeps the ring legible against the tone. */
a:hover > .sp-avatar,
button:hover > .sp-avatar {
    transform: scale(1.08);
    box-shadow:
        inset 0 0 0 1px color-mix(in oklch, var(--sp-text-on-accent) 18%, transparent),
        0 0 0 2px var(--sp-bg-surface),
        0 0 0 4px var(--sp-focus-ring);
}

a:focus-visible > .sp-avatar,
button:focus-visible > .sp-avatar {
    box-shadow:
        inset 0 0 0 1px color-mix(in oklch, var(--sp-text-on-accent) 18%, transparent),
        0 0 0 2px var(--sp-bg-surface),
        0 0 0 4px var(--sp-accent);
}

/* Presence sits on the disc's lower-right quadrant with a surface-coloured
   halo so it survives any tone behind it; the shape carries the meaning and
   the colour only confirms it. */
.sp-avatar__status {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 28%;
    height: 28%;
    border-radius: var(--sp-radius-full);
    background: var(--sp-text-disabled);
    box-shadow: 0 0 0 2px var(--sp-bg-surface);
}
.sp-avatar__status--ok   { background: var(--sp-success); }
.sp-avatar__status--warn { background: var(--sp-warning); }
.sp-avatar__status--err  { background: var(--sp-danger); }

/* A stack overlaps its discs by a third so five people read as one group;
   the surface-coloured ring is what keeps each edge distinct from the next
   tone, and hover lifts one disc clear of its neighbours. */
.sp-avatar-group {
    display: inline-flex;
    align-items: center;
    padding-inline-start: var(--sp-space-2);
}
.sp-avatar-group > .sp-avatar {
    margin-inline-start: calc(-1 * var(--sp-space-2));
    box-shadow: 0 0 0 2px var(--sp-bg-surface);
}
.sp-avatar-group > .sp-avatar:hover {
    z-index: 1;
    transform: translateY(-2px) scale(1.08);
}

/* Inside a table the disc must not stretch the line box: it is sized to the
   sm step and its overflow past the density line is folded into the cell's
   own padding, so a 24px disc sits in a 20px line without growing the row. */
.sp-table__el td .sp-avatar {
    width: var(--sp-space-6);
    height: var(--sp-space-6);
    font-size: var(--sp-text-2xs);
    margin-block: calc((var(--sp-density-cell-line) - var(--sp-space-6)) / 2);
}

}

@layer components {

/* A cell holding several badges stays one line: the first few show, the rest
   sit as offset cards behind a +N pill and fan out as a list on hover/focus. */
.sp-badge-stack {
    position: relative;
    display: inline-flex;
    max-width: 100%;
    vertical-align: middle;
    border-radius: var(--sp-radius-sm);
    outline-offset: 2px;
}

.sp-badge-stack__row {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    min-width: 0;
    white-space: nowrap;
}

.sp-badge-stack__item {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-badge-stack--mono .sp-badge { font-family: var(--sp-font-mono); }

.sp-badge-stack__more {
    position: relative;
    flex: 0 0 auto;
    padding: 0.0625rem var(--sp-space-2);
    border-radius: var(--sp-radius-full);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    line-height: var(--sp-leading-normal);
    color: var(--sp-text-secondary);
    background: var(--sp-bg-surface-raised);
    border: 1px solid var(--sp-border-subtle);
    box-shadow:
        3px -3px 0 -1px var(--sp-bg-tertiary),
        3px -3px 0 0 var(--sp-border-subtle),
        6px -6px 0 -1px var(--sp-bg-tertiary),
        6px -6px 0 0 var(--sp-border-subtle);
    cursor: default;
    transition: box-shadow var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-badge-stack__pop {
    position: absolute;
    inset-block-start: calc(100% + var(--sp-space-1));
    inset-inline-start: 0;
    z-index: var(--sp-z-dropdown);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-space-1);
    min-width: 100%;
    margin: 0;
    padding: var(--sp-space-2);
    list-style: none;
    background: var(--sp-bg-surface-raised);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    box-shadow: var(--sp-shadow-float);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px) scale(0.98);
    transform-origin: top left;
    transition:
        opacity var(--sp-duration-fast) var(--sp-ease-out),
        transform var(--sp-duration-fast) var(--sp-ease-out),
        visibility 0s linear var(--sp-duration-fast);
}

/* Table cells clip to ellipsis; a cell holding a stack must let the list out. */
td:has(> .sp-badge-stack) { overflow: visible; }
td:has(> .sp-badge-stack:is(:hover, :focus-within)) { position: relative; z-index: 2; }

/* Nothing hidden means nothing to reveal. */
.sp-badge-stack:not(:has(.sp-badge-stack__more)) .sp-badge-stack__pop { display: none; }

.sp-badge-stack:is(:hover, :focus-within) .sp-badge-stack__more {
    box-shadow: 0 0 0 1px var(--sp-border-subtle);
}

.sp-badge-stack:is(:hover, :focus-within) .sp-badge-stack__pop {
    opacity: 1;
    visibility: visible;
    transform: none;
    transition-delay: 0s;
}

.sp-badge-stack__pop > li {
    opacity: 0;
    transform: translateY(-3px);
    transition: opacity var(--sp-duration-fast) var(--sp-ease-out), transform var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-badge-stack:is(:hover, :focus-within) .sp-badge-stack__pop > li {
    opacity: 1;
    transform: none;
}

.sp-badge-stack:is(:hover, :focus-within) .sp-badge-stack__pop > li:nth-child(2) { transition-delay: 20ms; }
.sp-badge-stack:is(:hover, :focus-within) .sp-badge-stack__pop > li:nth-child(3) { transition-delay: 40ms; }
.sp-badge-stack:is(:hover, :focus-within) .sp-badge-stack__pop > li:nth-child(n + 4) { transition-delay: 60ms; }

@media (prefers-reduced-motion: reduce) {
    .sp-badge-stack__pop,
    .sp-badge-stack__pop > li,
    .sp-badge-stack__more { transition: none; transform: none; }
}

}

@layer components {

.sp-badge {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: 0.0625rem var(--sp-space-2);
    border-radius: var(--sp-corners-sm);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-medium);
    line-height: var(--sp-leading-normal);
    white-space: nowrap;
    color: var(--sp-text-secondary);
    background: var(--sp-bg-tertiary);
    border: 1px solid color-mix(in oklch, currentColor 15%, transparent);
}

/* The dot is what makes the tone legible without colour. */
.sp-badge::before {
    content: "";
    width: 0.375rem;
    height: 0.375rem;
    border-radius: var(--sp-radius-full);
    background: currentColor;
    flex: 0 0 auto;
}

.sp-badge--nodot::before { display: none; }

.sp-badge--ok   { color: var(--sp-success-strong); background: var(--sp-success-dim); }
.sp-badge--warn { color: var(--sp-warning-strong); background: var(--sp-warning-dim); }
.sp-badge--err  { color: var(--sp-danger-strong);  background: var(--sp-danger-dim); }
.sp-badge--info { color: var(--sp-info-strong);    background: color-mix(in oklch, var(--sp-info) 12%, transparent); }
.sp-badge--accent { color: var(--sp-accent-text);  background: var(--sp-accent-dim); }
/* Why: tertiary text on the tertiary surface fell under 4.5:1 and the source
   column on Groups was unreadable; secondary text keeps the tone quiet at AA. */
.sp-badge--muted {
    color: var(--sp-text-secondary);
    background: var(--sp-bg-tertiary);
    border-color: var(--sp-border-subtle);
}

.sp-badge--sm {
    padding: 0 var(--sp-space-1);
    font-size: var(--sp-text-2xs);
}

}

@layer responsive {

/* Touch targets on a phone: 44px is the Apple and WCAG minimum for a
   control operated by a thumb. A button inside a table cell is exempt, since
   the card layout sizes its own action buttons and a scrolling ledger keeps
   the desktop row density. :where keeps the exemption weightless, so the
   small size below and the page header's 44px row both still apply. */
@media (max-width: 48rem) {
    .sp-btn:where(:not(.sp-table__el td .sp-btn)) {
        min-height: 44px;
    }

    .sp-btn--sm:where(:not(.sp-table__el td .sp-btn)) {
        min-height: 36px;
    }
}

}

@layer components {

.sp-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-2) var(--sp-space-4);
    border: 1px solid transparent;
    border-radius: var(--sp-corners-sm);
    font-size: var(--sp-text-sm);
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    transition: background-color var(--sp-duration-fast) var(--sp-ease-in-out),
                border-color var(--sp-duration-fast) var(--sp-ease-in-out),
                color var(--sp-duration-fast) var(--sp-ease-in-out),
                box-shadow var(--sp-duration-fast) var(--sp-ease-in-out),
                transform var(--sp-duration-fast) var(--sp-ease-in-out);
    text-decoration: none;
    white-space: nowrap;
    line-height: 20px;
    background: var(--sp-bg-surface-raised);
    color: var(--sp-text-primary);
    border-color: var(--sp-border-default);
}

/* Why: a `.sp-btn` with no variant used to inherit a transparent, borderless
   box, so the Search/Apply submits on every toolbar read as loose text. The
   base now paints a raised neutral so an unmodified button is still a button;
   every variant below overrides all three properties. */
.sp-btn:hover {
    border-color: var(--sp-border-strong);
}

.sp-btn:active { transform: scale(0.97); }

.sp-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px var(--sp-accent);
}

.sp-btn--primary {
    background: var(--sp-accent-fill);
    color: var(--sp-text-on-accent);
    border-color: var(--sp-accent);
    box-shadow: var(--sp-shadow-accent-sm);
}

.sp-btn--primary:hover {
    background: var(--sp-accent-hover);
    border-color: var(--sp-accent-hover);
    box-shadow: var(--sp-shadow-accent-md);
}

.sp-btn--primary:active {
    box-shadow: var(--sp-shadow-xs);
}

.sp-btn--secondary {
    background: transparent;
    color: var(--sp-text-secondary);
    border-color: var(--sp-border-default);
    box-shadow: var(--sp-shadow-xs);
}

.sp-btn--secondary:hover {
    background: color-mix(in oklch, var(--sp-warm-900) 4%, transparent);
    border-color: var(--sp-border-strong);
    color: var(--sp-text-primary);
}

.sp-btn--danger {
    background: transparent;
    color: var(--sp-danger-strong);
    border-color: color-mix(in oklch, var(--sp-danger) 30%, transparent);
    box-shadow: var(--sp-shadow-xs);
}

.sp-btn--danger:hover {
    background: var(--sp-danger-dim);
    border-color: color-mix(in oklch, var(--sp-danger) 50%, transparent);
}

.sp-btn--view {
    background: transparent;
    color: var(--sp-accent-text);
    border-color: color-mix(in oklch, var(--sp-accent) 30%, transparent);
    box-shadow: var(--sp-shadow-xs);
}

.sp-btn--view:hover {
    background: var(--sp-accent-dim);
    border-color: var(--sp-accent);
}

.sp-btn--sm {
    padding: var(--sp-space-1) var(--sp-space-3);
    font-size: var(--sp-text-xs);
}

.sp-btn--icon {
    padding: var(--sp-space-2);
    min-width: 36px;
    justify-content: center;
}

.sp-btn--sm.sp-btn--icon {
    padding: var(--sp-space-1);
    min-width: 28px;
    font-size: var(--sp-text-sm);
}

.sp-btn--outline {
    background: transparent;
    color: var(--sp-text-secondary);
    border-color: var(--sp-border-default);
}
.sp-btn--outline:hover {
    background: color-mix(in oklch, var(--sp-warm-900) 4%, transparent);
    border-color: var(--sp-border-strong);
    color: var(--sp-text-primary);
}

/* Why: a segmented range/source group is a row of outline buttons with one
   selected; the shell's scope bar and the Groups toolbar both draw it, so the
   selected state belongs to the component rather than to either page. */
.sp-btn--outline.is-active {
    border-color: var(--sp-accent);
    background: var(--sp-bg-tertiary);
    color: var(--sp-text-primary);
}

.sp-btn--outline-primary {
    background: transparent;
    color: var(--sp-accent-text);
    border-color: color-mix(in oklch, var(--sp-accent) 40%, transparent);
}
.sp-btn--outline-primary:hover {
    background: var(--sp-accent-dim);
    border-color: var(--sp-accent);
}

.sp-btn--outline-danger {
    background: transparent;
    color: var(--sp-danger-strong);
    border-color: color-mix(in oklch, var(--sp-danger) 40%, transparent);
}
.sp-btn--outline-danger:hover {
    background: var(--sp-danger-dim);
    border-color: var(--sp-danger);
}

.sp-btn--ghost {
    background: transparent;
    color: var(--sp-text-secondary);
    border-color: transparent;
}
.sp-btn--ghost:hover {
    background: color-mix(in oklch, var(--sp-warm-900) 4%, transparent);
    color: var(--sp-text-primary);
}

.sp-btn--tertiary {
    background: transparent;
    color: var(--sp-accent-text);
    border-color: transparent;
    box-shadow: none;
}
.sp-btn--tertiary:hover {
    background: var(--sp-accent-dim);
    color: var(--sp-accent-hover);
}

.sp-btn--xs {
    padding: 0.0625rem var(--sp-space-2);
    font-size: var(--sp-text-xs);
}
.sp-btn--files {
    flex-shrink: 0;
    align-self: flex-start;
}

@media (prefers-reduced-motion: reduce) {
    .sp-btn {
        transition: none;
    }
    .sp-btn:active {
        transform: none;
    }
}

}

@layer components {

/* One surface, one elevation. No inset glow and no hover lift: a card that
   moves under the pointer is a card the reader has to re-find, and in a console
   where a page carries a dozen of them the movement reads as noise. Cards are
   never nested — an inner region is a .sp-section, not another card. */

.sp-card {
    background: var(--sp-bg-surface);
    border-radius: var(--sp-corners-md);
    padding: var(--sp-space-4);
    box-shadow: var(--sp-shadow-card);
}

.sp-card__body {
    color: var(--sp-text-secondary);
    min-width: 0;
}

.sp-card__body > :first-child { margin-top: 0; }
.sp-card__body > :last-child { margin-bottom: 0; }

.sp-card__body--flush {
    margin: 0 calc(-1 * var(--sp-space-4)) calc(-1 * var(--sp-space-4));
}

.sp-card--danger {
    box-shadow: 0 0 0 1px color-mix(in oklch, var(--sp-danger) 35%, transparent);
}

.sp-card--flush {
    padding: 0;
}

}

@layer components {

.sp-delta {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    font-variant-numeric: tabular-nums;
    color: var(--sp-text-tertiary);
}

/* The glyph carries the direction as well as the colour: a red number and a
   green number are the same number to a reader who cannot separate the two. */
.sp-delta::before { content: "→"; }
.sp-delta--up::before { content: "↑"; }
.sp-delta--down::before { content: "↓"; }

.sp-delta--up { color: var(--sp-success-strong); }
.sp-delta--down { color: var(--sp-danger-strong); }
.sp-delta--up-bad { color: var(--sp-danger-strong); }
.sp-delta--up-bad::before { content: "↑"; }
.sp-delta--down-good { color: var(--sp-success-strong); }
.sp-delta--down-good::before { content: "↓"; }

}

@layer components {

.sp-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--sp-space-1);
    padding: var(--sp-space-8) var(--sp-space-4);
    text-align: center;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-sm);
}

.sp-empty p { margin: 0; }

.sp-empty__title {
    font-size: var(--sp-text-base);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}

/* Inside a form or card the empty state is a line of text, not a centred void. */
.sp-empty--inline {
    align-items: flex-start;
    padding: var(--sp-space-2) 0;
    text-align: left;
}

/* A section whose absence is the normal case: one quiet line under the
   section head, so a page of empty sections reads as a checklist, not a void. */
.sp-empty--compact {
    align-items: flex-start;
    padding: var(--sp-space-3) var(--sp-space-4);
    text-align: left;
    border: 1px dashed var(--sp-border-default);
    border-radius: var(--sp-radius-md);
}

.sp-empty--pad { padding-block: var(--sp-space-10); }
.sp-empty--pad-lg { padding-block: var(--sp-space-16); }

}

@layer responsive {

/* A centred empty state sized for a desktop fold filled half a phone screen
   with white space; the inline and compact variants already fit and keep
   their own padding. */
@media (max-width: 48rem) {
    .sp-empty:not(.sp-empty--inline, .sp-empty--compact) {
        padding: var(--sp-space-5) var(--sp-space-3);
    }

    .sp-empty.sp-empty--pad,
    .sp-empty.sp-empty--pad-lg {
        padding-block: var(--sp-space-6);
    }
}

}

@layer components {

/* Glyphs size from the text they sit beside, so the same partial reads right
   in a tile label, a table head, a button and a dialog list without a size
   parameter; the sidebar's own 1rem rule is more specific and still wins. */
.sp-icon {
    width: 1em;
    height: 1em;
    flex-shrink: 0;
    vertical-align: -0.125em;
}

.sp-icon--sm {
    width: 0.75em;
    height: 0.75em;
}

}

@layer components {

/* Tone is a 2px bar on the inline start, not a tinted background: a grid of
   washed tiles turns the fold into a colour chart and the numbers stop being
   the thing you read first.

   The tile is a fixed band and its supporting line is one clamped line. A KPI
   row is read by scanning the numbers across it, and that only works if the
   numbers sit on one baseline; a tile whose note wrapped to four lines pushed
   its whole row to 150px and broke the scan. A note that does not fit is a note
   that belongs in the tile's title attribute, not in the band. */

.sp-kpi-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
    gap: var(--sp-density-gap);
    margin-bottom: var(--sp-density-section);
}

/* A compact strip sits inside a card or beside a table, where the full
   section gap would read as two unrelated groups of tiles. */
.sp-kpi-grid--compact {
    gap: var(--sp-space-2);
}

.sp-kpi {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    padding: var(--sp-density-tile);
    background: var(--sp-bg-surface);
    border-radius: var(--sp-corners-sm);
    box-shadow: var(--sp-shadow-card);
    min-width: 0;
    min-height: var(--sp-density-tile-h);
    overflow: hidden;
}

.sp-kpi__body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    min-width: 0;
    flex: 1 1 auto;
}

/* The trend is a reserved row under the value, never an overlay: a
   sparkline drawn over the value made the number unreadable, and one beside
   it squeezed eight-tile rows until every label truncated. */
.sp-kpi__trend {
    display: flex;
    align-items: flex-end;
    width: 100%;
    min-width: 0;
    margin-block: var(--sp-space-1);
}

.sp-kpi__trend .sp-spark {
    width: 100%;
    height: 1.6rem;
}

.sp-kpi__label .sp-icon {
    width: 0.875rem;
    height: 0.875rem;
    margin-inline-end: var(--sp-space-1);
    vertical-align: -0.125em;
    color: var(--sp-text-tertiary);
}

.sp-kpi__label,
.sp-kpi__sub {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

.sp-kpi__label {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}

.sp-kpi__value {
    display: flex;
    align-items: baseline;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-kpi);
    font-weight: var(--sp-font-semibold);
    line-height: var(--sp-leading-tight);
    letter-spacing: var(--sp-tracking-tight);
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-kpi__unit {
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-medium);
    color: var(--sp-text-tertiary);
}

.sp-kpi__sub {
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    margin-top: auto;
}

.sp-kpi--ok      { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-success); }
.sp-kpi--warn,
.sp-kpi--warning { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-warning); }
.sp-kpi--err,
.sp-kpi--danger  { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-danger); }
.sp-kpi--accent  { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-accent); }
.sp-kpi--info    { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-info); }

.sp-kpi--link {
    text-decoration: none;
    color: inherit;
    transition: box-shadow var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-kpi--link:hover {
    box-shadow: var(--sp-shadow-card-hover);
}

.sp-kpi--link:focus-visible {
    outline: none;
    box-shadow: var(--sp-shadow-card), 0 0 0 2px var(--sp-bg-surface), 0 0 0 4px var(--sp-accent);
}

.sp-kpi--link.is-active {
    box-shadow: var(--sp-shadow-focus-inset);
}

}

@layer responsive {

/* On a phone the auto-fit track collapses to one tile per row, which turns a
   ten-tile strip into ten screens of scrolling. Two to a row keeps the scan,
   and the label and note may take two lines because a clamped single line at
   this width cut every label to three letters. */
@media (max-width: 48rem) {
    .sp-kpi-grid,
    .sp-p-overview__kpis {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .sp-kpi {
        min-height: 0;
    }

    .sp-kpi__label,
    .sp-kpi__sub {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 2;
        line-clamp: 2;
        white-space: normal;
        overflow-wrap: anywhere;
    }
}

/* Below the narrowest phones two tiles leave the value no room for its
   digits, so the strip falls back to one column. */
@media (max-width: 22rem) {
    .sp-kpi-grid,
    .sp-p-overview__kpis {
        grid-template-columns: minmax(0, 1fr);
    }
}

}

@layer components {

/* A record's facts as a definition list: one row per fact, label left, value
   right, an optional action beside the value. A table for six fixed rows spent
   a header and an empty actions column on what is a list. */

.sp-kv-list {
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-kv-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--sp-space-3);
    font-size: var(--sp-text-sm);
}

.sp-kv-row dt {
    color: var(--sp-text-tertiary);
    flex-shrink: 0;
}

.sp-kv-row dd {
    margin: 0;
    color: var(--sp-text-primary);
    text-align: right;
    min-width: 0;
    overflow-wrap: anywhere;
}

.sp-kv-row__value {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-3);
}

}

@layer components {

.sp-notice {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    padding: var(--sp-space-3);
    margin-bottom: var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    background: var(--sp-bg-surface);
    box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-text-tertiary);
}

.sp-notice__title {
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}

.sp-notice__list {
    margin: 0;
    padding-left: var(--sp-space-5);
}

.sp-notice--ok   { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-success); }
.sp-notice--warn { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-warning); }
.sp-notice--err  { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-danger); }
.sp-notice--info { box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-info); }

.sp-notice-region:empty { display: none; }

}

@layer components {

.sp-skeleton {
    background: linear-gradient(90deg, var(--sp-shimmer-from) 25%, var(--sp-shimmer-via) 50%, var(--sp-shimmer-to) 75%);
    background-size: 200% 100%;
    animation: sp-shimmer var(--sp-duration-slower) linear infinite;
    border-radius: var(--sp-radius-sm);
}

.sp-skeleton__text {
    height: var(--sp-space-3);
    margin-block: var(--sp-space-1);
}

/* A veil keeps the element's box while its content is being replaced: the
   text goes transparent and children invisible, so the shimmer plays over the
   exact footprint the fresh value will occupy and nothing on the page jumps. */
.sp-skeleton--veil {
    color: transparent;
    user-select: none;
}

.sp-skeleton--veil > * {
    visibility: hidden;
}


@keyframes sp-shimmer {
    to { background-position: -200% 0; }
}

.sp-spinner {
    width: 2rem;
    height: 2rem;
    border: 3px solid var(--sp-border-default);
    border-top-color: var(--sp-accent);
    border-radius: var(--sp-radius-full);
    animation: sp-spin var(--sp-duration-slow) linear infinite;
}

@keyframes sp-spin {
    to { transform: rotate(360deg); }
}

.sp-loading {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--sp-space-8);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-sm);
}

}

/* The sync-plane component: one plane's head, drift tiles, three direction
   cards and diff table. Rendered on an owner page's Sync tab and on the
   import preview. */
@layer components {

/* Why: hashes are printed in twelve characters; the mono cell keeps a pair
   of them aligned so declared and applied read as a pair. */
.sp-sync-hash {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    cursor: help;
}

.sp-sync-plane {
    margin-block: var(--sp-space-6);
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-sync-plane__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-space-2) var(--sp-space-4);
    margin-bottom: var(--sp-space-3);
}

.sp-sync-plane__head h2 { margin: 0; font-size: var(--sp-text-lg); }

.sp-sync-plane__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1) var(--sp-space-4);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

/* Why: three directions, three cards; the destructive one is bordered in the
   danger colour so the eye lands on the deletion count before the button. */
.sp-sync-actions {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: var(--sp-space-4);
    margin-block: var(--sp-space-5);
}

.sp-sync-card {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-sync-card h3 { margin: 0; font-size: var(--sp-text-base); }

.sp-sync-card p {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-sync-card .sp-btn { align-self: flex-start; margin-top: auto; }

.sp-sync-card--danger { border-color: var(--sp-danger-strong); }

/* Why: the card the "Next:" line points at is the one the eye should land
   on; a left rule in the accent colour marks it without recolouring the
   danger border of an overwrite. */
.sp-sync-card--recommended {
    box-shadow: inset 4px 0 0 var(--sp-info);
}

.sp-sync-plane__next {
    margin-block: 0 var(--sp-space-3);
    padding: var(--sp-space-2) var(--sp-space-3);
    border-left: 4px solid var(--sp-info);
    background: var(--sp-bg-surface-alt);
    font-size: var(--sp-text-sm);
}

.sp-sync-card__count {
    font-family: var(--sp-font-mono);
    color: var(--sp-text-primary);
}

/* Why: the preview's "apply every plane" bar sits above the plane sections
   as one row so the two whole-archive buttons are never mistaken for one
   plane's. */
.sp-sync-apply-all {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-4);
    padding: var(--sp-space-3) var(--sp-space-4);
    border: 1px dashed var(--sp-border-strong);
    border-radius: var(--sp-corners-md);
    font-size: var(--sp-text-sm);
}

}

@layer components {

.sp-tabs {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: var(--sp-space-1);
    border-bottom: 1px solid var(--sp-border-subtle);
    margin-bottom: var(--sp-space-5);
    overflow-x: auto;
    scrollbar-width: thin;
}

.sp-tab {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-3) var(--sp-space-4);
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    position: relative;
    top: 1px;
    transition: color var(--sp-duration-fast), border-color var(--sp-duration-fast), background var(--sp-duration-fast);
}

.sp-tab:hover {
    color: var(--sp-text-primary);
    background: color-mix(in oklch, var(--sp-accent) 5%, transparent);
}

.sp-tab--active,
.sp-tab[aria-selected="true"] {
    color: var(--sp-accent-text);
    border-bottom-color: var(--sp-accent);
}

.sp-tab:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px color-mix(in oklch, var(--sp-accent) 50%, transparent);
    border-radius: var(--sp-radius-sm);
}

.sp-tab-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 var(--sp-space-1);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface-raised);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    line-height: 1;
}

/* A solid fill, as the pill variant uses. Accent text on an accent tint reaches
   only 4.47:1 at this size; the count is the one part of a tab that is always a
   number, so it cannot rely on its neighbours for legibility. */
.sp-tab--active .sp-tab-count,
.sp-tab[aria-selected="true"] .sp-tab-count {
    background: var(--sp-accent-fill);
    color: var(--sp-text-on-accent);
}

.sp-tabs[data-variant="pill"] {
    border-bottom: none;
    gap: var(--sp-space-2);
}

.sp-tabs[data-variant="pill"] .sp-tab {
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface);
    top: 0;
}

.sp-tabs[data-variant="pill"] .sp-tab--active,
.sp-tabs[data-variant="pill"] .sp-tab[aria-selected="true"] {
    background: var(--sp-accent-fill);
    color: var(--sp-text-on-accent);
    border-color: var(--sp-accent);
}

.sp-tabs[data-variant="pill"] .sp-tab--active .sp-tab-count,
.sp-tabs[data-variant="pill"] .sp-tab[aria-selected="true"] .sp-tab-count {
    background: color-mix(in oklch, var(--sp-text-on-accent) 25%, transparent);
    color: var(--sp-text-on-accent);
}

.sp-tab-panel[hidden] {
    display: none;
}

}

@layer components {

.sp-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-space-4);
}

.sp-search-input {
    width: 100%;
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    padding: var(--sp-space-2) var(--sp-space-4);
    color: var(--sp-text-primary);
    font-size: var(--sp-text-base);
    font-family: inherit;
    outline: none;
    transition: border-color var(--sp-duration-fast), box-shadow var(--sp-duration-fast);
}

.sp-search-input:focus-visible {
    border-color: var(--sp-accent);
    outline: 2px solid var(--sp-accent-dim);
    outline-offset: -1px;
}

.sp-search-input::placeholder {
    color: var(--sp-text-disabled);
}

/* Why: the labelled select every toolbar field uses. It lives with the other
   filter controls because the roles, access-control and contexts pages all
   share it; a page file is the wrong home for a shared control. */
.sp-toolbar__field .sp-select {
    appearance: auto;
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    color: var(--sp-text-primary);
    font-size: var(--sp-text-sm);
    font-family: inherit;
    min-width: 140px;
    cursor: pointer;
}

.sp-toolbar__field .sp-select:hover {
    border-color: var(--sp-accent);
}

.sp-toolbar__field .sp-select:focus-visible {
    outline: none;
    border-color: var(--sp-accent);
    box-shadow: 0 0 0 3px color-mix(in oklch, var(--sp-accent) 25%, transparent);
}

.sp-filter-select {
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    padding: var(--sp-space-2) var(--sp-space-4);
    color: var(--sp-text-primary);
    font-size: var(--sp-text-sm);
    font-family: inherit;
    outline: none;
    cursor: pointer;
    transition: border-color var(--sp-duration-fast);
}

.sp-filter-select:focus-visible {
    border-color: var(--sp-accent);
    outline: 2px solid var(--sp-accent-dim);
    outline-offset: -1px;
}

.sp-filter-select option {
    background: var(--sp-bg-surface-overlay);
    color: var(--sp-text-primary);
}

.sp-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: var(--sp-space-1) var(--sp-space-3);
    border-radius: var(--sp-radius-full);
    border: 1px solid var(--sp-border-default);
    background: var(--sp-bg-surface-raised);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    font-family: inherit;
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
    cursor: pointer;
    transition: color var(--sp-duration-fast), background-color var(--sp-duration-fast),
                border-color var(--sp-duration-fast);
}

.sp-chip:hover {
    color: var(--sp-text-primary);
    border-color: var(--sp-border-strong);
}

.sp-chip.is-active {
    background: var(--sp-accent-fill);
    border-color: var(--sp-accent);
    color: var(--sp-text-on-accent);
    font-weight: 600;
}

}

@layer responsive {

/* A 240px dropdown anchored under a pill ran off the right edge of a phone
   for every pill past the first, so on a phone each panel opens as a sheet
   from the bottom of the screen over a dimmed page. filter-ribbon.js closes
   the group when that dimmed backdrop is tapped. */
@media (max-width: 48rem) {
    .sp-filter-ribbon__groups {
        flex-wrap: nowrap;
        width: 100%;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scrollbar-width: none;
    }

    .sp-filter-ribbon__group {
        flex: 0 0 auto;
    }

    .sp-filter-ribbon__group-summary {
        min-height: 44px;
        white-space: nowrap;
    }

    /* The search box leads the scrolling row so it is never the control
       that starts off screen, and leaves a sliver for the first pill. */
    .sp-ribbon__search {
        order: -1;
        flex: 0 0 min(14rem, 70%);
        min-height: 44px;
    }

    .sp-filter-ribbon__group[open]::before {
        content: '';
        position: fixed;
        inset: 0;
        background: var(--sp-overlay-light);
    }

    .sp-filter-ribbon__group-panel {
        position: fixed;
        inset: auto 0 0;
        width: 100vw;
        min-width: 0;
        max-width: none;
        max-height: 70dvh;
        padding: var(--sp-space-3) var(--sp-space-3) calc(var(--sp-space-3) + env(safe-area-inset-bottom, 0px));
        border-width: 1px 0 0;
        border-radius: var(--sp-radius-lg) var(--sp-radius-lg) 0 0;
        box-shadow: var(--sp-shadow-float);
        overscroll-behavior: contain;
    }

    .sp-filter-ribbon__option {
        min-height: 44px;
    }

    .sp-filter-ribbon__actions .sp-btn,
    .sp-filter-ribbon__clear {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }
}

}

@layer components {

.sp-filter-ribbon {
    position: relative;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin-bottom: var(--sp-space-4);
}

/* The ribbon rises only while a pill panel is open, and only to the raised
   tier. A permanent panel-tier z-index made it paint over the sidebar drawer,
   its overlay and the topbar menus, since main forms no stacking context. */
.sp-filter-ribbon:has(.sp-filter-ribbon__group[open]) {
    z-index: var(--sp-z-raised);
}

.sp-filter-ribbon__groups {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-filter-ribbon__group {
    position: relative;
}

.sp-filter-ribbon__group[open] {
    z-index: 1;
}

.sp-filter-ribbon__group-summary {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: var(--sp-space-1) var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    cursor: pointer;
    list-style: none;
    user-select: none;
    transition: border-color var(--sp-duration-fast), color var(--sp-duration-fast);
}

.sp-filter-ribbon__group-summary::-webkit-details-marker {
    display: none;
}

.sp-filter-ribbon__group-summary:hover {
    color: var(--sp-text-primary);
    border-color: var(--sp-border-strong);
}

.sp-filter-ribbon__group[open] > .sp-filter-ribbon__group-summary {
    color: var(--sp-text-primary);
    border-color: var(--sp-accent);
}

.sp-filter-ribbon__group-caret {
    font-size: 0.6em;
    transition: transform var(--sp-duration-fast);
}

.sp-filter-ribbon__group[open] .sp-filter-ribbon__group-caret {
    transform: rotate(180deg);
}

.sp-filter-ribbon__group-panel {
    position: absolute;
    top: calc(100% + var(--sp-space-1));
    left: 0;
    z-index: var(--sp-z-dropdown);
    min-width: 240px;
    max-width: 320px;
    max-height: 320px;
    overflow-y: auto;
    padding: var(--sp-space-2);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-lg);
}

.sp-filter-ribbon__group-search {
    width: 100%;
    margin-bottom: var(--sp-space-2);
    padding: var(--sp-space-1) var(--sp-space-2);
    background: var(--sp-bg-input);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
}

.sp-filter-ribbon__group-list {
    display: flex;
    flex-direction: column;
    gap: 1px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-filter-ribbon__group-item {
    margin: 0;
}

.sp-filter-ribbon__option {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-1) var(--sp-space-2);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    cursor: pointer;
}

.sp-filter-ribbon__option:hover {
    background: color-mix(in oklch, var(--sp-accent) 6%, transparent);
    color: var(--sp-text-primary);
}

.sp-filter-ribbon__option-label {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-filter-ribbon__option-count {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-filter-ribbon__group--empty {
    padding: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
}

.sp-filter-ribbon__group-title {
    font-size: var(--sp-text-sm);
    color: inherit;
}

.sp-filter-ribbon__group--empty {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
}
}

@layer components {

.sp-filter-ribbon__group-empty-text {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-style: italic;
}

.sp-filter-ribbon__actions {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
}
}



@layer components {

.sp-filter-ribbon__clear {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    text-decoration: none;
}

.sp-filter-ribbon__clear:hover {
    color: var(--sp-text-primary);
    text-decoration: underline;
}

.sp-filter-ribbon__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-1);
    width: 100%;
    margin: var(--sp-space-1) 0 0;
    padding: 0;
    list-style: none;
}

.sp-filter-ribbon__chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: var(--sp-space-05) var(--sp-space-2);
    background: color-mix(in oklch, var(--sp-accent) 8%, var(--sp-bg-surface));
    border: 1px solid color-mix(in oklch, var(--sp-accent) 30%, var(--sp-border-subtle));
    border-radius: var(--sp-radius-full);
    font-size: var(--sp-text-xs);
}

.sp-filter-ribbon__chip-group {
    color: var(--sp-text-tertiary);
}

.sp-filter-ribbon__chip-value {
    color: var(--sp-text-primary);
    font-weight: 600;
    max-width: 18ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-filter-ribbon__chip-remove {
    color: var(--sp-text-tertiary);
    text-decoration: none;
    font-weight: 700;
    line-height: 1;
    padding: 0 var(--sp-space-05);
}

.sp-filter-ribbon__chip-remove:hover {
    color: var(--sp-danger-strong);
}
}

@layer components {

.sp-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-space-2) var(--sp-density-gap);
    padding: var(--sp-space-2) var(--sp-density-cell-x);
    border-top: 1px solid var(--sp-border-subtle);
    background: var(--sp-bg-card-header);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-pagination__info { min-width: 0; }

.sp-pagination__controls {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin-left: auto;
}

.sp-pagination__current { color: var(--sp-text-secondary); }

.sp-pagination__size {
    font-size: var(--sp-text-2xs);
    padding: 0 var(--sp-space-1);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-input);
    color: var(--sp-text-secondary);
}

.sp-pagination .is-disabled {
    opacity: 0.45;
    pointer-events: none;
}

}

@layer components {

/* The generic ribbon reuses the identity ribbon's pills and panels; these
   rules only add what the generic form has that the identity one has not —
   a search box in the pill row, a per-pill active count, and the export
   glyph on a chip. */
.sp-ribbon {
    margin-block: var(--sp-space-2) var(--sp-space-3);
}

.sp-ribbon .sp-filter-ribbon__group-summary .sp-icon {
    color: var(--sp-text-tertiary);
}

.sp-ribbon .sp-filter-ribbon__group.is-active > .sp-filter-ribbon__group-summary {
    color: var(--sp-accent-text);
    background: var(--sp-accent-dim);
    border-color: transparent;
}

.sp-ribbon .sp-filter-ribbon__group.is-active > .sp-filter-ribbon__group-summary .sp-icon {
    color: var(--sp-accent-text);
}

.sp-ribbon__badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.1rem;
    height: 1.1rem;
    padding-inline: var(--sp-space-1);
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent);
    color: var(--sp-text-on-accent);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    font-variant-numeric: tabular-nums;
}

.sp-ribbon__search {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: 0 var(--sp-space-2) 0 var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    color: var(--sp-text-tertiary);
    min-width: 14rem;
    flex: 1 1 14rem;
    max-width: 26rem;
}

.sp-ribbon__search:focus-within {
    border-color: var(--sp-accent);
    box-shadow: 0 0 0 2px var(--sp-accent-dim);
}

.sp-ribbon__search-input {
    flex: 1;
    min-width: 0;
    padding: var(--sp-space-1) 0;
    border: 0;
    background: transparent;
    color: var(--sp-text-primary);
    font: inherit;
    font-size: var(--sp-text-sm);
}

.sp-ribbon__search-input:focus {
    outline: none;
}

.sp-ribbon__chip-export {
    display: inline-flex;
    color: var(--sp-text-tertiary);
    text-decoration: none;
}

.sp-ribbon__chip-export:hover,
.sp-ribbon__chip-export:focus-visible {
    color: var(--sp-accent-text);
}

}

@layer components {

/* The scope selector the AI-activity pages share. It sits above the page header
   because the scope decides what the page is about, not how it is filtered. */

.sp-scope-filter {
    display: flex;
    align-items: flex-end;
    flex-wrap: wrap;
    gap: var(--sp-density-gap);
    padding: var(--sp-space-3) 0;
}

.sp-scope-filter__scope {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    min-width: 0;
}

/* The reset layer's [hidden] loses to this block's display: flex, so the
   attribute the script toggles needs restating at the same layer. */
.sp-scope-filter__scope[hidden] { display: none; }

.sp-scope-filter__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
}

/* A chip is a link that removes the filter it names, so it reads as a value and
   behaves as a control. */
.sp-scope-filter__chip {
    padding: var(--sp-space-05) var(--sp-space-2);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-primary);
    text-decoration: none;
    background: var(--sp-bg-tertiary);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
}

.sp-scope-filter__chip:hover { border-color: var(--sp-border-strong); }

.sp-scope-filter__label {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    letter-spacing: var(--sp-tracking-wide);
    text-transform: uppercase;
    color: var(--sp-text-tertiary);
}

.sp-scope-filter__ranges {
    display: flex;
    align-items: center;
    gap: var(--sp-space-1);
    margin-left: auto;
}

}

@layer responsive {

/* The sort bar exists only for card tables on a phone, where the header row
   and its sort links are hidden. Above that width the header does the job. */
.sp-table__sort-bar { display: none; }

@media (max-width: 48rem) {

    /* A phone cannot show twelve columns side by side, so each row becomes its
       own card. The wrapper stops being the card and the scroller stops
       scrolling, because nothing is wider than the screen any more. Every rule
       here is rooted in data-cards, which table-cards.js sets only once each
       cell carries its column label, so without the script nothing changes. */
    .sp-table[data-cards="ready"] {
        background: transparent;
        box-shadow: none;
        border-radius: 0;
        overflow: visible;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll {
        overflow: visible;
        background-image: none;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el {
        display: block;
        width: auto;
        min-width: 0;
    }

    /* The header is clipped rather than removed, so assistive technology still
       reads the column names that the cards now repeat visually per cell. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > thead th {
        position: static;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) {
        display: grid;
        gap: var(--sp-space-3);
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tfoot {
        margin-block-start: var(--sp-space-3);
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr);
        row-gap: var(--sp-space-1);
        position: relative;
        padding: var(--sp-space-3) var(--sp-space-4);
        background: var(--sp-bg-surface);
        border-radius: var(--sp-corners-md);
        box-shadow: var(--sp-shadow-card);
    }

    /* The tint is layered over the surface rather than replacing it, because
       the accent wash is translucent and the page would show through. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr.is-selected {
        background: linear-gradient(var(--sp-accent-dim), var(--sp-accent-dim)), var(--sp-bg-surface);
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr:focus-visible {
        outline: 2px solid var(--sp-accent);
        outline-offset: 2px;
    }

    /* Each cell is a label/value pair. Every desktop clamp is undone here: the
       nowrap, the ellipsis and the column ceilings existed to keep a row one
       line tall, and a card has the height to show the whole value instead. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td {
        display: grid;
        grid-template-columns: minmax(7rem, 38%) minmax(0, 1fr);
        column-gap: var(--sp-space-3);
        justify-items: start;
        align-items: start;
        position: static;
        width: auto;
        min-width: 0;
        max-width: none;
        padding: var(--sp-space-1) 0;
        border: 0;
        background: transparent;
        box-shadow: none;
        color: var(--sp-text-secondary);
        font-weight: var(--sp-font-normal);
        text-align: left;
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
        overflow-wrap: anywhere;
    }

    /* The label spans a dozen implicit rows so every child of the cell, text
       runs included, auto-places into the value column beneath the last one. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td[data-label]::before {
        content: attr(data-label);
        grid-column: 1;
        grid-row: 1 / span 12;
        font-size: var(--sp-text-2xs);
        font-weight: var(--sp-font-semibold);
        line-height: var(--sp-density-cell-line);
        text-transform: uppercase;
        letter-spacing: var(--sp-tracking-wide);
        color: var(--sp-text-tertiary);
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td[data-label] > * {
        grid-column: 2;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td:not([data-label]) {
        display: block;
    }

    /* The identity cell is the card's title: full width, first, and set in
       the body size so a reader scanning cards reads names, not labels. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td[data-card-cell="title"] {
        order: -2;
        padding-block: 0 var(--sp-space-2);
        margin-block-end: var(--sp-space-1);
        border-bottom: 1px solid var(--sp-border-subtle);
        font-size: var(--sp-text-base);
        font-weight: var(--sp-font-medium);
        color: var(--sp-text-primary);
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr:has(> td[data-card-cell="check"]) > td[data-card-cell="title"] {
        padding-inline-end: var(--sp-space-8);
    }

    /* The selection box sits in the card's corner with a full touch target,
       so ticking a row never lands on the title link beside it. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr > td[data-card-cell="check"] {
        position: absolute;
        inset-block-start: var(--sp-space-1);
        inset-inline-end: var(--sp-space-1);
        display: grid;
        place-items: center;
        min-width: 44px;
        min-height: 44px;
        padding: 0;
    }
}

}

@layer responsive {

@media (max-width: 48rem) {

    /* A number or a date reads against its label from the right edge, which
       is where a reader's eye compares one card's figure with the next. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td:is(.sp-table__cell--num, .sp-table__cell--date, .sp-col-date, .sp-col-currency) {
        justify-items: end;
        text-align: right;
        font-variant-numeric: tabular-nums;
    }

    /* The label keeps the left column's alignment so every label in a card
       lines up, whichever way its value reads. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td:is(.sp-table__cell--num, .sp-table__cell--date, .sp-col-date, .sp-col-currency)::before {
        justify-self: start;
        text-align: left;
    }

    /* Stacked lines and badge rows were forced onto one line to keep a table
       row short; inside a card they wrap instead of being clipped. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td.sp-table__cell--stacked > *,
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td .sp-badge-stack__row {
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td .sp-badge-stack__row {
        flex-wrap: wrap;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td.sp-table__cell--spark {
        width: auto;
    }

    /* Row actions become the card's footer. They were pinned to the right edge
       of a scrolling table; a card does not scroll, so they sit last instead,
       with buttons at full touch height rather than the table's line height. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td.sp-table__cell--actions {
        order: 99;
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        justify-content: flex-end;
        gap: var(--sp-space-2);
        padding-block: var(--sp-space-2) 0;
        margin-block-start: var(--sp-space-1);
        border-top: 1px solid var(--sp-border-subtle);
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td.sp-table__cell--actions::before {
        content: none;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td.sp-table__cell--actions:not(:has(*)) {
        display: none;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > :is(tbody, tfoot) > tr > td.sp-table__cell--actions .sp-btn {
        min-width: 44px;
        min-height: 44px;
        height: auto;
    }

    /* A closed detail row is hidden outright; an open one is drawn as the
       lower half of the summary card above it, pulled up across the gap. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr.sp-table__row-detail:not(.is-open) {
        display: none;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr.sp-table__row-detail {
        display: block;
        padding: 0;
        margin-block-start: calc(-1 * var(--sp-space-3));
        border-start-start-radius: 0;
        border-start-end-radius: 0;
        background: var(--sp-bg-surface-raised);
        overflow: hidden;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr.sp-table__row--expand.is-expanded {
        border-end-start-radius: 0;
        border-end-end-radius: 0;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr.sp-table__row-detail > td {
        display: block;
        padding: 0;
    }

    /* The nested table inside an open detail keeps its desktop layout, since
       every card rule stops at the outer table, and scrolls sideways here. */
    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr.sp-table__row-detail.is-open .sp-table__detail-inner {
        overflow-x: auto;
    }

    .sp-table[data-cards="ready"] > .sp-table__scroll > .sp-table__el > tbody > tr.sp-table__empty > td {
        display: block;
        padding: var(--sp-space-6) 0;
        text-align: center;
        color: var(--sp-text-tertiary);
    }

    /* Pagination under a list of cards is a card of its own, with the page
       controls spread across it and every control at touch height. */
    .sp-table[data-cards="ready"] > .sp-pagination {
        flex-direction: column;
        align-items: stretch;
        margin-block-start: var(--sp-space-3);
        padding: var(--sp-space-3) var(--sp-space-4);
        border-top: 0;
        border-radius: var(--sp-corners-md);
        box-shadow: var(--sp-shadow-card);
    }

    .sp-table[data-cards="ready"] > .sp-pagination .sp-pagination__controls {
        justify-content: space-between;
        margin-left: 0;
    }

    .sp-table[data-cards="ready"] > .sp-pagination :is(.sp-btn, .sp-pagination__size) {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
    }

    /* The header row and its sort links are hidden on a phone, so the same
       sort orders are offered as one select above the first card. */
    .sp-table[data-cards="ready"] > .sp-table__sort-bar {
        display: flex;
        align-items: center;
        gap: var(--sp-space-2);
        margin-block-end: var(--sp-space-3);
        font-size: var(--sp-text-sm);
        color: var(--sp-text-secondary);
    }

    .sp-table[data-cards="ready"] > .sp-table__sort-bar .sp-table__sort-select {
        flex: 1 1 auto;
        min-width: 0;
        min-height: 44px;
        padding-inline: var(--sp-space-3);
        border: 1px solid var(--sp-border-default);
        border-radius: var(--sp-corners-sm);
        background: var(--sp-bg-input);
        color: var(--sp-text-primary);
        font-family: inherit;
        font-size: max(1rem, var(--sp-text-base));
    }

    /* A table that opts out of cards keeps scrolling sideways, so the swipe
       must stop at its edge instead of dragging the page with it. */
    .sp-table--scroll > .sp-table__scroll {
        overscroll-behavior-x: contain;
    }

    /* Its first column stays pinned while the rest scroll under it, which is
       what tells a reader whose row the far-right figures belong to. */
    .sp-table--scroll > .sp-table__scroll > .sp-table__el > * > tr:not(.sp-table__row-detail) > :first-child {
        position: sticky;
        left: 0;
        z-index: var(--sp-z-sticky);
        background: var(--sp-bg-surface);
    }

    .sp-table--scroll > .sp-table__scroll > .sp-table__el > thead > tr > th:first-child {
        background: var(--sp-bg-card-header);
    }
}

}

@layer components {

.sp-table__el th[aria-sort] { cursor: pointer; }

/* The sort link wraps with its header rather than forcing one line. */
/* The sort control fills its header, padding included. As an inline link it
   occupied only the text, so a click anywhere else in a wide column landed on
   the header's padding and did nothing — and a header that looks sortable and
   ignores half its own clicks is worse than one that is not sortable at all.
   The negative margin is what reclaims the padding the th already owns; the
   link then re-applies it so the text stays where it was. */
.sp-table__sort {
    display: block;
    margin: calc(-1 * var(--sp-density-cell-y)) calc(-1 * var(--sp-density-cell-x));
    padding: var(--sp-density-cell-y) var(--sp-density-cell-x);
    color: inherit;
    text-align: inherit;
    text-decoration: none;
    white-space: normal;
}

.sp-table__sort:focus-visible {
    outline: 2px solid var(--sp-accent);
    outline-offset: -2px;
}
.sp-table__el th[aria-sort]:hover { color: var(--sp-text-secondary); }

.sp-table__sort-icon {
    display: inline-block;
    margin-left: var(--sp-space-1);
    opacity: 0.3;
    transition: opacity var(--sp-duration-fast);
}

.sp-table__el th[aria-sort="ascending"] .sp-table__sort-icon,
.sp-table__el th[aria-sort="descending"] .sp-table__sort-icon {
    opacity: 1;
    color: var(--sp-accent-text);
}

/* The width sizes the column and applies to the header too; nowrap and the
   ceiling are data-cell rules, because a header that cannot wrap and cannot
   overflow is a header that gets cut in half. */
.sp-table__cell--num {
    width: 7ch;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

td.sp-table__cell--num { white-space: nowrap; }

.sp-table__el th.sp-table__cell--num { text-align: right; }

/* A timestamp that wraps doubles the row height and halves how much of the
   table a reader sees at once, which is the whole point of the compact table. */
.sp-table__cell--date {
    width: 12ch;
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-table__cell--mono {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-2xs);
}

/* An id is recognised by its first characters, so it is clipped rather than
   given the width its full length would demand. */
.sp-table__cell--id {
    width: 14ch;
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-2xs);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-table__cell--muted { color: var(--sp-text-tertiary); }
.sp-table__cell--primary { color: var(--sp-text-primary); }
.sp-table__cell--secondary { color: var(--sp-text-secondary); }
.sp-table__cell--flush { padding: 0; }

.sp-table__cell--stacked {
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
    min-width: 0;
}

/* Both lines of a stacked cell are single lines. The second one is a
   description the row does not depend on, so it is the one that gets clipped;
   left to wrap it pushed its row into the next one. */
.sp-table__cell--stacked > * {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Why: a `td` may never carry a display other than `table-cell`. Any other value
   pulls it out of the table box model, the browser wraps it in an anonymous cell,
   and the flex box then shrink-to-fits inside that cell instead of filling the
   column — so the cell's own background, zebra stripe included, stopped short and
   left a dead band the width of the remaining column. The class is also used on
   inner `div`s, where the flex container above is correct and load-bearing
   (`analytics-requests.hbs` relies on `align-items: flex-end`), so the correction
   is scoped to the `td` case rather than applied to the class. */
.sp-table__el td.sp-table__cell--stacked {
    display: table-cell;
}

/* The two lines stack because they are blocks, not because a flex container
   ordered them to. */
.sp-table__el td.sp-table__cell--stacked > * {
    display: block;
}

/* The gap the flex container used to draw between the two lines. */
.sp-table__el td.sp-table__cell--stacked > * + * {
    margin-block-start: 0.125rem;
}

.sp-table__cell--spark {
    width: 6rem;
    min-width: 6rem;
}

.sp-table__cell--spark svg { display: block; width: 100%; height: 1.25rem; }

.sp-table__el td.sp-table__cell--actions,
.sp-table__el th.sp-table__cell--actions {
    position: sticky;
    right: 0;
    z-index: var(--sp-z-sticky-header);
    width: 1%;
    white-space: nowrap;
    text-align: right;
    background: var(--sp-bg-surface);
    border-left: 1px solid var(--sp-border-subtle);
}

.sp-table__el th.sp-table__cell--actions { background: var(--sp-bg-card-header); }

.sp-table__el tbody tr:nth-child(even) td.sp-table__cell--actions,
.sp-table__el tbody tr:hover td.sp-table__cell--actions {
    background: var(--sp-bg-surface);
}

.sp-table__el .sp-col-checkbox    { width: 2.5rem; }
.sp-table__el .sp-col-status { width: 9ch; }

/* The ceilings are on data cells only. On a th they clipped the header, and a
   header is the one thing that may never be clipped: it names the column, and
   the column is entitled to be as wide as its name. */
/* No ceiling on a number. Every cell is border-box, so a 9ch cap was 9ch less
   the 1.5ch of horizontal padding, and "$0.2964" came back as "$0.29…". A
   number's length is bounded by the formatter that produced it, which is a
   better bound than anything set here, and a truncated figure is worse than a
   wide column: it reads as a different, smaller number. */
.sp-table__el td.sp-table__cell--num { white-space: nowrap; }
.sp-table__el td.sp-table__cell--date { max-width: 16ch; white-space: nowrap; }
.sp-table__el td.sp-table__cell--id { max-width: 14ch; }
.sp-table__el td.sp-col-status { max-width: 12ch; }

/* A badge is a label, not a reason to widen a column. */
.sp-table__el .sp-badge {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
}
.sp-table__el .sp-col-thumbnail   { width: 3.5rem; min-width: 3.5rem; }
.sp-table__el .sp-col-date        { width: 6.5rem; min-width: 5.5rem; }
.sp-table__el .sp-col-currency    { width: 7rem;   min-width: 6rem; }
.sp-table__el .sp-col-status      { width: 7rem;   min-width: 5.5rem; }
.sp-table__el .sp-col-boolean     { width: 4.5rem; min-width: 4rem; }
.sp-table__el .sp-col-badge_count { width: 5rem;   min-width: 4.5rem; }
.sp-table__el .sp-col-tags        { width: 9.5rem; min-width: 7.5rem; }
.sp-table__el .sp-col-text        { min-width: 6.5rem; }

.sp-table__el td.sp-u-truncate {
    max-width: 18rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

}

@layer components {

/* An expandable row is the trigger; the detail row beneath it is a one-row
   grid whose track animates 0fr -> 1fr, so the nested table slides open to
   its real height and the summary row above it settles into a raised state. */
.sp-table__row--expand td {
    transition: background var(--sp-duration-fast) var(--sp-ease-in-out),
                box-shadow var(--sp-duration-fast) var(--sp-ease-in-out);
}

.sp-table__el tbody .sp-table__row--expand:hover td {
    background: color-mix(in oklch, var(--sp-accent) 5%, transparent);
}

.sp-table__row--expand:focus-visible {
    outline: none;
}

.sp-table__row--expand:focus-visible td {
    box-shadow: inset 0 0 0 2px var(--sp-accent);
}

.sp-table__el tbody .sp-table__row--expand.is-expanded td {
    background: var(--sp-bg-surface-raised);
    border-bottom-color: transparent;
    box-shadow: inset 0 1px 0 var(--sp-border-subtle);
}

.sp-table__el tbody .sp-table__row--expand.is-expanded td:first-child {
    box-shadow: inset 3px 0 0 var(--sp-accent), inset 0 1px 0 var(--sp-border-subtle);
}

.sp-table__el tbody .sp-table__row--expand.is-expanded:hover td {
    background: color-mix(in oklch, var(--sp-accent) 4%, var(--sp-bg-surface-raised));
}

.sp-table__row-toggle {
    width: var(--sp-space-8);
    height: var(--sp-space-8);
    border-radius: var(--sp-radius-full);
    color: var(--sp-text-tertiary);
    transition: background var(--sp-duration-fast) var(--sp-ease-in-out),
                color var(--sp-duration-fast) var(--sp-ease-in-out),
                transform var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-table__row--expand:hover .sp-table__row-toggle,
.sp-table__row-toggle:hover {
    background: var(--sp-accent-dim);
    color: var(--sp-accent-text);
}

.sp-table__row-toggle:active { transform: scale(0.92); }

.sp-table__row-toggle .sp-icon {
    width: var(--sp-space-4);
    height: var(--sp-space-4);
    transition: transform var(--sp-duration-normal) var(--sp-ease-spring);
}

.sp-table__row-toggle[aria-expanded="true"] .sp-icon {
    transform: rotate(180deg);
}

.sp-table__row-toggle[aria-expanded="true"] {
    background: var(--sp-accent-dim);
    color: var(--sp-accent-text);
}

.sp-table__row-detail[hidden] { display: none; }

.sp-table__el tbody .sp-table__row-detail > td {
    padding: 0;
    border-bottom: none;
    background: var(--sp-bg-surface-raised);
}

.sp-table__el tbody .sp-table__row-detail:hover > td {
    background: var(--sp-bg-surface-raised);
}

.sp-table__detail-panel {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--sp-duration-moderate) var(--sp-ease-out);
}

.sp-table__detail-inner {
    min-height: 0;
    overflow: hidden;
    visibility: hidden;
    opacity: 0;
    transform: translateY(calc(-1 * var(--sp-space-2)));
    transition: visibility 0s linear var(--sp-duration-moderate),
                opacity var(--sp-duration-normal) var(--sp-ease-out),
                transform var(--sp-duration-moderate) var(--sp-ease-out);
}

.sp-table__row-detail.is-open .sp-table__detail-panel {
    grid-template-rows: 1fr;
}

.sp-table__row-detail.is-open .sp-table__detail-inner {
    visibility: visible;
    opacity: 1;
    transform: none;
    transition-delay: 0s;
    border-bottom: 1px solid var(--sp-border-subtle);
    box-shadow: inset 0 var(--sp-space-2) var(--sp-space-3) calc(-1 * var(--sp-space-2)) var(--sp-shadow-a04);
}

/* The nested table's rows enter one after another so the panel reads as
   content arriving, not a block snapping into place. */
.sp-table__row-detail.is-open .sp-table__el--nested tbody tr {
    animation: sp-row-enter var(--sp-duration-moderate) var(--sp-ease-out) both;
}

.sp-table__row-detail.is-open .sp-table__el--nested tbody tr:nth-child(2) { animation-delay: var(--sp-duration-instant); }

.sp-table__row-detail.is-open .sp-table__el--nested tbody tr:nth-child(3) { animation-delay: var(--sp-duration-fast); }

.sp-table__row-detail.is-open .sp-table__el--nested tbody tr:nth-child(n+4) { animation-delay: var(--sp-duration-normal); }

@keyframes sp-row-enter {
    from { opacity: 0; transform: translateY(calc(-1 * var(--sp-space-1))); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .sp-table__detail-panel,
    .sp-table__detail-inner,
    .sp-table__row-toggle .sp-icon {
        transition: none;
    }
    .sp-table__row-detail.is-open .sp-table__el--nested tbody tr {
        animation: none;
    }
}

}

@layer components {

.sp-pagination__info {
    display: flex;
    align-items: center;
    gap: var(--sp-space-4);
}

.sp-pagination__controls {
    display: flex;
    align-items: center;
    gap: var(--sp-space-1);
}

.sp-pagination__controls button {
    background: none;
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    color: var(--sp-text-secondary);
    padding: var(--sp-space-1) var(--sp-space-3);
    cursor: pointer;
    font-size: var(--sp-text-sm);
    font-family: inherit;
    transition: background var(--sp-duration-fast), border-color var(--sp-duration-fast), color var(--sp-duration-fast);
}

.sp-pagination__controls button:hover:not(:disabled) {
    background: color-mix(in oklch, var(--sp-warm-900) 4%, transparent);
    border-color: var(--sp-border-strong);
    color: var(--sp-text-primary);
}

.sp-pagination__controls button:disabled {
    opacity: 0.3;
    cursor: default;
}

.sp-pagination__controls .is-disabled {
    opacity: 0.4;
    pointer-events: none;
}

.sp-pagination__controls .sp-pagination__current {
    padding: var(--sp-space-1) var(--sp-space-3);
    color: var(--sp-accent-text);
    font-weight: 600;
}

.sp-pagination__size {
    background: transparent;
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    color: var(--sp-text-secondary);
    padding: var(--sp-space-1) var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-family: inherit;
}

.sp-pagination__size:focus-visible,
.sp-pagination__controls button:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px var(--sp-accent);
}

.sp-table__el tfoot tr {
    background: var(--sp-bg-surface-raised);
}

.sp-table__el tfoot td {
    background: inherit;
    border-top: 2px solid var(--sp-border-default);
    border-bottom: none;
    font-weight: 700;
    color: var(--sp-text-primary);
    padding: var(--sp-space-3) var(--sp-space-4);
    font-size: var(--sp-text-sm);
    white-space: nowrap;
}

.sp-table__el tfoot td.sp-table__cell--actions {
    background: inherit;
}

.sp-table__el .sp-col-checkbox {
    width: 40px;
    min-width: 40px;
    max-width: 40px;
    text-align: center;
    padding: var(--sp-space-2);
}

.sp-col-checkbox input[type="checkbox"] {
    width: 16px;
    height: 16px;
}

.sp-table__el .sp-col-multiline {
    white-space: normal;
    line-height: 1.4;
}

.sp-table__cell--primary {
    font-weight: 500;
    color: var(--sp-text-primary);
}

.sp-table__cell--secondary {
    font-size: 0.8em;
    color: var(--sp-text-tertiary);
    margin-top: 0.125rem;
}
}



@layer components {

.sp-user-cell-text {
    display: inline-flex;
    flex-direction: column;
    line-height: 1.2;
    min-width: 0;
}

.sp-user-cell-name {
    color: var(--sp-text-primary);
    font-weight: 500;
}

.sp-user-cell-email {
    font-size: 0.78em;
    color: var(--sp-text-tertiary);
    margin-top: 0.1rem;
}

.sp-table__el td.sp-col-model,
.sp-table__el td.sp-col-client {
    white-space: nowrap;
}

.sp-pagination__info {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-session-current {
    margin-bottom: var(--sp-space-4);
}
}

@layer responsive {

@media (hover: none) {
    .sp-table__el tr:hover td {
        background: inherit;
    }
}
}

@layer components {

/* Drawn by hand: the UA checkbox under color-scheme light is a hairline grey
   square that vanished against the row, so a selection column read as empty. */
.sp-select__box {
    appearance: none;
    width: 1rem;
    height: 1rem;
    margin: 0;
    border: 1.5px solid var(--sp-border-strong);
    border-radius: var(--sp-radius-sm);
    background: var(--sp-bg-surface);
    cursor: pointer;
    vertical-align: middle;
    display: inline-grid;
    place-content: center;
    transition: background var(--sp-duration-fast), border-color var(--sp-duration-fast);
}

.sp-select__box:hover {
    border-color: var(--sp-accent);
}

.sp-select__box:focus-visible {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
}

.sp-select__box:checked,
.sp-select__box:indeterminate {
    border-color: var(--sp-accent);
    background: var(--sp-accent);
}

.sp-select__box::before {
    content: "";
    width: 0.6rem;
    height: 0.6rem;
    background: var(--sp-text-on-accent);
    transform: scale(0);
    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
    transition: transform var(--sp-duration-fast);
}

.sp-select__box:checked::before {
    transform: scale(1);
}

.sp-select__box:indeterminate::before {
    transform: scale(1);
    clip-path: inset(40% 10% 40% 10%);
}

.sp-table__el tr.is-selected > td {
    background: var(--sp-accent-dim);
}

/* Sticks to the viewport foot so a selection made three screens down still
   has its actions in reach; hidden entirely until the first tick so an
   unselected table looks exactly as it did. */
.sp-bulk-bar {
    position: sticky;
    inset-block-end: var(--sp-space-3);
    z-index: var(--sp-z-sticky);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-3);
    padding: var(--sp-space-2) var(--sp-space-4);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface-overlay);
    box-shadow: var(--sp-shadow-float);
}

.sp-bulk-bar[hidden] {
    display: none;
}

.sp-bulk-bar__count {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-bulk-bar__count b {
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-bulk-bar__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-bulk-bar__form {
    display: contents;
}

.sp-bulk-bar .sp-btn .sp-icon {
    margin-inline-end: var(--sp-space-1);
}

}

@layer components {

/* The card IS the table: .sp-table is the surface, so the border and shadow can
   never paint at a different width from the rows inside it. The edge fades live
   on .sp-table__scroll, which is the element that actually scrolls, so they
   cannot float in the middle of the page when the table does not overflow. */

.sp-table {
    background: var(--sp-bg-surface);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
    margin-bottom: var(--sp-density-section);
    max-width: 100%;
    overflow: hidden;
}

.sp-table__scroll {
    overflow-x: auto;
    max-width: 100%;
    background-image:
        linear-gradient(to right, var(--sp-bg-surface), transparent),
        linear-gradient(to left, var(--sp-bg-surface), transparent),
        linear-gradient(to right, var(--sp-shadow-a10), transparent),
        linear-gradient(to left, var(--sp-shadow-a10), transparent);
    background-position: left center, right center, left center, right center;
    background-repeat: no-repeat;
    background-size: 2rem 100%, 2rem 100%, 0.75rem 100%, 0.75rem 100%;
    background-attachment: local, local, scroll, scroll;
}

.sp-table__el {
    width: 100%;
    border-collapse: collapse;
    /* Auto, with every cell clamped. Fixed layout was the wrong instrument: it
       divides the table equally among the columns that have no width, so a name
       column and a two-character count column got the same share and the names
       clipped on twenty-one pages. What had actually caused the overlap it was
       brought in to fix was unclamped flex children in stacked cells, and that
       is fixed at the cell. Auto layout sizes a column to its content, so the
       primary label gets the room it needs and a header can never truncate,
       while --sp-table-cell-max stops one long description taking the table. */
    table-layout: auto;
    font-size: var(--sp-text-sm);
}

.sp-table__el th {
    position: sticky;
    top: 0;
    z-index: var(--sp-z-sticky);
    background: var(--sp-bg-card-header);
    padding: var(--sp-density-cell-y) var(--sp-density-cell-x);
    text-align: left;
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
    border-bottom: 1px solid var(--sp-border-default);
    /* Headers wrap rather than refusing to. A nowrap header sets a floor under
       its whole column, and "Most recent reason" alone was forcing a table past
       the viewport; wrapping costs one line once, at the top, and still never
       truncates. */
    white-space: normal;
    overflow-wrap: break-word;
    /* A header is never clipped. The typed cell rules set nowrap and a ceiling
       for data, and applied to a th as well they cut the column's own name in
       half — "Requests" came back as 72px of an 85px word. These three undo any
       of that which reaches a header. */
    overflow: visible;
    text-overflow: clip;
    max-width: none;
    vertical-align: bottom;
    user-select: none;
}

.sp-table__el td {
    /* No explicit height. Padding and line-height give the 2rem row on their
       own, and a fixed height here combined with the overflow clipping below
       cut two-line cells off mid-glyph on the plugin and marketplace listings.
       --sp-density-row remains the number those two are tuned to. */
    padding: var(--sp-density-cell-y) var(--sp-density-cell-x);
    border-bottom: 1px solid var(--sp-border-subtle);
    line-height: var(--sp-density-cell-line);
    color: var(--sp-text-secondary);
    vertical-align: middle;
    min-width: 0;
    /* Clipping needs all three: without nowrap the text wraps inside the fixed
       column instead of ellipsing, which is what turned a 32px row into 54px on
       the users listing. A cell whose text must wrap opts in with --wrap. */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: var(--sp-table-cell-max);
}

/* A row is padding plus one line box. An inline control sitting on the text
   baseline adds the descender gap below itself, so a 20px badge in a 20px line
   made a 25px line box and a 37px row on seven pages. Sizing the controls to the
   line and centring them on it removes both the gap and the guesswork. */
.sp-table__el td .sp-badge,
.sp-table__el td .sp-btn,
.sp-table__el td code,
.sp-table__el td .sp-table__sort-icon {
    height: var(--sp-density-cell-line);
    vertical-align: middle;
}

/* The first column that is not a checkbox carries the row's identity, so it is
   the one that absorbs the slack rather than the one that pays for it. Named as
   a class too, for a table whose identity column is not first. */
/* ...unless it has already been typed. A date, a number or a status cell names
   its own width, and the 22ch floor applied over the top of that widened the
   Started column past the 6.5rem it asks for. A typed column is not slack. */
.sp-table__el td:first-child:not(:has(input)):not(.sp-col-date):not(.sp-col-status):not(.sp-table__cell--date):not(.sp-table__cell--num),
.sp-table__el td:has(input) + td,
.sp-table__el td.sp-table__cell--primary {
    max-width: none;
    min-width: 22ch;
}

.sp-table__el tbody tr:last-child td { border-bottom: none; }

.sp-table__el td:first-child {
    color: var(--sp-text-primary);
    font-weight: var(--sp-font-medium);
}

.sp-table__el tbody tr:nth-child(even) td {
    background: color-mix(in oklch, var(--sp-shadow-color) 2%, transparent);
}

.sp-table__el tbody tr:hover td {
    background: color-mix(in oklch, var(--sp-shadow-color) 4%, transparent);
}

.sp-table__el tr.is-selected td {
    background: var(--sp-accent-dim);
}

.sp-table__link {
    color: var(--sp-text-primary);
    text-decoration: none;
}

.sp-table__link:hover { color: var(--sp-accent-text); text-decoration: underline; }

.sp-table__row--click,
.sp-table__row--expand { cursor: pointer; }

.sp-table__empty td {
    padding: var(--sp-space-8) var(--sp-space-4);
    text-align: center;
    color: var(--sp-text-tertiary);
}

}

@layer components {

.sp-time-range {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-3);
    margin-bottom: var(--sp-space-4);
}

.sp-time-range__presets {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: var(--sp-space-05);
    background: var(--sp-bg-surface-raised);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
}

.sp-time-range__custom {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: end;
    gap: var(--sp-space-2);
}

.sp-time-range__custom[hidden] {
    display: none;
}

.sp-time-range__label {
    display: inline-flex;
    flex-direction: column;
    gap: var(--sp-space-05);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-time-range__label-text {
    font-size: var(--sp-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--sp-text-tertiary);
}

.sp-time-range__input {
    padding: var(--sp-space-1) var(--sp-space-2);
    background: var(--sp-bg-input);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
}

.sp-time-range__input:focus {
    outline: 2px solid color-mix(in oklch, var(--sp-accent) 40%, transparent);
    border-color: var(--sp-accent);
}

.sp-time-range__btn {
    display: inline-flex;
    align-items: center;
    padding: var(--sp-space-1) var(--sp-space-3);
    border-radius: var(--sp-radius-full);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    text-decoration: none;
    user-select: none;
    transition: background var(--sp-duration-fast), color var(--sp-duration-fast);
}
.sp-time-range__btn:hover {
    color: var(--sp-text-primary);
    background: color-mix(in oklch, var(--sp-accent) 6%, transparent);
}

.sp-time-range__btn--active {
    color: var(--sp-accent-text);
    background: var(--sp-accent-dim);
    font-weight: var(--sp-font-semibold);
    /* The button has no border, so a border-color alone drew nothing: the
       active pill was a tint a shade off its neighbours. An inset ring is
       the edge that makes it unmistakable. */
    box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--sp-accent) 40%, transparent);
}

}

@layer components {

/* Shared by every entity detail page that opens with a back link and a
   fact strip (governance audit, request, trace). They used to live in the
   context-detail page file and vanished from those pages when it was
   replaced by the conversation reader. */

.sp-back-link {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-medium);
    color: var(--sp-text-tertiary);
    margin-bottom: var(--sp-space-3);
    transition: color var(--sp-duration-fast);
}

.sp-back-link:hover {
    color: var(--sp-accent-text);
}

.sp-trace-detail__summary {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-2) var(--sp-space-4);
    padding: var(--sp-space-3) var(--sp-space-4);
    margin: var(--sp-space-4) 0 var(--sp-space-5);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
}

.sp-trace-detail__field {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
    min-width: 0;
}

.sp-trace-detail__label {
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
    white-space: nowrap;
}

.sp-trace-detail__field a {
    color: var(--sp-text-primary);
    text-decoration: none;
}

.sp-trace-detail__field a:hover {
    color: var(--sp-accent-text);
    text-decoration: underline;
}

}

@layer responsive {

/* On a phone the fact strip reads as a list, one fact per line, because a
   wrapped flex row left labels orphaned at the end of the line above. */
@media (max-width: 48rem) {
    .sp-trace-detail__summary {
        flex-direction: column;
        align-items: stretch;
        gap: var(--sp-space-2);
        padding: var(--sp-space-2) var(--sp-space-3);
    }

    .sp-trace-detail__field {
        flex-wrap: wrap;
    }
}

}

@layer components {

.sp-notice {
    padding: var(--sp-space-3) var(--sp-space-4);
    margin-bottom: var(--sp-space-5);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-left: 4px solid var(--sp-text-tertiary);
    border-radius: 0 var(--sp-radius-sm) var(--sp-radius-sm) 0;
    color: var(--sp-text-secondary);
}
.sp-notice p { margin: var(--sp-space-1) 0 0; }

.sp-notice--err {
    border-left-color: var(--sp-danger);
    background: var(--sp-danger-dim);
}
.sp-notice--warn {
    border-left-color: var(--sp-warning);
    background: color-mix(in oklch, var(--sp-warning) 10%, var(--sp-bg-surface));
}

.sp-notice__title {
    margin: 0;
    font-size: var(--sp-text-base);
    font-weight: 600;
    color: var(--sp-text-primary);
}
.sp-notice--err .sp-notice__title { color: var(--sp-danger-strong); }

/* The trace table kept its own fixed layout and its own header nowrap after the
   shared table gave both up, which is why it stayed the last page with clipped
   labels and headers while every other listing went to zero. It follows the
   component now; what it still owns is its column widths. */
.sp-trace-table {
    width: 100%;
}

.sp-trace-table td {
    padding: var(--sp-density-cell-y) var(--sp-density-cell-x);
    vertical-align: middle;
}

.sp-trace-table td {
    white-space: nowrap;
}

.sp-trace-table .sp-table__cell--stacked > * {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-trace-table .sp-col-started   { width: 8.5rem; }

.sp-trace-table .sp-col-trace     { min-width: 11rem; }
.sp-trace-table .sp-col-identity  { width: 13rem; }
.sp-trace-table .sp-col-model     { width: 11.5rem; }
.sp-trace-table .sp-col-spans     { width: 8rem; }
.sp-trace-table .sp-col-tokens,
.sp-trace-table .sp-col-cost,
.sp-trace-table .sp-col-duration {
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.sp-trace-table .sp-col-tokens    { width: 8.5rem; }
.sp-trace-table .sp-col-cost      { width: 7rem; }
.sp-trace-table .sp-col-duration  { width: 8.5rem; }
.sp-trace-table .sp-col-status    { width: 8.5rem; }

.sp-trace-table .sp-col-tokens .sp-table__cell--stacked,
.sp-trace-table .sp-col-duration .sp-table__cell--stacked {
    align-items: flex-end;
}

.sp-trace-table tbody tr {
    position: relative;
}

.sp-trace-row__id {
    text-decoration: none;
    color: var(--sp-text-primary);
}
.sp-trace-row__id:hover { color: var(--sp-accent-text); }

.sp-trace-row__id::after {
    content: "";
    position: absolute;
    inset: 0;
}

.sp-trace-row__id:focus-visible::after {
    outline: 2px solid var(--sp-accent);
    outline-offset: -2px;
    border-radius: var(--sp-radius-sm);
}

.sp-trace-table .sp-col-identity [title],
.sp-trace-table .sp-col-model [title],
.sp-trace-row__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    justify-content: flex-end;
}

.sp-trace-table .sp-table__cell--muted { color: var(--sp-text-tertiary); }

@media (max-width: 1400px) {
    .sp-trace-table .sp-col-model { display: none; }

    .sp-trace-table .sp-col-identity { width: 11rem; }
    .sp-trace-table .sp-col-spans    { width: 7rem; }
    .sp-trace-table .sp-col-tokens   { width: 7.5rem; }
    .sp-trace-table .sp-col-cost     { width: 5.5rem; }
    .sp-trace-table .sp-col-duration { width: 8rem; }
    .sp-trace-table .sp-col-status   { width: 7.5rem; }
}

@media (max-width: 1150px) {
    .sp-trace-table .sp-col-identity { display: none; }
}

.sp-table__el th .sp-table__sort {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    color: inherit;
    text-decoration: none;
}

.sp-table__el th .sp-table__sort:hover { color: var(--sp-text-primary); }

.sp-table__el th:not(.is-sorted) .sp-table__sort .sp-table__sort-icon { opacity: 0.35; }

.sp-table__el th:not(:has(.sp-table__sort)) { cursor: default; }

.sp-code-collapsible summary {
    cursor: pointer;
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-accent-text);
    padding: var(--sp-space-1) 0;
}
.sp-code-collapsible .sp-code-block {
    margin-top: var(--sp-space-2);
    max-height: 480px;
    overflow: auto;
}

}

@layer components {

.sp-actions-menu {
    position: relative;
    display: inline-block;
}

.sp-actions-dropdown {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: var(--sp-space-1);
    background: var(--sp-bg-surface-overlay);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-inner-md);
    box-shadow: var(--sp-shadow-float);
    z-index: var(--sp-z-dropdown);
    min-width: 140px;
    padding: var(--sp-space-1) 0;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    transition: opacity var(--sp-duration-fast) var(--sp-ease-in-out),
                visibility var(--sp-duration-fast) var(--sp-ease-in-out),
                transform var(--sp-duration-fast) var(--sp-ease-in-out);
}

.sp-actions-menu.is-open .sp-actions-dropdown {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

}



@layer components {

.sp-dialog {
    padding: 0;
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-lg);
    background: var(--sp-bg-surface-overlay);
    color: var(--sp-text-primary);
    box-shadow: var(--sp-shadow-float);
    max-width: min(480px, 92vw);
    width: 100%;
}

.sp-dialog::backdrop {
    background: var(--sp-overlay-medium);
    backdrop-filter: blur(4px);
}

.sp-dialog-form {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    padding: var(--sp-space-6);
}

.sp-dialog-form h3 {
    margin: 0;
    font-size: var(--sp-text-lg);
    font-weight: 600;
    color: var(--sp-text-primary);
}

.sp-dialog-form label {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-secondary);
}

.sp-dialog-form input,
.sp-dialog-form textarea {
    font: inherit;
    font-weight: 400;
    padding: var(--sp-space-2) var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    color: var(--sp-text-primary);
}

.sp-dialog-form input:focus,
.sp-dialog-form textarea:focus {
    outline: none;
    border-color: var(--sp-accent);
    box-shadow: 0 0 0 2px var(--sp-accent-dim);
}

.sp-dialog-form menu {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-space-2);
    margin: var(--sp-space-2) 0 0;
    padding: 0;
}

@media (prefers-reduced-motion: reduce) {
    .sp-actions-dropdown {
        transition: none;
    }
}
}

@layer responsive {

@media (hover: none) {
}
}

@layer components {

/* Named 07-dialog3-* so it bundles after 07-dialog2.css: the base
   .sp-dialog caps at 480px and, at equal specificity, the later rule wins. */
.sp-dialog.sp-export {
    max-width: min(1040px, 94vw);
    width: min(1040px, 94vw);
}

.sp-export__form {
    display: flex;
    flex-direction: column;
    max-height: 88vh;
}

.sp-export__head {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    padding: var(--sp-space-4) var(--sp-space-5);
    border-bottom: 1px solid var(--sp-border-subtle);
}

.sp-export__title {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0;
    font-size: var(--sp-text-lg);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}

.sp-export__title .sp-icon {
    color: var(--sp-accent-text);
}

/* The scope strip says when the download is a selection or one breakdown
   bucket rather than the window, because the window controls are disabled
   in that state and a reader must see why. */
.sp-export__scope {
    flex: 1;
    margin: 0;
    padding: var(--sp-space-1) var(--sp-space-3);
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent-dim);
    color: var(--sp-accent-text);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-medium);
}

.sp-export__close {
    margin-inline-start: auto;
}

.sp-export__panes {
    display: grid;
    grid-template-columns: 20rem minmax(0, 1fr);
    min-height: 0;
    flex: 1;
}

.sp-export__pane {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
    min-width: 0;
    padding: var(--sp-space-5);
    overflow: auto;
}

.sp-export__pane--what {
    border-inline-end: 1px solid var(--sp-border-subtle);
    background: var(--sp-bg-surface-raised);
}

.sp-export__pane--columns {
    gap: var(--sp-space-3);
}

.sp-export__field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
}

/* `[hidden]` in the base layer loses to `display: flex` here, which is how
   all three window fieldsets showed at once; the hidden state has to be
   declared at this layer's own specificity. `.is-hidden` is the script's
   belt-and-braces toggle for the same state. */
.sp-export__field[hidden],
.sp-export__custom[hidden],
.sp-export__columns[hidden],
.sp-export__column[hidden],
.sp-export__group[hidden],
.sp-export__scope[hidden],
.sp-export .is-hidden {
    display: none;
}

.sp-export__field > legend,
.sp-export__field > span {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: 0;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}

.sp-export__field > legend .sp-icon {
    color: var(--sp-text-tertiary);
}

.sp-export__description,
.sp-export__hint {
    margin: 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    line-height: var(--sp-leading-relaxed);
}

.sp-export__description {
    margin-top: calc(-1 * var(--sp-space-2));
}

.sp-export__dataset[hidden] + .sp-export__description {
    margin-top: 0;
}

.sp-export__presets {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-1);
    padding: var(--sp-space-05);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    align-self: flex-start;
}

.sp-export__preset {
    display: inline-flex;
    align-items: center;
    padding: var(--sp-space-1) var(--sp-space-3);
    border-radius: var(--sp-radius-full);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-normal);
    color: var(--sp-text-secondary);
    cursor: pointer;
    user-select: none;
    transition: background var(--sp-duration-fast), color var(--sp-duration-fast);
}

/* The pill is the control; the radio inside it is kept in the accessibility
   tree and the tab order, not drawn a second time. */
.sp-export__preset input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.sp-export__preset:hover {
    color: var(--sp-text-primary);
    background: color-mix(in oklch, var(--sp-accent) 6%, transparent);
}

.sp-export__preset:has(input:checked) {
    color: var(--sp-accent-text);
    background: var(--sp-accent-dim);
    font-weight: var(--sp-font-semibold);
    box-shadow: inset 0 0 0 1px color-mix(in oklch, var(--sp-accent) 40%, transparent);
}

.sp-export__preset:has(input:focus-visible) {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
}

}

@layer components {

.sp-export__field:disabled .sp-export__presets {
    opacity: 0.5;
}

.sp-export__field:disabled .sp-export__preset {
    cursor: not-allowed;
}

.sp-export__custom {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
    gap: var(--sp-space-3);
}

.sp-export__custom p {
    grid-column: 1 / -1;
}

.sp-export__foot {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    margin-top: auto;
    padding-top: var(--sp-space-3);
    border-top: 1px solid var(--sp-border-subtle);
}

.sp-export__preview {
    margin: 0;
    padding: var(--sp-space-2) var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-export__preview strong {
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-export__preview[data-tone="warn"] {
    color: var(--sp-warning-strong);
}

.sp-export__preview[data-tone="error"] {
    color: var(--sp-danger-strong);
}

.sp-export__download {
    justify-content: center;
    gap: var(--sp-space-2);
}

.sp-export__columns-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2) var(--sp-space-3);
}

.sp-export__columns-title {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}

.sp-export__columns-title .sp-icon {
    color: var(--sp-text-tertiary);
}

.sp-export__columns-count {
    font-weight: var(--sp-font-normal);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-export__filter {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    flex: 1 1 10rem;
    max-width: 18rem;
    padding: 0 var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface);
    color: var(--sp-text-tertiary);
}

.sp-export__filter:focus-within {
    border-color: var(--sp-accent);
    box-shadow: 0 0 0 2px var(--sp-accent-dim);
}

.sp-export__filter-input {
    flex: 1;
    min-width: 0;
    padding: var(--sp-space-1) 0;
    border: 0;
    background: transparent;
    color: var(--sp-text-primary);
    font: inherit;
    font-size: var(--sp-text-sm);
}

.sp-export__filter-input:focus {
    outline: none;
}

.sp-export__column-tools {
    display: inline-flex;
    gap: var(--sp-space-1);
    margin-inline-start: auto;
}

.sp-export__columns {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
    margin: 0;
    padding: 0;
    border: 0;
    min-width: 0;
}

.sp-export__group-name {
    margin: 0 0 var(--sp-space-2);
    padding-bottom: var(--sp-space-1);
    border-bottom: 1px solid var(--sp-border-subtle);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}

.sp-export__column-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: var(--sp-space-1) var(--sp-space-3);
}

.sp-export__column {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--sp-space-2);
    min-width: 0;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-normal);
    color: var(--sp-text-primary);
    cursor: pointer;
}

.sp-export__column span {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-export__column input {
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--sp-accent);
}

}

@layer components {

/* The record choices ("Full transcript", "Full transcripts") have no
   columns: the checklist pane is hidden, so the dialog narrows to the one
   pane that is left rather than holding an empty column open beside it. */
.sp-dialog.sp-export.sp-export--document {
    max-width: min(28rem, 94vw);
    width: min(28rem, 94vw);
}

.sp-export--document .sp-export__panes {
    grid-template-columns: minmax(0, 1fr);
}

.sp-export--document .sp-export__pane--what {
    border-inline-end: 0;
}

}

@layer components {

/* The page filters a download carries, as chips the reader can drop for this
   one file. A pinned chip (the conversation, session or skill the page is
   about) has no drop button. */
.sp-export__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-export__chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    max-width: 100%;
    padding: var(--sp-space-1) var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface);
    font-size: var(--sp-text-xs);
}

.sp-export__chip-label {
    color: var(--sp-text-tertiary);
}

.sp-export__chip-value {
    overflow: hidden;
    color: var(--sp-text-primary);
    font-weight: var(--sp-font-medium);
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-export__chip-drop {
    padding: 0 var(--sp-space-1);
    border: 0;
    border-radius: var(--sp-radius-full);
    background: transparent;
    color: var(--sp-text-tertiary);
    font: inherit;
    line-height: 1;
    cursor: pointer;
}

.sp-export__chip-drop:hover,
.sp-export__chip-drop:focus-visible {
    background: var(--sp-accent-dim);
    color: var(--sp-accent-text);
}

.sp-export__filters-count {
    color: var(--sp-text-tertiary);
    font-weight: var(--sp-font-medium);
}

.sp-export__chip[hidden],
.sp-export__window-line[hidden] {
    display: none;
}

/* The dates the file covers, as the server resolved them. */
.sp-export__window-line {
    margin: 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-export__window-line[data-tone="warn"] {
    color: var(--sp-warning-strong);
}

}

@layer components {

.sp-dropdown-portal {
    position: fixed;
    top: 0;
    left: 0;
    width: 0;
    height: 0;
    z-index: var(--sp-z-dropdown);
    pointer-events: none;
}

.sp-dropdown-menu {
    position: fixed;
    left: auto;
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
    background: var(--sp-bg-surface-overlay);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-md);
    box-shadow: var(--sp-shadow-lg);
    min-width: 140px;
    padding: var(--sp-space-1) 0;
    z-index: var(--sp-z-dropdown);
}

}

@layer components {

.sp-field-hint {
    margin: var(--sp-space-1) 0 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    line-height: var(--sp-leading-normal);
}

.sp-btn--copy {
    position: absolute;
    top: var(--sp-space-2);
    right: var(--sp-space-2);
}

}

@layer components {

.sp-form-group {
    margin-bottom: var(--sp-space-5);
    border-radius: var(--sp-radius-sm);
}

.sp-form-group label {
    display: block;
    font-size: var(--sp-text-sm);
    font-weight: 500;
    color: var(--sp-text-secondary);
    margin-bottom: var(--sp-space-1);
}

.sp-form-group input,
.sp-form-group select,
.sp-form-group textarea {
    width: 100%;
    background: var(--sp-bg-base);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-sm);
    padding: var(--sp-space-2) var(--sp-space-3);
    color: var(--sp-text-primary);
    font-size: var(--sp-text-base);
    font-family: inherit;
    outline: none;
    transition: border-color var(--sp-duration-fast), box-shadow var(--sp-duration-fast);
    box-sizing: border-box;
}

.sp-form-group input:focus-visible,
.sp-form-group select:focus-visible,
.sp-form-group textarea:focus-visible {
    border-color: var(--sp-accent);
    outline: 2px solid var(--sp-accent-dim);
    outline-offset: -1px;
}

.sp-form-group input::placeholder,
.sp-form-group textarea::placeholder {
    color: var(--sp-text-disabled);
}

.sp-form-group textarea {
    min-height: 80px;
    resize: vertical;
}

.sp-form-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    margin-top: var(--sp-space-6);
    padding-top: var(--sp-space-5);
    border-top: 1px solid var(--sp-border-subtle);
}

.sp-btn[aria-busy="true"] {
    position: relative;
    color: transparent;
    pointer-events: none;
}

.sp-btn[aria-busy="true"]::after {
    content: '';
    position: absolute;
    inset: 0;
    margin: auto;
    width: 1.125em;
    height: 1.125em;
    border: 2px solid currentColor;
    border-right-color: transparent;
    border-radius: var(--sp-radius-full);
    animation: spin 0.6s linear infinite;
    color: var(--sp-text-on-accent);
}

.sp-btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.sp-field-input {
    width: 100%;
    padding: var(--sp-space-2) var(--sp-space-3);
    font-size: var(--sp-text-sm);
    font-family: inherit;
    color: var(--sp-text-primary);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    transition: border-color var(--sp-duration-fast);
}
.sp-field-input:focus { outline: none; border-color: var(--sp-accent); box-shadow: 0 0 0 2px color-mix(in oklch, var(--sp-accent) 20%, transparent); }


/* The field primitives every edit form is built from. They used to live on the
   user-detail page under a page-scoped prefix, which left the same markup on
   the gateway and access-control pages unstyled. */
.sp-form-field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    min-width: 0;
}

.sp-form-field--inline {
    flex-direction: row;
    align-items: center;
    gap: var(--sp-space-2);
    align-self: end;
}

.sp-form-field--readonly { color: var(--sp-text-tertiary); }

.sp-form-label {
    font-size: var(--sp-text-xs);
    font-weight: 600;
    color: var(--sp-text-secondary);
}

.sp-form-field input:not([type="checkbox"]):not([type="radio"]),
.sp-form-field select,
.sp-form-field textarea {
    width: 100%;
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-sm);
    background: var(--sp-bg-surface);
    color: var(--sp-text-primary);
    font: inherit;
    font-size: var(--sp-text-sm);
    transition: border-color var(--sp-duration-fast);
}

.sp-form-field input:disabled,
.sp-form-field select:disabled {
    opacity: 0.65;
    cursor: not-allowed;
}

.sp-form-status {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
}

}

@layer responsive {

/* iOS Safari zooms the page into any focused control whose text is under
   16px and never zooms back out, so every control in the shell reads at
   least 1rem on a phone and is tall enough to hit with a thumb. */
@media (max-width: 48rem) {
    .sp-shell input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
    .sp-shell select,
    .sp-shell textarea {
        font-size: max(1rem, var(--sp-text-base));
        min-height: 44px;
    }

    .sp-form-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .sp-form-field--inline {
        flex-wrap: wrap;
        align-self: stretch;
    }

    .sp-form-actions {
        flex-wrap: wrap;
    }

    .sp-form-actions .sp-btn {
        flex: 1 1 100%;
        justify-content: center;
        min-width: 0;
        min-height: 44px;
    }

    /* A long value (a hash, a URL) beside its label squeezed the label to a
       sliver, so on a phone the label sits above the value it names. */
    .sp-kv-row {
        flex-direction: column;
        align-items: flex-start;
        gap: var(--sp-space-1);
    }

    .sp-kv-row dd {
        text-align: left;
        max-width: 100%;
    }
}

}

@layer components {

/* An edit form as one surface: heading, fields, and the button that saves them
   inside the same card. The footer carries no divider and no extra margin, so
   the CTA sits with the fields it acts on rather than a screen-height below. */

.sp-form-section {
    padding: var(--sp-space-4);
    background: var(--sp-bg-surface);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
}

.sp-form-section > .sp-section__head { margin-top: 0; }

.sp-form-section__body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
}

.sp-form-section__body .sp-notice { margin-bottom: 0; }

.sp-form-section__foot {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-space-3);
    margin-top: var(--sp-space-4);
}

.sp-form-section__group-label {
    margin: 0;
    font-size: var(--sp-text-xs);
    font-weight: 600;
    color: var(--sp-text-secondary);
}

/* A choice is a checkbox wearing a chip. The state is read from the input, so
   there is no JavaScript to keep in step with it and the keyboard path is the
   native one. */
.sp-choice-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-2);
}

.sp-choice {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-1) var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface-raised);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
    cursor: pointer;
    transition: border-color var(--sp-duration-fast), background var(--sp-duration-fast);
}

.sp-choice input { margin: 0; }

.sp-choice:hover {
    color: var(--sp-text-primary);
    border-color: var(--sp-border-strong);
}

.sp-choice:has(input:checked) {
    background: var(--sp-accent-dim);
    border-color: var(--sp-accent);
    color: var(--sp-accent-text);
    font-weight: 600;
}

.sp-choice:has(input:disabled) {
    opacity: 0.6;
    cursor: not-allowed;
}

.sp-choice:has(input:focus-visible) {
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px color-mix(in oklch, var(--sp-accent) 50%, transparent);
}

.sp-choice .sp-badge { margin-left: var(--sp-space-1); }

}

@layer base {

input[type="checkbox"] {
    accent-color: var(--sp-accent-text);
    cursor: pointer;
}

select {
    background: var(--sp-bg-surface);
    color: var(--sp-text-primary);
}

select option {
    background: var(--sp-bg-surface-overlay);
    color: var(--sp-text-primary);
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px color-mix(in oklch, var(--sp-accent) 50%, transparent);
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

.sp-skeleton__text { color: var(--sp-text-secondary); padding: var(--sp-space-4); }

@keyframes shimmer {
    0% { background-position: -200% 0; }
    100% { background-position: 200% 0; }
}

.sp-shell {
    scrollbar-width: thin;
    scrollbar-color: var(--sp-scrollbar-thumb) var(--sp-scrollbar-track);
}

}

@layer components {

.sp-skill-file-category {
    font-size: var(--sp-text-xs);
    font-weight: 700;
    color: var(--sp-text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: var(--sp-space-2) var(--sp-space-3);
    margin-top: var(--sp-space-2);
}

.sp-code-inline {
    background: var(--sp-bg-surface-raised);
    padding: 0.125rem var(--sp-space-2);
    border-radius: var(--sp-radius-xs);
    font-size: var(--sp-text-xs);
}

.sp-code-block {
    margin: 0;
    padding: var(--sp-space-3);
    background: var(--sp-bg-surface-raised);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-md);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    line-height: 1.5;
    color: var(--sp-text-secondary);
    white-space: pre-wrap;
    word-break: break-word;
    overflow: auto;
}

.sp-section__foot {
    text-align: center;
    margin-top: var(--sp-space-3);
}

.sp-section__foot a {
    color: var(--sp-info-strong);
}

.is-clickable {
    cursor: pointer;
}

}

@layer components {

.sp-table__cell--flush {
    padding: 0;
}

.sp-col-chevron {
    width: 32px;
}

}

@layer responsive {

/* On a phone every overlay becomes a full-width sheet anchored to the foot of
   the screen, where the thumb already is. Heights use dvh because 100vh on
   iOS includes the collapsing toolbar and clipped the last row of a form. */
@media (max-width: 48rem) {
    .sp-dialog {
        width: 100vw;
        max-width: 100vw;
        max-height: 100dvh;
        margin: auto 0 0;
        border-width: 1px 0 0;
        border-radius: var(--sp-radius-lg) var(--sp-radius-lg) 0 0;
    }

    .sp-dialog-form {
        padding-bottom: 0;
    }

    /* The form scrolls inside the sheet, so the confirm and cancel buttons
       stick to its foot instead of scrolling away with a long form. */
    .sp-dialog-form menu {
        position: sticky;
        bottom: 0;
        flex-wrap: wrap;
        padding-block: var(--sp-space-3) calc(var(--sp-space-3) + env(safe-area-inset-bottom, 0px));
        background: var(--sp-bg-surface-overlay);
        border-top: 1px solid var(--sp-border-subtle);
    }

    .sp-dialog-form menu > * {
        flex: 1 1 0;
        justify-content: center;
        min-height: 44px;
    }

    .sp-help__frame {
        max-height: 100dvh;
    }

    .sp-help__close,
    .sp-export__close,
    .sp-panel-close {
        min-width: 44px;
        min-height: 44px;
        justify-content: center;
    }

    /* The export dialog stacks into one scrolling column. Its "what" pane
       dissolves so the download footer becomes the last row of the whole
       sheet and can stick to the bottom however far the column list runs. */
    .sp-export {
        overflow: hidden;
    }

    .sp-export__form {
        max-height: 100dvh;
        overflow-y: auto;
    }

    .sp-export__head {
        position: sticky;
        top: 0;
        z-index: var(--sp-z-sticky);
        background: var(--sp-bg-surface-overlay);
    }

    .sp-export__panes {
        flex: none;
        display: flex;
        flex-direction: column;
        gap: var(--sp-space-4);
        padding-top: var(--sp-space-4);
    }

    .sp-export__pane {
        overflow: visible;
    }

    .sp-export__pane--what {
        display: contents;
    }

    .sp-export__pane--what > * {
        margin-inline: var(--sp-space-4);
    }

    .sp-export__foot {
        order: 1;
        position: sticky;
        bottom: 0;
        z-index: var(--sp-z-sticky);
        margin: 0;
        padding: var(--sp-space-3) var(--sp-space-4) calc(var(--sp-space-3) + env(safe-area-inset-bottom, 0px));
        background: var(--sp-bg-surface-overlay);
    }

    .sp-export__download {
        min-height: 44px;
    }

    .sp-export__column-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .sp-side-panel {
        width: 100vw;
        max-width: 100vw;
        height: 100dvh;
        border-left: 0;
        border-radius: 0;
    }

    .sp-panel-header {
        position: sticky;
        top: 0;
        padding: calc(var(--sp-space-3) + env(safe-area-inset-top, 0px)) var(--sp-space-4) var(--sp-space-3);
    }

    .sp-panel-body {
        padding: var(--sp-space-3) var(--sp-space-4);
    }

    .sp-panel-footer {
        padding: var(--sp-space-3) var(--sp-space-4) calc(var(--sp-space-3) + env(safe-area-inset-bottom, 0px));
    }

    .sp-panel-footer .sp-btn {
        flex: 1 1 0;
        justify-content: center;
        min-height: 44px;
    }

    /* Set by dropdown.js instead of inline coordinates: a menu pinned to a
       trigger near the screen edge ran off a phone, a sheet cannot. */
    .sp-dropdown-menu.is-sheet {
        inset: auto 0 0;
        width: 100vw;
        max-height: 70dvh;
        overflow-y: auto;
        padding-bottom: calc(var(--sp-space-2) + env(safe-area-inset-bottom, 0px));
        border-width: 1px 0 0;
        border-radius: var(--sp-radius-lg) var(--sp-radius-lg) 0 0;
    }

    .sp-dropdown-menu.is-sheet > * {
        display: flex;
        align-items: center;
        min-height: 44px;
    }
}

}

@layer components {

.sp-panel-overlay {
    position: fixed;
    inset: 0;
    background: transparent;
    z-index: calc(var(--sp-z-panel) - 1);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--sp-duration-slow) var(--sp-ease-in-out),
                visibility var(--sp-duration-slow) var(--sp-ease-in-out),
                background var(--sp-duration-slow) var(--sp-ease-in-out),
                backdrop-filter var(--sp-duration-slow) var(--sp-ease-in-out);
    backdrop-filter: blur(0px);
}

.sp-panel-overlay.is-open,
.sp-panel-overlay.is-active {
    opacity: 1;
    visibility: visible;
    background: var(--sp-overlay-light);
    backdrop-filter: blur(4px);
}

.sp-side-panel {
    position: fixed;
    top: 0;
    right: 0;
    width: 640px;
    max-width: 94vw;
    height: 100vh;
    background: var(--sp-bg-surface-gradient);
    border-left: 1px solid var(--sp-border-subtle);
    box-shadow: var(--sp-shadow-float);
    z-index: var(--sp-z-panel);
    transform: translateX(100%);
    transition: transform var(--sp-duration-slow) var(--sp-ease-out);
    display: flex;
    flex-direction: column;
    border-radius: var(--sp-radius-md) 0 0 var(--sp-corners-md);
}

.sp-side-panel.is-open { transform: translateX(0); }

.sp-panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: var(--sp-space-6) var(--sp-space-8);
    border-bottom: 1px solid var(--sp-border-default);
    background: var(--sp-bg-card-header);
    flex-shrink: 0;
}

.sp-panel-header h2 {
    font-size: var(--sp-text-lg);
    font-weight: 600;
    margin: 0;
    color: var(--sp-text-primary);
    letter-spacing: -0.01em;
}

.sp-panel-close {
    background: color-mix(in oklch, var(--sp-warm-900) 6%, transparent);
    border: none;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-lg);
    cursor: pointer;
    padding: var(--sp-space-1) var(--sp-space-2);
    border-radius: var(--sp-radius-sm);
    line-height: 1;
    transition: color var(--sp-duration-fast),
                background var(--sp-duration-fast);
}

.sp-panel-close:hover {
    color: var(--sp-text-primary);
    background: color-mix(in oklch, var(--sp-warm-900) 8%, transparent);
}

.sp-panel-body {
    flex: 1;
    overflow-y: auto;
    padding: var(--sp-space-8);
}

.sp-panel-footer {
    padding: var(--sp-space-4) var(--sp-space-8);
    border-top: 1px solid var(--sp-border-subtle);
    display: flex;
    gap: var(--sp-space-3);
    justify-content: flex-end;
    flex-shrink: 0;
}

@keyframes panelContentIn {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

/* The first four fields stagger in so the eye follows the form top-down;
   the rest arrive together because a longer cascade reads as lag. */
.sp-side-panel.is-open .sp-panel-body .sp-form-group {
    animation: panelContentIn var(--sp-duration-normal) var(--sp-ease-out) both;
}

.sp-side-panel.is-open .sp-panel-body .sp-form-group:nth-child(1) { animation-delay: 40ms; }
.sp-side-panel.is-open .sp-panel-body .sp-form-group:nth-child(2) { animation-delay: 80ms; }
.sp-side-panel.is-open .sp-panel-body .sp-form-group:nth-child(3) { animation-delay: 120ms; }
.sp-side-panel.is-open .sp-panel-body .sp-form-group:nth-child(4) { animation-delay: 160ms; }
.sp-side-panel.is-open .sp-panel-body .sp-form-group:nth-child(n+5) { animation-delay: 200ms; }

@media (prefers-reduced-motion: reduce) {
    .sp-panel-overlay {
        transition: none;
    }
    .sp-side-panel {
        transition: none;
    }
    .sp-side-panel.is-open .sp-panel-body .sp-form-group {
        animation: none;
    }
}

}

@layer components {

.sp-user-name {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
    font-weight: 600;
    line-height: 1.3;
}

.sp-user-meta {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-btn--logout {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-md);
    background: var(--sp-bg-surface);
    color: var(--sp-text-secondary);
    cursor: pointer;
                border-color var(--sp-duration-fast);
    flex-shrink: 0;
}

.sp-btn--logout:hover {
    color: var(--sp-text-primary);
    background: var(--sp-bg-surface-raised);
    border-color: var(--sp-border-strong);
}

.sp-btn--logout svg {
    display: block;
}

}

@layer components {

.sp-user-cell {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-user-widget {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    text-decoration: none;
    transition: transform var(--sp-duration-fast);
}

.sp-user-widget:hover {
    transform: scale(1.08);
}

}

@layer responsive {

/* The avatar shrinks with the topbar on a phone so the bar keeps room for
   the search toggle and the actions menu beside it. */
@media (max-width: 48rem) {
    .sp-user-widget {
        width: 38px;
        height: 38px;
    }
}

@media (max-width: 30rem) {
    .sp-user-widget {
        width: 34px;
        height: 34px;
    }
}

}

@layer components {

/* The live chart draws at pixel size inside a host that takes every pixel
   its panel gives it; the server's stretched SVG stays underneath for the
   no-script case and is hidden once this takes over. */
/* Once the live layer is up the server plot, its gutters and its legend
   step aside; `[hidden]` alone loses to the component rules that give them
   a display, so the live modifier hides them here at equal weight. */
.sp-svgchart--live .sp-timeseries__plot,
.sp-svgchart--live .sp-timeseries__x-axis,
.sp-svgchart--live .sp-svgchart__legend,
.sp-svgchart--live .sp-svgchart__refs {
    display: none;
}

.sp-chart {
    position: relative;
    flex: 1 1 auto;
    min-height: 12rem;
    min-width: 0;
}

.sp-chart[hidden] {
    display: none;
}

/* Out of flow on purpose: draw() sizes the SVG from the host, so an in-flow
   SVG would feed its own height back into the host and every resize would
   grow the chart without bound. The host is sized by layout alone. */
.sp-chart__svg {
    display: block;
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    overflow: visible;
}

.sp-chart__svg:focus-visible {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
    border-radius: var(--sp-radius-sm);
}

/* Gridlines are one step off the surface and hairline; the baseline is the
   only axis line, so the data is the loudest thing on the panel. */
.sp-chart__grid {
    stroke: var(--sp-border-subtle);
    stroke-width: 1;
    shape-rendering: crispEdges;
}

.sp-chart__baseline {
    stroke: var(--sp-border-default);
    stroke-width: 1;
    shape-rendering: crispEdges;
}

.sp-chart__tick {
    font-size: var(--sp-text-2xs);
    fill: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-chart__line {
    fill: none;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.sp-chart__area {
    opacity: 0.1;
}

/* Dots carry a 2px surface ring so they stay legible where lines cross; on
   dense series they appear only for the hovered bucket. */
.sp-chart__dot {
    stroke: var(--sp-bg-surface);
    stroke-width: 2;
    transition: r var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-chart__dot--hover {
    opacity: 0;
}

.sp-chart__dot.is-active {
    opacity: 1;
    r: 6;
}

.sp-chart__bar {
    transition: opacity var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-chart__hits:hover ~ *,
.sp-chart__series:has(.is-active) .sp-chart__bar:not(.is-active) {
    opacity: 0.55;
}

.sp-chart__hit {
    fill: transparent;
    cursor: crosshair;
}

.sp-chart__cursor {
    stroke: var(--sp-border-strong);
    stroke-width: 1;
    stroke-dasharray: 3 3;
    opacity: 0;
    pointer-events: none;
}

.sp-chart__cursor.is-visible {
    opacity: 1;
}

.sp-chart__tip {
    position: absolute;
    /* Keep the readout inside the chart host. Dashboard panels scroll their
       fixed-height contents, so positioning it above the host clips the
       tooltip at the panel's top edge. */
    top: var(--sp-space-2);
    transform: translateX(-50%);
    display: grid;
    gap: var(--sp-space-05);
    min-width: 9rem;
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface-overlay);
    box-shadow: var(--sp-shadow-float);
    font-size: var(--sp-text-xs);
    pointer-events: none;
    z-index: var(--sp-z-dropdown);
}

.sp-chart__tip[hidden] {
    display: none;
}

.sp-chart__tip-label {
    color: var(--sp-text-tertiary);
    font-weight: var(--sp-font-semibold);
}

/* Values lead, names follow: the reader has the series and wants the number. */
.sp-chart__tip-row {
    display: grid;
    grid-template-columns: 0.9rem auto 1fr;
    align-items: center;
    gap: var(--sp-space-2);
    white-space: nowrap;
}

.sp-chart__tip-row i,
.sp-chart__key {
    display: inline-block;
    width: 0.9rem;
    height: 0.6rem;
    border-radius: 2px;
    background: var(--sp-series);
}

.sp-chart__tip-row i,
.sp-chart__key--line {
    height: 2px;
    border-radius: 1px;
}

.sp-chart__tip-row b {
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-chart__tip-row span {
    color: var(--sp-text-secondary);
}

}

@layer components {

/* Legend, table view and the head tools of a live chart; the plot itself is
   in 08-chart-live.css. */
.sp-chart__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1) var(--sp-space-4);
    margin: var(--sp-space-2) 0 0;
    padding: 0;
    list-style: none;
}

.sp-chart__legend-item {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    cursor: pointer;
    border-radius: var(--sp-radius-sm);
}

.sp-chart__legend-item:focus-visible {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
}

.sp-chart__legend-item.is-hidden {
    opacity: 0.45;
    text-decoration: line-through;
}

.sp-chart__legend-value {
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-chart__tools {
    margin-inline-start: auto;
}

.sp-chart__table {
    width: 100%;
    margin-top: var(--sp-space-2);
    border-collapse: collapse;
    font-size: var(--sp-text-xs);
}

.sp-chart__table th,
.sp-chart__table td {
    padding: var(--sp-space-1) var(--sp-space-2);
    border-bottom: 1px solid var(--sp-border-subtle);
    text-align: start;
}

.sp-chart__table-num {
    text-align: end;
    font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: reduce) {
    .sp-chart__dot,
    .sp-chart__bar {
        transition: none;
    }
}

}

@layer responsive {

/* On desktop a chart card has a fixed height so every card in a grid row
   shares a baseline. On a phone there is one card per row, so the card sizes
   to its content with a floor instead, and never scrolls inside itself. This
   cannot grow without bound: the live SVG is absolutely positioned inside
   .sp-chart, so it contributes no height back to the card. */
@media (max-width: 48rem) {
    .sp-p-overview__chart,
    .sp-analytics-grid__panel,
    .sp-requests-charts__panel {
        block-size: auto;
        min-block-size: 18rem;
        overflow: visible;
    }

    .sp-chart {
        min-height: 13rem;
    }

    .sp-requests-charts,
    .sp-p-overview__two-up {
        grid-template-columns: minmax(0, 1fr);
    }

    .sp-chart__legend,
    .sp-svgchart__legend {
        gap: var(--sp-space-1) var(--sp-space-3);
    }

    /* The ring and its legend stack, the ring capped so it leaves the
       legend on screen, and each legend label keeps the full row width. */
    .sp-pie-chart__body {
        flex-direction: column;
        align-items: stretch;
        gap: var(--sp-space-4);
    }

    .sp-pie-chart__ring {
        flex: none;
        width: 100%;
        min-width: 0;
        max-width: 12rem;
        align-self: center;
    }

    .sp-latency-histogram__row {
        grid-template-columns: 4rem 1fr 2.5rem;
        gap: var(--sp-space-2);
    }

    .sp-latency-histogram__axis {
        padding-left: calc(4rem + var(--sp-space-2));
    }
}

}

@layer components {
    /* The figure grows to its panel so four charts in one grid row share a
       baseline instead of each sitting at the top of a card sized by the
       tallest neighbour. */
    .sp-svgchart {
        display: flex;
        flex-direction: column;
        gap: var(--sp-space-2);
        flex: 1;
        min-height: 0;
        min-width: 0;
        margin: 0;
    }
    .sp-svgchart .sp-timeseries__head {
        flex-direction: row;
        flex-wrap: wrap;
        align-items: baseline;
        gap: var(--sp-space-2);
    }

    .sp-svgchart__plot {
        width: 100%;
        height: 100%;
        min-height: 10rem;
        display: block;
        border-bottom: 1px solid var(--sp-border-default);
        background: linear-gradient(var(--sp-border-subtle), var(--sp-border-subtle))
            0 50% / 100% 1px no-repeat;
    }

    .sp-svgchart__line {
        stroke-width: 2px;
    }

    .sp-svgchart__area {
        opacity: 0.12;
    }

    /* A dot is a zero-length round-capped stroke: with preserveAspectRatio
       "none" a <circle> stretches into an ellipse, while a non-scaling stroke
       stays round at every panel width. */
    .sp-svgchart__dot {
        stroke-width: 6px;
        stroke-linecap: round;
    }

    .sp-svgchart__ref {
        stroke-dasharray: 4 3;
        stroke-width: 1.5px;
        stroke: var(--sp-chart-amber);
    }

    .sp-svgchart__refs {
        display: flex;
        gap: var(--sp-space-3);
        list-style: none;
        margin: var(--sp-space-1) 0 0;
        padding: 0;
        font-size: var(--sp-text-xs);
        color: var(--sp-text-secondary);
    }

    .sp-svgchart__ref-label::before {
        content: "";
        display: inline-block;
        width: 14px;
        border-top: 2px dashed var(--sp-chart-amber);
        margin-right: 0.35em;
        vertical-align: middle;
    }


        .sp-kpi__delta {
        display: inline-block;
        font-size: var(--sp-text-xs);
        color: var(--sp-text-secondary);
    }

    .sp-kpi__delta[data-tone="good"] {
        color: var(--sp-success-strong);
    }

    .sp-kpi__delta[data-tone="bad"] {
        color: var(--sp-danger-strong);
    }

    .sp-kpi__delta[data-direction="up"]::before {
        content: "\2191\00a0";
    }

    .sp-kpi__delta[data-direction="down"]::before {
        content: "\2193\00a0";
    }

}
@layer components {
    /* Sparklines: a 100x24 unit space stretched to its cell. The stroke keeps
       its weight through the stretch; the last point is marked. */
    .sp-spark {
        display: block;
        width: 6rem;
        height: 1.5rem;
        color: var(--sp-accent);
        overflow: visible;
    }
    .sp-spark--ok { color: var(--sp-success-strong); }
    .sp-spark--warn { color: var(--sp-warning-strong); }
    .sp-spark--err { color: var(--sp-danger-strong); }
    .sp-spark--muted { color: var(--sp-text-tertiary); }
    .sp-spark--accent { color: var(--sp-accent); }
    .sp-spark--empty {
        border-bottom: 1px dashed var(--sp-border-subtle);
        height: 1rem;
    }
    .sp-spark__line {
        fill: none;
        stroke: currentColor;
        stroke-width: 1.5px;
        stroke-linejoin: round;
        stroke-linecap: round;
    }
    .sp-spark__area {
        fill: currentColor;
        opacity: 0.1;
    }
    .sp-spark__dot {
        fill: none;
        stroke: currentColor;
        stroke-width: 6px;
        stroke-linecap: round;
        paint-order: stroke;
    }
    .sp-spark__dot-ring {
        fill: none;
        stroke: var(--sp-bg-surface);
        stroke-width: 9px;
        stroke-linecap: round;
    }

    /* The server plot's crosshair; the live layer sp-chart.js draws carries
       its own cursor and tooltip (08-chart-live.css). */
    .sp-timeseries__plot {
        position: relative;
    }
    .sp-svgchart__cursor {
        stroke: var(--sp-text-tertiary);
        stroke-width: 1px;
        stroke-dasharray: 2 2;
        pointer-events: none;
    }
    .sp-svgchart__cursor[hidden] {
        display: none;
    }
    .sp-svgchart--live .sp-svgchart__plot:focus-visible {
        outline: 2px solid var(--sp-accent);
        outline-offset: 2px;
    }
    .sp-svgchart__series.is-hidden {
        display: none;
    }
    .sp-svgchart__legend-item {
        cursor: pointer;
    }
    .sp-svgchart__legend-item.is-hidden {
        opacity: 0.4;
        text-decoration: line-through;
    }
}

@layer components {

.sp-kpi--danger .sp-kpi__value { color: var(--sp-danger-strong); }

.sp-kpi--warning .sp-kpi__value { color: var(--sp-warning-strong); }

.sp-requests-charts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: var(--sp-space-4);
    margin-block: var(--sp-space-6);
}

.sp-requests-charts__panel {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    padding: var(--sp-space-5);
    min-width: 0;
}

.sp-requests-charts__panel--wide {
    margin-block: var(--sp-space-6);
}

.sp-requests-charts__title {
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-secondary);
    margin: 0 0 var(--sp-space-3);
}

.sp-latency-histogram {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
}

.sp-latency-histogram__label {
    grid-column: 1;
    grid-row: 1;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    font-variant-numeric: tabular-nums;
    text-align: right;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-latency-histogram__track {
    grid-column: 2;
    grid-row: 1;
    height: 0.75rem;
    border-radius: var(--sp-radius-sm);
    background: color-mix(in oklch, var(--sp-warm-900) 6%, transparent);
}

.sp-latency-histogram__fill {
    display: block;
    width: var(--v, 0%);
    height: 100%;
    border-radius: var(--sp-radius-sm);
    background: var(--sp-chart-blue);
}

.sp-latency-histogram__row--peak .sp-latency-histogram__fill {
    background: var(--sp-accent-fill);
}

.sp-latency-histogram__count {
    grid-column: 3;
    grid-row: 1;
    text-align: right;
    font-size: var(--sp-text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--sp-text-tertiary);
}

.sp-latency-histogram__axis {
    display: flex;
    justify-content: space-between;
    margin-top: var(--sp-space-2);
    padding-top: var(--sp-space-1);
    padding-left: calc(5.5rem + var(--sp-space-3));
    border-top: 1px solid var(--sp-border-subtle);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-timeseries {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    flex: 1;
    margin: 0;
    min-width: 0;
}

.sp-timeseries__head {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-05);
}

.sp-timeseries__title {
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-primary);
}
}

@layer components {

.sp-timeseries__subtitle {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-latency-histogram__row {
    display: grid;
    grid-template-columns: 5.5rem 1fr 3rem;
    align-items: center;
    gap: var(--sp-space-3);
    min-height: 1.5rem;
    border-radius: var(--sp-radius-sm);
    transition: background var(--sp-duration-fast);
}
.sp-latency-histogram__row:hover {
    background: color-mix(in oklch, var(--sp-accent) 5%, transparent);
}

}



@layer components {

.sp-timeseries__plot {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--sp-space-3);
    flex: 1;
    min-height: 150px;
}

.sp-timeseries__y-axis {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    align-items: flex-end;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.sp-timeseries__bars {
    display: flex;
    align-items: flex-end;
    gap: var(--sp-space-05);
    border-bottom: 1px solid var(--sp-border-default);
    background-image: linear-gradient(
        transparent 1px 100%
    );
    background-size: 100% 50%;
    background-repeat: repeat-y;
}

.sp-timeseries__bar {
    flex: 1 1 0;
    min-width: 0;
    height: var(--v, 0%);
    border-radius: var(--sp-radius-sm) var(--sp-radius-sm) 0 0;
    background: var(--sp-chart-blue);
    transition: filter var(--sp-duration-fast);
}

.sp-timeseries[data-tone="success"] .sp-timeseries__bar {
    background: var(--sp-chart-green);
}

.sp-timeseries__bar:hover {
    filter: brightness(1.12);
}

.sp-timeseries__x-axis {
    display: flex;
    justify-content: space-between;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-chart-caption {
    margin: 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-waterfall {
    margin: var(--sp-space-6) 0 0;
}

.sp-waterfall__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-2);
    list-style: none;
    margin: 0;
    padding: 0;
}

.sp-waterfall__legend li {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-waterfall__swatch {
    display: inline-block;
    width: 0.625rem;
    height: 0.625rem;
    border-radius: var(--sp-radius-sm);
    background: var(--sp-warm-500);
}

.sp-waterfall__swatch--gateway    { background: var(--sp-chart-blue); }

.sp-waterfall__swatch--governance { background: var(--sp-chart-amber); }

.sp-waterfall__swatch--tool       { background: var(--sp-chart-green); }

.sp-waterfall__swatch--model      { background: var(--sp-chart-purple); }

.sp-waterfall__swatch--spawn      { background: var(--sp-chart-indigo); }

}


@layer components {

.sp-connect__cmd {
    margin: 0;
    padding: var(--sp-space-3) var(--sp-space-4);
    background: var(--sp-bg-surface-alt);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    overflow-x: auto;
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-sm);
    line-height: 1.6;
    color: var(--sp-text-primary);
    user-select: all;
}

.sp-copy {
    position: relative;
    min-width: 0;
}

.sp-copy .sp-connect__cmd {
    padding-right: calc(var(--sp-space-4) + 2rem);
}

.sp-copy__btn {
    position: absolute;
    top: var(--sp-space-2);
    right: var(--sp-space-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.85rem;
    height: 1.85rem;
    padding: 0;
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    color: var(--sp-text-tertiary);
    cursor: pointer;
    opacity: 0.75;
    transition: opacity var(--sp-duration-fast) ease,
                color var(--sp-duration-fast) ease;
}

.sp-copy__btn svg {
    width: 1rem;
    height: 1rem;
}

.sp-copy__btn:hover,
.sp-copy__btn:focus-visible {
    opacity: 1;
    color: var(--sp-text-primary);
}

.sp-copy__btn.is-copied {
    opacity: 1;
    color: var(--sp-success-strong);
    border-color: var(--sp-success);
}

.sp-copy__btn.is-failed {
    opacity: 1;
    color: var(--sp-danger-strong);
    border-color: var(--sp-danger);
}

.sp-connect__raw summary {
    cursor: pointer;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    margin-bottom: var(--sp-space-2);
}

}

@layer components {

.sp-notice-region {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    margin: var(--sp-space-3) 0;
}

.sp-notice-region:empty { display: none; }

}

@layer components {

.sp-install-menu {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin-left: auto;
    margin-right: var(--sp-space-3);
}

.sp-install-trigger {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-md);
    color: var(--sp-text-secondary);
    cursor: pointer;
                color var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-plugin-counter {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 18px;
    height: 18px;
    padding: 0 0.3125rem;
    font-size: var(--sp-text-xs);
    font-weight: 600;
    line-height: 18px;
    text-align: center;
    color: var(--sp-text-on-accent);
    background: var(--sp-accent-fill);
    border-radius: var(--sp-radius-full);
    pointer-events: none;
}

.sp-install-trigger:hover,
.sp-install-menu.is-open .sp-install-trigger {
    background: var(--sp-bg-surface-raised);
    border-color: var(--sp-border-strong);
    color: var(--sp-text-primary);
}

.sp-install-trigger:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--sp-bg-canvas), 0 0 0 4px var(--sp-accent);
}

.sp-install-dropdown {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: var(--sp-space-2);
    width: 380px;
    background: var(--sp-bg-surface-overlay);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-inner-md);
    box-shadow: var(--sp-shadow-float);
    z-index: var(--sp-z-dropdown);
    padding: var(--sp-space-4);
    display: none;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity var(--sp-duration-fast) var(--sp-ease-out),
                transform var(--sp-duration-fast) var(--sp-ease-out);
}

.sp-install-menu.is-open .sp-install-dropdown {
    display: block;
    opacity: 1;
    transform: translateY(0);
}

.sp-install-dropdown-header {
    margin-bottom: var(--sp-space-3);
}

.sp-install-dropdown-title {
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-primary);
    margin-bottom: var(--sp-space-2);
}

.sp-install-dropdown .sp-install-widget-stats {
    display: flex;
    gap: var(--sp-space-3);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    flex-wrap: wrap;
}

.sp-install-dropdown .sp-install-stat strong {
    color: var(--sp-text-primary);
}

.sp-install-dropdown-body {
    padding: var(--sp-space-2);
}

.sp-install-tab-content {
    padding: var(--sp-space-3) 0;
}

.sp-install-tab-hint {
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

}

@layer responsive {

/* The 380px dropdown is wider than a phone, so it spans the screen less a
   gutter, pulled back over the trigger's own inset. */
@media (max-width: 48rem) {
    .sp-install-trigger {
        min-width: 44px;
        min-height: 44px;
    }

    .sp-install-dropdown {
        width: calc(100vw - var(--sp-space-6));
        right: calc(-1 * var(--sp-space-3));
    }
}

@media (max-width: 30rem) {
    .sp-install-dropdown {
        width: calc(100vw - var(--sp-space-4));
        right: calc(-1 * var(--sp-space-2));
    }

    .sp-install-dropdown .sp-install-widget-stats {
        flex-wrap: wrap;
        gap: var(--sp-space-2) var(--sp-space-3);
    }
}

}

@layer components {
.sp-table__cell--num,
.sp-table__cell--num {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.is-disabled {
    opacity: 0.5;
    pointer-events: none;
}

.sp-badge--ok {
    border-color: color-mix(in oklab, var(--sp-success) 40%, transparent);
    background: color-mix(in oklab, var(--sp-success) 14%, transparent);
    color: var(--sp-success-strong);
}

.sp-badge--err {
    border-color: color-mix(in oklab, var(--sp-danger) 45%, transparent);
    background: color-mix(in oklab, var(--sp-danger) 14%, transparent);
    color: var(--sp-danger-strong);
}

.sp-badge--warn {
    border-color: color-mix(in oklab, var(--sp-warning) 45%, transparent);
    background: color-mix(in oklab, var(--sp-warning) 16%, transparent);
    color: var(--sp-warning-strong);
}

.sp-requests-charts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: var(--sp-space-4);
    margin: var(--sp-space-4) 0;
}

.sp-requests-charts__panel {
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    padding: var(--sp-space-4);
}

.sp-requests-charts__title {
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--sp-text-tertiary);
    margin: 0 0 var(--sp-space-3);
}

.sp-latency-histogram {
    display: flex;
    align-items: flex-end;
    gap: var(--sp-space-1);
    height: 140px;
}

.sp-latency-histogram__count {
    position: absolute;
    top: -1.2em;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-latency-histogram__label {
    position: absolute;
    bottom: -1.4em;
    font-size: 10px;
    color: var(--sp-text-tertiary);
    white-space: nowrap;
}

.sp-pagination__current {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
}

}

@layer components {

.sp-trace-stats__row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
    gap: var(--sp-space-3);
}

.sp-trace-row__id {
    text-decoration: none;
    color: var(--sp-accent-text);
}

.sp-pagination__info {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
    margin: 0 var(--sp-space-3);
}

.sp-waterfall {
    margin: var(--sp-space-4) 0;
}

.sp-waterfall__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-3);
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-waterfall__legend li {
    display: flex;
    align-items: center;
    gap: var(--sp-space-1);
}

.sp-waterfall__swatch {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 2px;
    background: var(--sp-text-tertiary);
    flex-shrink: 0;
}

.sp-waterfall__swatch--gateway { background: var(--sp-info); }
.sp-waterfall__swatch--governance { background: var(--sp-warning); }
.sp-waterfall__swatch--tool { background: var(--sp-success); }
.sp-waterfall__swatch--model { background: var(--sp-accent-fill); }
.sp-waterfall__swatch--spawn { background: var(--sp-chart-purple); }

.sp-notice__title {
    font-weight: var(--sp-font-semibold);
    margin: 0 0 var(--sp-space-1);
}

}

@layer components {

.sp-code-collapsible {
    max-height: 320px;
    overflow: auto;
}

.sp-table__row--expand {
    cursor: pointer;
}
}

@layer utilities {

.sp-u-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.sp-u-num,
.sp-u-numeric {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.sp-u-mono {
    font-family: var(--sp-font-mono);
    font-variant-numeric: tabular-nums;
}

.sp-u-font-mono { font-family: var(--sp-font-mono); }

.sp-u-text-2xs { font-size: var(--sp-text-2xs); }
.sp-u-text-xs { font-size: var(--sp-text-xs); }
.sp-u-text-sm { font-size: var(--sp-text-sm); }
.sp-u-text-lg { font-size: var(--sp-text-lg); }
.sp-u-text-semibold { font-weight: var(--sp-font-semibold); }
.sp-u-text-bold { font-weight: var(--sp-font-bold); }
.sp-u-text-secondary { color: var(--sp-text-secondary); }
.sp-u-text-muted { color: var(--sp-text-secondary); }
.sp-u-text-muted-inline { color: var(--sp-text-tertiary); font-size: var(--sp-text-2xs); }
.sp-u-text-tertiary { color: var(--sp-text-tertiary); }
.sp-u-text-danger,
.sp-u-text-error { color: var(--sp-danger-strong); }
.sp-u-text-warning { color: var(--sp-warning-strong); }

.sp-u-link-accent { color: var(--sp-accent-text); text-decoration: none; }
.sp-u-link-strong { color: var(--sp-text-primary); font-weight: var(--sp-font-medium); text-decoration: none; }

.sp-u-flex { display: flex; }
.sp-u-flex-col { display: flex; flex-direction: column; }
.sp-u-flex-1 { flex: 1; }
.sp-u-flex-wrap { flex-wrap: wrap; }
.sp-u-items-start { align-items: flex-start; }
.sp-u-items-center { align-items: center; }
.sp-u-justify-between { justify-content: space-between; }

.sp-u-grid { display: grid; gap: var(--sp-density-gap); }
.sp-u-d-grid { display: grid; }
.sp-u-grid-2, .sp-u-grid-2col { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-density-gap); }
.sp-u-grid-3, .sp-u-grid-3col { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-density-gap); }
.sp-u-grid-auto-fill { display: grid; grid-template-columns: repeat(auto-fill, minmax(17.5rem, 1fr)); gap: var(--sp-density-gap); }

.sp-u-gap-4 { gap: var(--sp-space-4); }
.sp-u-gap-6 { gap: var(--sp-space-6); }
.sp-u-mt-2 { margin-top: var(--sp-space-2); }
.sp-u-mt-3 { margin-top: var(--sp-space-3); }
.sp-u-mt-4 { margin-top: var(--sp-space-4); }
.sp-u-mt-8 { margin-top: var(--sp-space-8); }
.sp-u-p-3 { padding: var(--sp-space-3); }
.sp-u-p-4 { padding: var(--sp-space-4); }
.sp-u-p-5 { padding: var(--sp-space-5); }

.sp-u-w-full { width: 100%; }
.sp-u-h-full { height: 100%; }
.sp-u-hidden { display: none; }
.sp-u-block { display: block; }
.sp-u-inline { display: inline; }
.sp-u-inline-block { display: inline-block; }
.sp-u-overflow-auto { overflow: auto; }
.sp-u-overflow-x-auto { overflow-x: auto; }
.sp-u-truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-u-border-top { border-top: 1px solid var(--sp-border-subtle); }
.sp-u-border-bottom { border-bottom: 1px solid var(--sp-border-subtle); }

.is-clickable { cursor: pointer; }

.sp-dashboard-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--sp-density-gap);
    margin-bottom: var(--sp-density-section);
}
.is-hidden { display: none; }

.sp-skip-link {
    position: absolute;
    top: -100%;
    left: var(--sp-space-2);
    padding: var(--sp-space-2) var(--sp-space-4);
    background: var(--sp-accent-fill);
    color: var(--sp-text-on-accent);
    border-radius: 0 0 var(--sp-radius-sm) var(--sp-radius-sm);
    z-index: var(--sp-z-toast);
    text-decoration: none;
    font-weight: var(--sp-font-semibold);
}

.sp-skip-link:focus-visible { top: 0; }

}

/* Print rules for the whole console, not for one page. The end-of-month report
   pages they were written for are gone; what survives is the general behaviour
   of an admin page sent to a printer: drop the chrome, unclip the tables. */

@media print {
    @page {
        size: A4;
        margin: 14mm;
    }

    body {
        background: #fff !important;
        color: #000 !important;
    }

    .sp-admin-sidebar,
    .sp-sidebar-close-btn,
    .sp-admin-footer,
    .sp-toolbar,
    .sp-topbar,
    .sp-notice-region,
    .sp-page-header__actions,
    .sp-table__cell--actions,
    [data-print-hide],
    [data-print-report] {
        display: none !important;
    }

    /* On screen the shell is a viewport-high flex box whose main column
       scrolls. A printer has no scrollbar: left as it is, every console page
       printed exactly one sheet and clipped the rest, so both boxes become
       ordinary flow for the page engine to paginate. */
    .sp-shell {
        display: block !important;
        height: auto !important;
        overflow: visible !important;
        background: #fff !important;
    }

    .sp-shell__main {
        display: block !important;
        height: auto !important;
        overflow: visible !important;
        margin: 0 !important;
        padding: 0 !important;
        max-width: none !important;
        background: none !important;
    }

    .sp-kpi-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }

    .sp-table__scroll {
        overflow: visible !important;
        background-image: none !important;
    }

    .sp-table {
        box-shadow: none;
        border: 1px solid #ccc;
    }

    .sp-table__el th {
        position: static;
    }

    .sp-table__el {
        width: 100% !important;
        max-width: 100% !important;
        font-size: 8pt;
    }

    .sp-table__el td,
    .sp-table__el th {
        white-space: normal !important;
        overflow: visible !important;
        min-width: 0 !important;
        max-width: none !important;
        padding: 2pt 4pt !important;
    }

    .sp-table__el td {
        overflow-wrap: anywhere;
    }

    .sp-table__el td.sp-table__cell--num,
    .sp-table__el td.sp-table__cell--date {
        white-space: nowrap !important;
    }

    html,
    body,
    .sp-shell,
    .sp-shell__main {
        width: 100% !important;
        min-width: 0 !important;
    }

    .sp-kpi,
    .sp-table__el {
        width: 100% !important;
        font-size: 8.5pt;
    }

    .sp-table__el thead {
        display: table-header-group;
    }

    .sp-table__el tr {
        break-inside: avoid;
    }

    a {
        color: #000 !important;
        text-decoration: none !important;
    }
}

@layer components {

/* Why: the grid is a matrix, not a list — both header rows and the entity
   column stay put while the body scrolls in both directions, or the reader
   loses which subject and which entity a cell belongs to. */
.sp-ac-audience__wrap {
    overflow: auto;
    max-height: 75vh;
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-ac-audience {
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--sp-text-sm);
    min-width: 100%;
}

.sp-ac-audience thead th {
    position: sticky;
    top: 0;
    z-index: var(--sp-z-sticky);
    background: var(--sp-bg-card-header);
    border-bottom: 1px solid var(--sp-border-default);
    text-align: center;
    vertical-align: bottom;
    padding: var(--sp-space-1) var(--sp-space-2);
}

/* Why: the second header row sits under the first; its offset is the first
   row's height, which the band row pins with a fixed line box. */
.sp-ac-audience__bands th { height: var(--sp-space-8); }
.sp-ac-audience thead tr + tr th { top: var(--sp-space-8); }

.sp-ac-audience__corner,
.sp-ac-audience__entity,
.sp-ac-audience__group-row th {
    position: sticky;
    left: 0;
    z-index: var(--sp-z-sticky);
    text-align: left;
    background: var(--sp-bg-surface);
    border-right: 1px solid var(--sp-border-default);
}

.sp-ac-audience__corner {
    z-index: var(--sp-z-sticky-header);
    background: var(--sp-bg-card-header);
    font-size: var(--sp-text-2xs);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
    min-width: 16rem;
}

/* Why: the three subject kinds are three different bands of the ladder;
   a tint per band keeps "role" and "group" columns from reading as one axis. */
.sp-ac-audience__band {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-secondary);
    border-left: 1px solid var(--sp-border-default);
}

.sp-ac-audience__band--role { background: var(--sp-bg-tertiary); }
.sp-ac-audience__band--group { background: color-mix(in oklch, var(--sp-info) 10%, var(--sp-bg-card-header)); }
.sp-ac-audience__band--project { background: color-mix(in oklch, var(--sp-accent) 8%, var(--sp-bg-card-header)); }

.sp-ac-audience__col {
    min-width: 5.5rem;
    max-width: 9rem;
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
    white-space: normal;
    overflow-wrap: normal;
    word-break: keep-all;
}

.sp-ac-audience__col--group { background: color-mix(in oklch, var(--sp-info) 5%, var(--sp-bg-card-header)); }
.sp-ac-audience__col--project { background: color-mix(in oklch, var(--sp-accent) 4%, var(--sp-bg-card-header)); }

.sp-ac-audience__col.is-focused {
    box-shadow: inset 0 calc(-1 * var(--sp-space-05)) 0 var(--sp-accent);
    color: var(--sp-accent-text);
}

.sp-ac-audience__col-link { color: inherit; text-decoration: none; }
.sp-ac-audience__col-link:hover { text-decoration: underline; }

.sp-ac-audience__col-counts {
    display: flex;
    justify-content: center;
    gap: var(--sp-space-1);
    margin-top: var(--sp-space-05);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-medium);
    font-variant-numeric: tabular-nums;
}

.sp-ac-audience__count--ok { color: var(--sp-success-strong); }
.sp-ac-audience__count--err { color: var(--sp-danger-strong); }
.sp-ac-audience__count::before { content: "✓"; margin-right: var(--sp-space-05); }
.sp-ac-audience__count--err::before { content: "✕"; }

.sp-ac-audience__group-row th {
    background: var(--sp-bg-tertiary);
    padding: var(--sp-space-1) var(--sp-space-3);
    border-top: 1px solid var(--sp-border-default);
    border-bottom: 1px solid var(--sp-border-subtle);
}

.sp-ac-audience__group-label {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-secondary);
}

.sp-ac-audience__entity {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-05);
    padding: var(--sp-space-1) var(--sp-space-3);
    border-bottom: 1px solid var(--sp-border-subtle);
    min-width: 16rem;
    max-width: 22rem;
}

.sp-ac-audience__entity-link {
    color: var(--sp-text-primary);
    font-weight: var(--sp-font-semibold);
    text-decoration: none;
}

.sp-ac-audience__entity-link:hover { color: var(--sp-accent-text); text-decoration: underline; }

.sp-ac-audience__entity-sub {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-ac-audience__row:hover .sp-ac-audience__entity { background: var(--sp-bg-tertiary); }
.sp-ac-audience__row:hover .sp-ac-audience__cell { filter: saturate(1.6); }

/* Why: the decision is the colour and the mark; the band word is deliberately
   quiet. Denied cells carry a real tint so a closed row is unmistakable, and
   no zebra striping competes with it. */
.sp-ac-audience__cell {
    padding: var(--sp-space-1) var(--sp-space-2);
    border-bottom: 1px solid var(--sp-border-subtle);
    border-left: 1px solid color-mix(in oklch, var(--sp-border-subtle) 50%, transparent);
    text-align: center;
    line-height: 1.15;
}

.sp-ac-audience__cell .sp-ac-audience__glyph { display: block; font-size: var(--sp-text-sm); font-weight: var(--sp-font-semibold); }
.sp-ac-audience__layer {
    display: block;
    font-size: var(--sp-text-2xs);
    letter-spacing: 0.02em;
    color: var(--sp-text-secondary);
}

.sp-ac-audience__cell.is-allow { background: var(--sp-success-dim); }
.sp-ac-audience__cell.is-allow .sp-ac-audience__glyph { color: var(--sp-success-strong); }
.sp-ac-audience__cell.is-deny { background: var(--sp-danger-dim); }
.sp-ac-audience__cell.is-deny .sp-ac-audience__glyph { color: var(--sp-danger-strong); }
.sp-ac-audience__cell.is-warn { background: var(--sp-warning-dim); }
.sp-ac-audience__cell.is-warn .sp-ac-audience__glyph { color: var(--sp-warning-strong); }
.sp-ac-audience__cell.is-pending { background: color-mix(in oklch, var(--sp-info) 12%, transparent); }
.sp-ac-audience__cell.is-pending .sp-ac-audience__glyph { color: var(--sp-info-strong); }

@media print {
    .sp-ac-audience__filters { display: none; }
    .sp-ac-audience__wrap { max-height: none; overflow: visible; }
    .sp-ac-audience__cell { print-color-adjust: exact; }
}

}

@layer components {

.sp-ac-field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    margin-bottom: var(--sp-space-3);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-ac-form-error {
    margin: 0 0 var(--sp-space-2);
    color: var(--sp-danger-strong);
    font-size: var(--sp-text-sm);
}

.sp-ac-modal-hint {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-ac-dialog {
    max-width: min(720px, 94vw);
}

.sp-ac-dialog__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    padding: var(--sp-space-4) var(--sp-space-5);
    border-bottom: 1px solid var(--sp-border-subtle);
}

.sp-ac-dialog__header h2 {
    margin: 0;
    font-size: var(--sp-text-lg);
}

.sp-ac-dialog__close {
    background: none;
    border: none;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-lg);
    line-height: 1;
    cursor: pointer;
}

.sp-ac-dialog__body {
    padding: var(--sp-space-5);
    max-height: 60vh;
    overflow-y: auto;
}

.sp-ac-dialog__actions {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-space-2);
    padding: var(--sp-space-4) var(--sp-space-5);
    border-top: 1px solid var(--sp-border-subtle);
}

/* Why: the band name is a fixed vocabulary next to free text, so it takes a
   monospace pill to read as a category rather than part of the sentence. */
.sp-ac-layer-tag {
    display: inline-block;
    padding: 0 var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface-raised);
    color: var(--sp-text-secondary);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    line-height: var(--sp-leading-normal);
    white-space: nowrap;
}

.sp-ac-yaml-pre {
    margin: 0;
    padding: var(--sp-space-3);
    background: var(--sp-bg-surface-raised);
    border-radius: var(--sp-corners-sm);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    white-space: pre-wrap;
    overflow-x: auto;
}

}

@layer components {

.sp-ac-audience__legend {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin: var(--sp-space-3) 0;
    font-size: var(--sp-text-xs);
}

.sp-ac-audience__legend .sp-ac-audience__glyph { font-weight: var(--sp-font-semibold); }
.sp-ac-audience__legend-note { color: var(--sp-text-tertiary); }

.sp-ac-audience__kpis { margin-top: var(--sp-space-3); }

.sp-ac-audience__focus {
    margin: var(--sp-space-3) 0 var(--sp-space-4);
    padding: var(--sp-space-3) var(--sp-space-4);
    border: 1px solid var(--sp-border-default);
    border-left: var(--sp-space-1) solid var(--sp-accent);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-ac-audience__focus-kind {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
    margin-right: var(--sp-space-1);
}

.sp-ac-audience__focus-sub {
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-normal);
    color: var(--sp-text-tertiary);
}

/* Why: one card per decision, side by side when the width allows, so the
   allowed and denied sets can be compared without scrolling between them. */
.sp-ac-audience__buckets {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
    align-items: start;
    gap: var(--sp-space-3);
    margin-top: var(--sp-space-3);
}

.sp-ac-audience__bucket { padding: var(--sp-space-3); border-top: var(--sp-space-05) solid var(--sp-border-default); }
.sp-ac-audience__bucket--ok { border-top-color: var(--sp-success); }
.sp-ac-audience__bucket--err { border-top-color: var(--sp-danger); }
.sp-ac-audience__bucket--warn { border-top-color: var(--sp-warning); }
.sp-ac-audience__bucket--info { border-top-color: var(--sp-info); }

.sp-ac-audience__bucket-title {
    display: flex;
    align-items: center;
    gap: var(--sp-space-1);
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
}

.sp-ac-audience__bucket--ok .sp-ac-audience__glyph { color: var(--sp-success-strong); }
.sp-ac-audience__bucket--err .sp-ac-audience__glyph { color: var(--sp-danger-strong); }
.sp-ac-audience__bucket--warn .sp-ac-audience__glyph { color: var(--sp-warning-strong); }
.sp-ac-audience__bucket--info .sp-ac-audience__glyph { color: var(--sp-info-strong); }

.sp-ac-audience__bucket-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--sp-text-xs);
}

.sp-ac-audience__bucket-table th,
.sp-ac-audience__bucket-table td {
    padding: var(--sp-space-1) var(--sp-space-2);
    text-align: left;
    vertical-align: top;
}

.sp-ac-audience__bucket-table th {
    color: var(--sp-text-tertiary);
    font-weight: var(--sp-font-medium);
    text-transform: uppercase;
    font-size: var(--sp-text-2xs);
    letter-spacing: var(--sp-tracking-wide);
}

.sp-ac-audience__bucket-table tr + tr td { border-top: 1px solid var(--sp-border-subtle); }

.sp-ac-audience__bucket-label {
    display: block;
    color: var(--sp-text-primary);
    font-weight: var(--sp-font-semibold);
    text-decoration: none;
}

.sp-ac-audience__bucket-label:hover { color: var(--sp-accent-text); text-decoration: underline; }

.sp-ac-audience__bucket-kind {
    display: block;
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
}

.sp-ac-audience__none { color: var(--sp-text-tertiary); }

}

@layer components {

/* Why: the search is the whole tab until it has run, so it reads as one
   line — the input takes the width, the button sits beside it. */
.sp-ac-person__picker { margin-bottom: var(--sp-space-4); }

.sp-ac-person__field { flex: 1 1 24rem; }

.sp-ac-person__field .sp-search-input { width: 100%; }

.sp-ac-person__hits {
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-ac-person__who {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    margin-bottom: var(--sp-space-4);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface-raised);
}

.sp-ac-person__who .sp-user-cell-text { flex: 1 1 auto; }

}

@layer components {

/* Why: the per-entity rule list is a table inside a cell; it inherits the
   body type so it reads as detail, not as a second data table. */
.sp-ac-rules {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--sp-text-xs);
}

.sp-ac-rules th,
.sp-ac-rules td {
    padding: var(--sp-space-1) var(--sp-space-2);
    text-align: left;
    vertical-align: top;
}

.sp-ac-rules th {
    color: var(--sp-text-tertiary);
    font-weight: 500;
}

.sp-ac-rules tr + tr td { border-top: 1px solid var(--sp-border-subtle); }

/* Why: one band is a labelled cluster of chips, so "group india-devs, uk"
   reads as a unit and two bands on the same entity do not run together. */
.sp-ac-band {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-1);
    margin: 0 var(--sp-space-2) var(--sp-space-1) 0;
}

.sp-ac-band__label {
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--sp-text-tertiary);
}

.sp-ac-band__chip {
    padding: 0 var(--sp-space-2);
    border-radius: var(--sp-radius-full);
    background: var(--sp-badge-accent-bg);
    color: var(--sp-text-primary);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    line-height: var(--sp-leading-normal);
    white-space: nowrap;
}

.sp-ac-band--deny .sp-ac-band__chip {
    background: var(--sp-danger-dim);
    color: var(--sp-danger-strong);
}

/* Why: one heading row per entity kind turns the ledger into a catalogue;
   it is a table row so the columns above still line up with the rows below. */
.sp-ac-group + .sp-ac-group .sp-ac-group__row th { border-top: 1px solid var(--sp-border-subtle); }

.sp-ac-group__row th {
    padding: var(--sp-space-3) var(--sp-space-2) var(--sp-space-1);
    border-bottom: 1px solid var(--sp-border-subtle);
    background: var(--sp-bg-surface-raised);
    text-align: left;
}

.sp-ac-group__label {
    font-size: var(--sp-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--sp-text-secondary);
}

}

@layer components {

/* Why: the entity and its reason are what say what this row is, so those two
   take the slack and every other column is sized to its content. */
.sp-p-ac__entities .sp-col-default { width: 6rem; }
.sp-p-ac__entities .sp-col-reaches { width: 22%; }
.sp-p-ac__entities .sp-col-denied { width: 10rem; }
.sp-p-ac__entities .sp-col-state { width: 7.5rem; }

.sp-p-ac__entities .sp-col-entity,
.sp-p-ac__entities .sp-col-why { min-width: 12rem; }
.sp-p-ac__diff .sp-u-text-secondary { max-width: 22rem; }

.sp-ac-drift .sp-btn { margin-top: var(--sp-space-2); }

/* Why: the model in five lines, open on first visit and collapsible after.
   A <details> so it costs nothing to keep on the page once it has been read. */
.sp-ac-explain {
    margin-block: var(--sp-space-4);
    padding: var(--sp-space-3) var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-ac-explain > summary {
    cursor: pointer;
    font-weight: 600;
    color: var(--sp-text-primary);
}

.sp-ac-explain__body {
    display: grid;
    grid-template-columns: minmax(16rem, 22rem) 1fr;
    gap: var(--sp-space-5);
    margin-top: var(--sp-space-3);
}

.sp-ac-explain__rules {
    margin: 0;
    padding-left: var(--sp-space-4);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-ac-explain__rules li + li { margin-top: var(--sp-space-1); }

.sp-ac-explain__more {
    grid-column: 1 / -1;
    margin: 0;
    font-size: var(--sp-text-sm);
}

/* Why: the ladder is drawn as a ladder — narrowest band at the top, precedence
   number beside it — because the order IS the rule. */
.sp-ac-ladder {
    margin: 0;
    padding: 0;
    list-style: none;
    border-left: 2px solid var(--sp-border-strong);
}

.sp-ac-ladder li {
    display: grid;
    grid-template-columns: 8rem 3rem 1fr;
    gap: var(--sp-space-2);
    align-items: baseline;
    padding: var(--sp-space-1) var(--sp-space-3);
    font-size: var(--sp-text-sm);
}

.sp-ac-ladder li + li { border-top: 1px dashed var(--sp-border-subtle); }

.sp-ac-ladder__band {
    font-weight: 600;
    color: var(--sp-text-primary);
}

.sp-ac-ladder__prec {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-ac-ladder__note { color: var(--sp-text-secondary); }

.sp-ac-entity[data-entity-type] > td { vertical-align: top; }

.sp-ac-entity__summary,
.sp-ac-entity__details > summary {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-05);
    cursor: pointer;
    list-style: none;
}

.sp-ac-entity__details > summary::-webkit-details-marker { display: none; }

.sp-ac-entity__kind {
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--sp-text-tertiary);
}

/* Why: the label is what the row is called; the generated id is kept as a
   quiet subtitle so a rule written against it can still be matched by eye. */
.sp-ac-entity__label {
    color: var(--sp-text-primary);
    font-weight: 500;
}

.sp-ac-entity__sub {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-ac-entity__id {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-ac-entity__details[open] .sp-ac-entity__label { text-decoration: underline dotted; }

.sp-ac-entity__expanded {
    margin-top: var(--sp-space-3);
    padding: var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface-raised);
}

.sp-ac-entity__resolution {
    margin: 0 0 var(--sp-space-3);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
}

.sp-ac-entity__why {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}


@media (max-width: 900px) {
    .sp-ac-explain__body { grid-template-columns: 1fr; }
}

}

@layer components {

.sp-timeseries[data-tone="info"] .sp-timeseries__bar {
    background: var(--sp-chart-cyan);
}

.sp-analytics-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-space-4);
    margin-block: var(--sp-space-6);
}

/* A panel has a fixed height, not a minimum: the live chart draws its SVG at
   the host's pixel height, so a panel that grew with its content would grow
   the SVG, which grows the panel, without end. The donut's ring is sized to
   the same height so the four panels read as one row. */
.sp-analytics-grid__panel {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    padding: var(--sp-space-4) var(--sp-space-5);
    min-width: 0;
    block-size: 26rem;
    overflow: auto;
}

.sp-analytics-filters {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-4);
}

.sp-analytics-filters__group {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

}

@layer components {

.sp-pie-chart__value {
    grid-area: value;
    text-align: right;
    white-space: nowrap;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

/* Index order mirrors CHART_COLOR_TOKENS in the admin line-chart module so
   a model keeps one colour across the disc, the bars and both legends. */
.sp-pie-chart__swatch--1 { background: var(--sp-chart-purple); }
.sp-pie-chart__swatch--2 { background: var(--sp-chart-blue); }
.sp-pie-chart__swatch--3 { background: var(--sp-chart-green); }
.sp-pie-chart__swatch--4 { background: var(--sp-chart-amber); }
.sp-pie-chart__swatch--5 { background: var(--sp-chart-red); }
.sp-pie-chart__swatch--6 { background: var(--sp-chart-cyan); }
.sp-pie-chart__swatch--7 { background: var(--sp-chart-indigo); }
.sp-pie-chart__bar--1 { --bar-color: var(--sp-chart-purple); }
.sp-pie-chart__bar--2 { --bar-color: var(--sp-chart-blue); }
.sp-pie-chart__bar--3 { --bar-color: var(--sp-chart-green); }
.sp-pie-chart__bar--4 { --bar-color: var(--sp-chart-amber); }
.sp-pie-chart__bar--5 { --bar-color: var(--sp-chart-red); }
.sp-pie-chart__bar--6 { --bar-color: var(--sp-chart-cyan); }
.sp-pie-chart__bar--7 { --bar-color: var(--sp-chart-indigo); }

.sp-svgchart__legend {
    flex: 0 0 auto;
    flex-direction: row;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: var(--sp-space-1) var(--sp-space-4);
}

@media (max-width: 64rem) {
    .sp-analytics-grid { grid-template-columns: minmax(0, 1fr); }
}
}

@layer components {

/* The distribution donut: a ring sized to its panel, the total in the hole,
   and a legend whose rows carry a share bar in the slice's colour. The
   swatch and bar colour indices live in 20-page-analytics-dashboard2.css
   beside the chart colour tokens they mirror. */

.sp-pie-chart {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    flex: 1;
    margin: 0;
    min-width: 0;
}

.sp-pie-chart__head {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-05);
}

.sp-pie-chart__title {
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-primary);
}

.sp-pie-chart__subtitle {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

/* The ring takes the panel's height and the legend the rest of its width;
   on a narrow panel the legend drops under the ring. */
.sp-pie-chart__body {
    display: flex;
    align-items: center;
    gap: var(--sp-space-5);
    flex: 1;
    min-height: 0;
    flex-wrap: wrap;
}

.sp-pie-chart__ring {
    position: relative;
    flex: 0 1 15rem;
    min-width: 11rem;
    max-width: 16rem;
    aspect-ratio: 1;
    align-self: center;
}

.sp-pie-chart__svg {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
}

/* A slice lifts on hover and its siblings step back, so the one under the
   pointer is the one the tooltip names. */
.sp-pie-chart__arc {
    transition: opacity var(--sp-duration-fast) ease, transform var(--sp-duration-fast) ease;
    transform-origin: 50% 50%;
    transform-box: view-box;
}

.sp-pie-chart__svg:hover .sp-pie-chart__arc {
    opacity: 0.45;
}

.sp-pie-chart__svg .sp-pie-chart__arc:hover {
    opacity: 1;
    transform: scale(1.04);
}

.sp-pie-chart__center {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: none;
}

.sp-pie-chart__center-value {
    font-size: var(--sp-text-2xl);
    font-weight: 600;
    line-height: 1;
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-pie-chart__center-label {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    margin-top: var(--sp-space-1);
}

.sp-pie-chart__legend {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    min-width: 0;
    flex: 1;
}

.sp-pie-chart__item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto auto;
    grid-template-areas:
        "swatch label share value"
        "swatch bar   bar   bar";
    column-gap: var(--sp-space-2);
    row-gap: var(--sp-space-05);
    align-items: baseline;
    font-size: var(--sp-text-xs);
}

/* The share as a bar under each row, filled to `--v`, in the slice's colour. */
.sp-pie-chart__bar {
    grid-area: bar;
    display: block;
    height: 0.25rem;
    border-radius: var(--sp-radius-sm);
    background: linear-gradient(var(--sp-border-subtle), var(--sp-border-subtle));
    position: relative;
    overflow: hidden;
}

.sp-pie-chart__bar::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: var(--v, 0%);
    background: var(--bar-color, var(--sp-accent));
    border-radius: inherit;
}

.sp-pie-chart__item--inline {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    white-space: nowrap;
}

.sp-pie-chart__swatch {
    grid-area: swatch;
    width: 0.65rem;
    height: 0.65rem;
    border-radius: var(--sp-radius-sm);
    align-self: center;
}

.sp-pie-chart__label {
    grid-area: label;
    color: var(--sp-text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-pie-chart__label a {
    color: inherit;
    text-decoration: none;
}

.sp-pie-chart__label a:hover {
    text-decoration: underline;
}

.sp-pie-chart__share {
    grid-area: share;
    font-variant-numeric: tabular-nums;
    color: var(--sp-text-secondary);
}

}

@layer components {

/* The fold budget. The log is the page, so the bands above it are held tight
   enough that twelve rows clear 900px: header, tabs, tiles, one toolbar. */
.sp-p-requests__band + .sp-p-requests__band {
    margin-top: var(--sp-space-3);
}

.sp-p-requests__band.sp-kpi-grid {
    margin-bottom: 0;
}

/* The log is the page, so its chrome is budgeted: the five facets are one
   inline row rather than five stacked full-width controls, which is what put
   the table below the fold. */
.sp-p-requests__filters {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--sp-space-2);
    min-width: 0;
}

.sp-p-requests__filters .sp-search-input {
    width: auto;
    min-width: 0;
    flex: 1 1 0;
    max-width: 11rem;
}

.sp-p-requests__filters .sp-toolbar__search {
    flex: 2 1 0;
    min-width: 0;
}

.sp-p-requests-table .sp-col-project,
.sp-p-requests-table .sp-col-group {
    width: 8rem;
    min-width: 5.5rem;
}

.sp-p-requests-table .sp-col-model {
    width: 10rem;
    min-width: 7rem;
}

.sp-table__row[data-href] {
    cursor: pointer;
}

.sp-pagination__current {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-pagination__current:first-child {
    margin-right: auto;
}

@media (max-width: 80rem) {
    .sp-p-requests-table .sp-col-group { display: none; }
}

}

@layer components {

/* The row of link-groups that change how the page reads its own numbers:
   attribution, bucket size, cost audience and container axis. They sit on one
   line so the reader sees every claim-changing control at once. */
.sp-p-analytics__controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-4);
}

.sp-p-analytics__toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
}

.sp-p-analytics__toggle-label {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    margin-inline-end: var(--sp-space-1);
}

/* The share cell's bar. The fill is drawn to --v, which the handler floors at
   a visible width for any non-zero share: a model with real traffic must not
   render identically to one with none. A true zero draws the track only. */
.sp-p-analytics__bar {
    display: block;
    inline-size: 100%;
    min-inline-size: var(--sp-space-8);
    block-size: var(--sp-space-2);
    border-radius: var(--sp-radius-sm);
    background:
        linear-gradient(to right, var(--sp-accent) var(--v, 0%), transparent var(--v, 0%)),
        color-mix(in oklch, var(--sp-text-primary) 8%, transparent);
}

/* The name cell is one line and does not clip. Two bars pull against each
   other here: an ellipsized name is a defect, because that is the value
   telling you which row you are reading, and a row over 36px is a defect too.
   Neither is bought from the other — the width comes from dropping columns and
   from showing the half of the id that differs, and the qualifier that used to
   sit on a second line is on the title instead. */
.sp-p-analytics__name {
    white-space: nowrap;
}

}

@layer components {

/* Artifact detail: /admin/artifacts/{id}. The body is third-party content
   and is bounded so a large result never becomes the page. */
.sp-p-artifact-detail__body {
    max-block-size: 40rem;
    overflow: auto;
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-md);
    background: var(--sp-bg-surface);
    font-size: var(--sp-text-sm);
    white-space: pre-wrap;
    word-break: break-word;
}

.sp-p-artifact-detail__preview {
    inline-size: 100%;
    min-block-size: 24rem;
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-md);
    background: var(--sp-bg-surface);
}

.sp-p-artifact-detail__clean {
    color: var(--sp-text-secondary);
}

}

@layer components {
.sp-chip {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: var(--sp-space-05) var(--sp-space-2);
    border-radius: var(--sp-radius-full);
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-medium);
    border: 1px solid var(--sp-border-subtle);
    background: var(--sp-bg-surface-alt);
    color: var(--sp-text-secondary);
    line-height: 1.6;
}

.sp-chip--tag {
    border-color: var(--sp-accent-dim);
    color: var(--sp-accent-text);
    background: var(--sp-accent-surface);
}

.sp-chip--muted {
    color: var(--sp-text-tertiary);
}

.sp-catalog-meta-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin: var(--sp-space-3) 0;
}

.sp-catalog-detail-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: var(--sp-space-4);
    margin-top: var(--sp-space-4);
}

.sp-catalog-rel-section {
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    padding: var(--sp-space-4);
}

.sp-catalog-rel-section__title {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--sp-text-tertiary);
    margin: 0 0 var(--sp-space-3);
}

/* Why: the entry name is the cell every one of these tables is read by, and a
   fixed layout splits width evenly until told otherwise — which ellipsized
   plugin and skill names while the numeric columns sat half empty. The name
   takes a third; the rest share what is left. */
.sp-p-catalog__table th:first-child,
.sp-p-catalog__table td:first-child {
    width: 32%;
}

}

@layer components {
.sp-count-pill {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4em;
    padding: 0 var(--sp-space-2);
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent-surface);
    color: var(--sp-accent-text);
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-bold);
}

.sp-rel-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
}

.sp-rel-link {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-2);
    padding: var(--sp-space-2) var(--sp-space-3);
    border-radius: var(--sp-radius-sm);
    text-decoration: none;
    color: var(--sp-text-primary);
    transition: background 0.12s ease;
}

.sp-rel-link:hover {
    background: var(--sp-bg-surface-alt);
}

.sp-rel-link--static {
    cursor: default;
}

.sp-rel-link__name {
    font-weight: var(--sp-font-medium);
}

.sp-rel-hook {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-2) var(--sp-space-3);
    border-radius: var(--sp-radius-sm);
    background: var(--sp-bg-surface-alt);
}

.sp-table__link {
    color: var(--sp-accent-text);
    font-weight: var(--sp-font-medium);
    text-decoration: none;
}

.sp-table__link:hover {
    text-decoration: underline;
}

}

/* /admin/configuration — one row per kind of configuration the instance
   loads. Column widths keep the path and the hash from crowding the label. */
@layer components {

.sp-config td:first-child { min-width: 14rem; }

.sp-config td:nth-child(2) {
    max-width: 18rem;
    font-size: var(--sp-text-xs);
    overflow-wrap: anywhere;
}

.sp-config td:nth-child(6),
.sp-config td:nth-child(7) {
    font-size: var(--sp-text-sm);
}

}

@layer components {

.sp-p-connect__issue {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-4);
}

.sp-p-connect__status {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0;
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-success);
    border-radius: var(--sp-corners-sm);
    background: color-mix(in oklch, var(--sp-success) 8%, var(--sp-bg-surface));
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
}

.sp-p-connect__status code {
    padding: 0 var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    background: var(--sp-bg-surface);
    color: var(--sp-text-primary);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-base);
    letter-spacing: 0.04em;
    user-select: all;
}

/* Why: display:flex in this layer outranks the reset's [hidden] rule, so
   the hidden attribute the script toggles has to be restated here. */
.sp-p-connect__status[hidden],
.sp-p-connect__pending[hidden] { display: none; }

.sp-p-connect__status-label { font-weight: 600; color: var(--sp-success-strong); }
.sp-p-connect__status-expiry strong { font-variant-numeric: tabular-nums; }

.sp-p-connect__error {
    margin: var(--sp-space-3) 0 0;
    color: var(--sp-danger-strong);
    font-size: var(--sp-text-sm);
}

.sp-p-connect__pending {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-2) 0;
    padding: var(--sp-space-4) var(--sp-space-5);
    border: 1px dashed var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface-alt);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
}

.sp-p-connect__pending::before {
    content: "";
    flex: none;
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-text-tertiary);
}

.sp-p-connect__wizard[data-connect-state="expired"] .sp-p-connect__pending {
    border-style: solid;
    border-color: var(--sp-warning);
    color: var(--sp-text-primary);
}

.sp-p-connect__wizard[data-connect-state="expired"] .sp-p-connect__pending::before { background: var(--sp-warning); }

}

@layer components {

/* Why: a download is an action, not a table row. Each platform gets its own
   card with a visible Download button, so the call to action reads as a
   link rather than a filename in body text. */
.sp-p-connect__downloads {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: var(--sp-space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-p-connect__downloads li {
    display: grid;
    gap: var(--sp-space-2);
    padding: var(--sp-space-4);
    font-size: var(--sp-text-sm);
}

.sp-p-connect__downloads strong { font-size: var(--sp-text-base); }

.sp-p-connect__downloads code {
    color: var(--sp-text-secondary);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    overflow-wrap: anywhere;
}

.sp-p-connect__download-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin-block-start: var(--sp-space-2);
}

.sp-p-connect__guides {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    gap: var(--sp-space-3);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-p-connect__guide-link {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    block-size: 100%;
    padding: var(--sp-space-4);
    color: inherit;
    text-decoration: none;
}

.sp-p-connect__guide-link strong { font-size: var(--sp-text-sm); }
.sp-p-connect__guide-link span { color: var(--sp-text-secondary); font-size: var(--sp-text-xs); }
.sp-p-connect__guide-link:hover strong { color: var(--sp-accent-text); }

.sp-p-connect__guide-link::after {
    content: "Read the guide →";
    margin-block-start: auto;
    padding-block-start: var(--sp-space-2);
    color: var(--sp-accent-text);
    font-size: var(--sp-text-xs);
    font-weight: 600;
}

.sp-p-connect__section .sp-table__el tbody tr.is-active {
    background: var(--sp-bg-accent-wash);
}

.sp-p-connect__section .sp-table__el tbody tr.is-active td:first-child {
    box-shadow: inset 2px 0 0 var(--sp-accent);
}

}

@layer components {

.sp-p-connect__wizard,
.sp-p-connect__section { margin-block: var(--sp-space-5) var(--sp-space-8); }
.sp-p-connect__wizard .sp-card__body { padding: 0 var(--sp-space-6); }

/* Why: each step is a two-column row — the number, title and one-line
   explanation on the left, the control on the right — so the wizard uses the
   full console width instead of stacking narrow blocks under one another. */
.sp-p-connect__step {
    display: grid;
    grid-template-columns: minmax(14rem, 20rem) minmax(0, 1fr);
    gap: var(--sp-space-6) var(--sp-space-8);
    padding-block: var(--sp-space-6);
    border-block-start: 1px solid var(--sp-border-subtle);
}

.sp-p-connect__step:first-child { border-block-start: 0; }

.sp-p-connect__step-heading {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: var(--sp-space-3);
    align-items: center;
    align-content: start;
}

.sp-p-connect__step-heading h3 { margin: 0; font-size: var(--sp-text-base); }

.sp-p-connect__step-heading p {
    grid-column: 2;
    margin: var(--sp-space-1) 0 0;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    line-height: 1.6;
}

.sp-p-connect__step-num {
    display: grid;
    place-items: center;
    inline-size: 1.75rem;
    block-size: 1.75rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent-fill);
    color: var(--sp-text-on-accent);
    font-size: var(--sp-text-xs);
    font-weight: 700;
}

.sp-p-connect__step-body { min-inline-size: 0; }

.sp-p-connect__lede {
    margin-block: 0 var(--sp-space-3);
    max-inline-size: 90ch;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    line-height: 1.6;
}

.sp-p-connect__lede a {
    color: var(--sp-accent-text);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.sp-p-connect__label {
    display: block;
    margin-block: var(--sp-space-4) var(--sp-space-2);
    color: var(--sp-text-primary);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.sp-p-connect__ready > .sp-p-connect__label:first-child { margin-block-start: 0; }

.sp-p-connect__wizard .sp-tabs {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-space-3);
    border: 0;
    overflow: visible;
    margin: 0;
}

.sp-p-connect__wizard .sp-tab {
    display: grid;
    gap: var(--sp-space-1);
    justify-items: start;
    text-align: start;
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    color: var(--sp-text-primary);
    white-space: normal;
    top: 0;
}

.sp-p-connect__wizard .sp-tab strong { font-size: var(--sp-text-sm); font-weight: 600; }
.sp-p-connect__wizard .sp-tab span { color: var(--sp-text-secondary); font-size: var(--sp-text-xs); font-weight: 400; }

.sp-p-connect__wizard .sp-tab:hover { border-color: var(--sp-border-strong); }

.sp-p-connect__wizard .sp-tab--active,
.sp-p-connect__wizard .sp-tab[aria-selected="true"] {
    border-color: var(--sp-accent-text);
    background: var(--sp-accent-surface);
    box-shadow: inset 0 0 0 1px var(--sp-accent-text);
}

.sp-p-connect__wizard .sp-tab--active strong { color: var(--sp-accent-text); }

.sp-p-connect__guide {
    display: flex;
    flex-wrap: wrap;
    align-items: start;
    justify-content: space-between;
    gap: var(--sp-space-3);
    margin-block: 0 var(--sp-space-4);
}

.sp-p-connect__guide .sp-p-connect__lede { margin: 0; max-inline-size: 65ch; }

.sp-p-connect__wizard .sp-connect__cmd {
    min-block-size: 4rem;
    margin-block: 0 var(--sp-space-3);
    padding: var(--sp-space-4) var(--sp-space-8) var(--sp-space-4) var(--sp-space-4);
    font-size: var(--sp-text-xs);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    line-height: 1.7;
}

.sp-p-connect__advanced {
    padding: var(--sp-space-3) 0;
    border-block-start: 1px solid var(--sp-border-subtle);
}

.sp-p-connect__advanced summary {
    cursor: pointer;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    font-weight: 600;
}

.sp-p-connect__advanced[open] summary { margin-bottom: var(--sp-space-3); }

}

@layer responsive {
@media (max-width: 72rem) {
    .sp-p-connect__step { grid-template-columns: minmax(0, 1fr); gap: var(--sp-space-4); }
}
@media (max-width: 40rem) {
    .sp-p-connect__wizard .sp-card__body { padding: 0 var(--sp-space-4); }
    .sp-p-connect__step { padding-block: var(--sp-space-4); }
    .sp-p-connect__wizard .sp-tabs { grid-template-columns: minmax(0, 1fr); gap: var(--sp-space-2); }
}
}

@layer components {

/* The handshake, one row per stage. A stage is pending, running, ok, failed
   or skipped; the mark carries the state so the eye reads the column before
   the words, and a failure names the stage rather than the provider. */

.sp-connector__check {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface-alt);
}

.sp-connector__check[hidden] { display: none; }

.sp-connector__steps {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-connector__step {
    display: grid;
    grid-template-columns: 1.25rem 7rem minmax(0, 1fr) auto;
    align-items: baseline;
    column-gap: var(--sp-space-2);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-connector__step-mark {
    display: inline-block;
    inline-size: 0.75rem;
    block-size: 0.75rem;
    align-self: center;
    border: 2px solid var(--sp-border-default);
    border-radius: var(--sp-radius-full);
}

.sp-connector__step.is-running .sp-connector__step-mark {
    border-top-color: var(--sp-accent);
    animation: sp-spin var(--sp-duration-slow) linear infinite;
}

.sp-connector__step.is-ok .sp-connector__step-mark {
    border-color: var(--sp-success);
    background: var(--sp-success);
}

.sp-connector__step.is-fail .sp-connector__step-mark {
    border-color: var(--sp-danger);
    background: var(--sp-danger);
}

.sp-connector__step.is-skipped { opacity: 0.6; }

.sp-connector__step-title {
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}

.sp-connector__step.is-ok .sp-connector__step-title,
.sp-connector__step.is-running .sp-connector__step-title { color: var(--sp-text-primary); }
.sp-connector__step.is-fail .sp-connector__step-title { color: var(--sp-danger-strong); }

.sp-connector__step-detail {
    overflow-wrap: anywhere;
    color: var(--sp-text-secondary);
}

.sp-connector__step.is-fail .sp-connector__step-detail { color: var(--sp-danger-strong); }

.sp-connector__step-ms {
    font-family: var(--sp-font-mono);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.sp-connector__summary {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-connector__summary.is-ok { color: var(--sp-success-strong); }
.sp-connector__summary.is-fail { color: var(--sp-danger-strong); }

/* The personal-token and site forms open inside the card, under the actions,
   so a person types where they clicked and cancels back to the same card. */

.sp-connector__form {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--sp-space-3);
    align-items: end;
    padding: var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-base);
}

.sp-connector__form label {
    display: grid;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-connector__form .sp-connector__actions { grid-column: 1 / -1; margin-top: 0; }

}

@layer responsive {
@media (max-width: 40rem) {
    .sp-connector__step { grid-template-columns: 1.25rem minmax(0, 1fr) auto; }
    .sp-connector__step-detail { grid-column: 2 / -1; }
}
}

@layer components {

/* The health strip answers "am I set up?" in one glance: a headline, the one
   thing to do next, and a bar whose green and amber lengths are the counts.
   The four stats beside it are the same numbers, so a person who wants the
   figure reads it without leaving the strip. */

.sp-connect-health {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    gap: var(--sp-space-6);
    align-items: center;
    margin-block: 0 var(--sp-space-6);
    padding: var(--sp-space-5) var(--sp-space-6);
    background: var(--sp-bg-surface);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
}

.sp-connect-health__lead {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    min-width: 0;
}

.sp-connect-health__headline {
    margin: 0;
    font-size: var(--sp-text-xl);
    font-weight: var(--sp-font-semibold);
    line-height: var(--sp-leading-snug);
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-connect-health__next {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-connect-health__next[hidden] { display: none; }

.sp-connect-health__bar {
    display: flex;
    height: var(--sp-space-2);
    margin-top: var(--sp-space-2);
    overflow: hidden;
    border-radius: var(--sp-radius-sm);
    background: var(--sp-bg-tertiary);
}

.sp-connect-health__seg {
    flex: 0 0 var(--sp-fill, 0%);
    transition: flex-basis var(--sp-duration-fast) var(--sp-ease-in-out);
}

.sp-connect-health__seg--ok {
    background: linear-gradient(90deg, var(--sp-progress-green-from), var(--sp-progress-green-to));
}

.sp-connect-health__seg--warn {
    background: linear-gradient(90deg, var(--sp-progress-amber-from), var(--sp-progress-amber-to));
}

.sp-connect-health__stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--sp-space-3);
    margin: 0;
}

.sp-connect-health__stat {
    display: flex;
    flex-direction: column-reverse;
    gap: var(--sp-space-1);
    padding-inline-start: var(--sp-space-3);
    border-inline-start: 2px solid var(--sp-border-subtle);
}

.sp-connect-health__stat--ok   { border-inline-start-color: var(--sp-success); }
.sp-connect-health__stat--warn { border-inline-start-color: var(--sp-warning); }

.sp-connect-health__stat dt {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    letter-spacing: var(--sp-tracking-wide);
    text-transform: uppercase;
    color: var(--sp-text-tertiary);
}

.sp-connect-health__stat dd {
    margin: 0;
    font-size: var(--sp-text-xl);
    font-weight: var(--sp-font-semibold);
    line-height: 1;
    color: var(--sp-text-primary);
    font-variant-numeric: tabular-nums;
}

.sp-p-connectors__message { margin-block: 0 var(--sp-space-3); }
.sp-p-connectors__message[hidden] { display: none; }

/* Groups read as a to-do list: the first section is the one to act on, and
   an empty group is not rendered, so the page never opens on "nothing here". */

.sp-connector-group + .sp-connector-group { margin-top: var(--sp-density-section); }

.sp-connector-group[data-group="quiet"] .sp-connector { opacity: 0.82; }

}

@layer responsive {
@media (max-width: 56rem) {
    .sp-connect-health { grid-template-columns: minmax(0, 1fr); }
    .sp-connect-health__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
}

@layer components {

/* One card per provider, and every card the same shape: mark, name and kind
   on one row, what it unlocks beneath, the account facts as a list, then the
   actions pinned to the bottom edge so the primary button of every card in a
   row sits on the same line. The status colour lives on the mark's ring and
   the card's leading edge, never on the whole surface. */

.sp-connector-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr));
    gap: var(--sp-space-4);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-connector {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    padding: var(--sp-space-5);
    background: var(--sp-bg-surface);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
    border-inline-start: 3px solid var(--sp-border-subtle);
    transition: box-shadow var(--sp-duration-fast) var(--sp-ease-in-out);
}

.sp-connector:hover { box-shadow: var(--sp-shadow-card-hover); }

.sp-connector[data-status="connected"] { border-inline-start-color: var(--sp-success); }
.sp-connector[data-status="reconnect_required"],
.sp-connector[data-status="verification_required"] { border-inline-start-color: var(--sp-warning); }
.sp-connector[data-status="temporarily_unavailable"] { border-inline-start-color: var(--sp-danger); }

.sp-connector__head {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    column-gap: var(--sp-space-3);
}

.sp-connector__mark {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: var(--sp-space-10);
    height: var(--sp-space-10);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-tertiary);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-md);
    font-weight: var(--sp-font-semibold);
    letter-spacing: var(--sp-tracking-wide);
}

.sp-connector[data-glyph="salesforce"] .sp-connector__mark,
.sp-connector[data-glyph="atlassian"] .sp-connector__mark,
.sp-connector[data-glyph="google"] .sp-connector__mark {
    background: var(--sp-accent-dim);
    color: var(--sp-accent-text);
}

.sp-connector[data-status="connected"] .sp-connector__mark {
    background: var(--sp-success-dim);
    color: var(--sp-success-strong);
}

.sp-connector__mark::after {
    content: "";
    position: absolute;
    right: calc(-1 * var(--sp-space-1));
    bottom: calc(-1 * var(--sp-space-1));
    width: var(--sp-space-3);
    height: var(--sp-space-3);
    border: 2px solid var(--sp-bg-surface);
    border-radius: var(--sp-radius-full);
    background: var(--sp-border-default);
}

.sp-connector[data-status="connected"] .sp-connector__mark::after { background: var(--sp-success); }
.sp-connector[data-status="reconnect_required"] .sp-connector__mark::after,
.sp-connector[data-status="verification_required"] .sp-connector__mark::after { background: var(--sp-warning); }
.sp-connector[data-status="temporarily_unavailable"] .sp-connector__mark::after { background: var(--sp-danger); }

.sp-connector__title {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-05);
    min-width: 0;
}

.sp-connector__name {
    margin: 0;
    font-size: var(--sp-text-md);
    font-weight: var(--sp-font-semibold);
    line-height: var(--sp-leading-snug);
    color: var(--sp-text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-connector__kind {
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    letter-spacing: var(--sp-tracking-wide);
    text-transform: uppercase;
    color: var(--sp-text-tertiary);
}

.sp-connector__status { justify-self: end; white-space: nowrap; }

.sp-connector__about {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-connector__blurb {
    margin: 0;
    font-size: var(--sp-text-sm);
    line-height: var(--sp-leading-relaxed);
    color: var(--sp-text-secondary);
}

.sp-connector__uses {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-connector__use {
    padding: var(--sp-space-05) var(--sp-space-2);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface-alt);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
}

.sp-connector__facts {
    display: grid;
    gap: var(--sp-space-1);
    margin: 0;
    padding: var(--sp-space-3);
    border-radius: var(--sp-corners-inner-sm);
    background: var(--sp-bg-surface-alt);
    font-size: var(--sp-text-xs);
}

.sp-connector__facts[hidden] { display: none; }

.sp-connector__fact {
    display: grid;
    grid-template-columns: 4.5rem minmax(0, 1fr);
    column-gap: var(--sp-space-2);
}

.sp-connector__fact dt { color: var(--sp-text-tertiary); }

.sp-connector__fact dd {
    margin: 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--sp-text-primary);
}

.sp-connector__note {
    margin: 0;
    padding: var(--sp-space-2) var(--sp-space-3);
    border-radius: var(--sp-corners-inner-sm);
    background: var(--sp-warning-dim);
    color: var(--sp-warning-strong);
    font-size: var(--sp-text-xs);
}

.sp-connector__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-2);
    margin-top: auto;
    padding-top: var(--sp-space-2);
}

.sp-connector__actions:empty { display: none; }

}

@layer components {

/* The share bar is a proportion of the busiest entity on the context, so the
   dominant one reads at a glance rather than being inferred from the counts. */
.sp-col-share {
    width: 8rem;
    min-width: 6rem;
}

.sp-p-context-detail__bar {
    display: block;
    block-size: var(--sp-space-2);
    inline-size: var(--sp-share);
    min-inline-size: 2px;
    border-radius: var(--sp-corners-sm);
    background: var(--sp-accent-fill);
}

}

@layer components {

/* A title is a whole first prompt when nothing better was recorded: one
   line, with the rest readable on hover, or it takes the row to 157px. */
.sp-p-contexts__title {
    display: inline-block;
    max-inline-size: 26rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

/* One line of chips: the busiest model or two plus a +N chip, never a
   wrapping cloud of every model a person touched. The cell stays a table
   cell — flex on a <td> pulls it out of the row, so row hover and the
   expanded tint stopped short of these columns. */
.sp-p-contexts__chips {
    white-space: nowrap;
}

.sp-p-contexts__chips > .sp-badge + .sp-badge {
    margin-inline-start: var(--sp-space-1);
}

.sp-p-contexts__table td { white-space: nowrap; }

.sp-p-contexts__table .sp-col-identity     { min-inline-size: 8rem; }
.sp-p-contexts__table .sp-col-conversation { min-inline-size: 14rem; }
.sp-p-contexts__table .sp-col-model        { min-inline-size: 8rem; }
.sp-p-contexts__table .sp-col-client       { min-inline-size: 6rem; }
.sp-p-contexts__table .sp-col-date         { min-inline-size: 7rem; }

.sp-p-contexts__table th.sp-table__cell--num,
.sp-p-contexts__table td.sp-table__cell--num { min-inline-size: 4.5rem; }

@media (max-width: 1200px) {
    .sp-p-contexts__title { max-inline-size: 16rem; }
}

}

@layer components {

/* The reader is a sticky turn rail beside the transcript. The rail is a
   <details> that ships open: on a wide viewport its summary is hidden and it
   reads as a plain sidebar; under 900px the summary appears and the rail
   collapses above the transcript without a line of JS.

   The reader takes the full width of the shell and starts at its left edge.
   It used to be capped at 88rem and centred, which on a wide screen left a
   column of dead space beside the rail while the transcript — the entire
   reason the page is open — was the thing being squeezed. Prose keeps its own
   measure further down, so width here costs legibility nothing. */

.sp-conversation {
    display: grid;
    grid-template-columns: 18rem minmax(0, 1fr);
    gap: var(--sp-space-6);
    align-items: start;
}

.sp-conversation__nav {
    position: sticky;
    top: var(--sp-space-4);
    z-index: var(--sp-z-sticky);
    max-height: calc(100vh - var(--sp-space-8));
    overflow-y: auto;
    scrollbar-width: thin;
    padding: var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
}

.sp-conversation__nav-summary {
    display: none;
    cursor: pointer;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}

.sp-conversation__nav-summary::-webkit-details-marker { display: none; }

.sp-conversation__nav-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-05);
}

.sp-conversation__nav-group {
    margin: var(--sp-space-2) 0 var(--sp-space-1);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-conversation__nav-link {
    display: grid;
    grid-template-columns: 2ch minmax(0, 1fr);
    gap: var(--sp-space-2);
    align-items: baseline;
    padding: var(--sp-space-1) var(--sp-space-2);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    text-decoration: none;
    transition: background var(--sp-duration-fast), color var(--sp-duration-fast);
}

.sp-conversation__nav-link:hover {
    background: var(--sp-bg-surface-raised);
    color: var(--sp-text-primary);
}

.sp-conversation__nav-num {
    font-variant-numeric: tabular-nums;
    color: var(--sp-text-tertiary);
    text-align: right;
}

.sp-conversation__nav-text {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-conversation__body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
    min-width: 0;
}

.sp-conversation__thread {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2) var(--sp-space-3);
    margin-top: var(--sp-space-4);
    padding-top: var(--sp-space-3);
    border-top: 1px dashed var(--sp-border-default);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    scroll-margin-top: var(--sp-space-4);
}

.sp-conversation__thread-name {
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-secondary);
}

.sp-conversation__thread-label {
    flex-basis: 100%;
    color: var(--sp-text-secondary);
    font-style: italic;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-conversation__system {
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    background: var(--sp-bg-surface-alt);
}

.sp-conversation__system-summary {
    cursor: pointer;
    padding: var(--sp-space-2) var(--sp-space-3);
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}

.sp-conversation__system-summary::-webkit-details-marker { display: none; }

.sp-conversation__system .sp-code-block {
    margin: 0 var(--sp-space-3) var(--sp-space-3);
    max-height: 24rem;
}

.sp-conversation__turn {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    padding: var(--sp-space-4);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
    scroll-margin-top: var(--sp-space-4);
}

.sp-conversation__turn:target {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
}

.sp-conversation__turn-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2) var(--sp-space-3);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-conversation__turn-num {
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-accent-text);
}

.sp-conversation__prompt {
    position: relative;
    padding: var(--sp-space-3) var(--sp-space-4);
    background: var(--sp-accent-surface);
    border-inline-start: 3px solid var(--sp-accent-text);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-base);
    line-height: var(--sp-leading-relaxed);
    color: var(--sp-text-primary);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

}

@layer components {

/* Long assistant text and long prompts are clamped to twelve lines by a
   sibling <details>: while it is closed the text beside it is clamped, opening
   it removes the clamp. The details sits after the text via flex order, so it
   reads as a "Show more" at the foot of the block. */

.sp-conversation__step {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-conversation__step--assistant {
    padding: var(--sp-space-3) var(--sp-space-4);
    background: var(--sp-bg-surface-alt);
    border-inline-start: 3px solid var(--sp-section-users);
    border-radius: var(--sp-radius-sm);
}

.sp-conversation__text {
    order: 1;
    margin: 0;
    font-size: var(--sp-text-base);
    line-height: var(--sp-leading-relaxed);
    color: var(--sp-text-primary);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.sp-conversation__more {
    order: 2;
}

.sp-conversation__more:not([open]) + .sp-conversation__text,
.sp-conversation__more:not([open]) + .sp-conversation__prompt-text {
    display: -webkit-box;
    -webkit-line-clamp: 12;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.sp-conversation__more-toggle {
    cursor: pointer;
    list-style: none;
    display: inline-block;
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-medium);
    color: var(--sp-accent-text);
}

.sp-conversation__more-toggle::-webkit-details-marker { display: none; }

.sp-conversation__more-toggle:hover { text-decoration: underline; }

.sp-conversation__more[open] .sp-conversation__more-label,
.sp-conversation__more:not([open]) .sp-conversation__less-label {
    display: none;
}

.sp-conversation__prompt-text {
    order: 1;
    margin: 0;
}

.sp-conversation__tool {
    background: var(--sp-bg-surface-raised);
    border: 1px solid var(--sp-border-subtle);
    border-inline-start: 3px solid var(--sp-warning);
    border-radius: var(--sp-radius-sm);
    overflow: hidden;
}

.sp-conversation__tool-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    cursor: pointer;
    list-style: none;
    padding: var(--sp-space-15) var(--sp-space-3);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    transition: background var(--sp-duration-fast);
}

.sp-conversation__tool-summary:hover { background: var(--sp-bg-surface-overlay); }

.sp-conversation__tool-summary::-webkit-details-marker { display: none; }

.sp-conversation__tool-chevron {
    display: inline-block;
    color: var(--sp-warning-strong);
    font-size: var(--sp-text-sm);
    line-height: 1;
    transition: transform var(--sp-duration-fast);
}

.sp-conversation__tool[open] .sp-conversation__tool-chevron { transform: rotate(90deg); }

.sp-conversation__tool[open] .sp-conversation__tool-summary {
    border-bottom: 1px solid var(--sp-border-subtle);
}

.sp-conversation__tool-name {
    font-family: var(--sp-font-mono);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}


.sp-conversation__tool-body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    padding: var(--sp-space-3);
}

.sp-conversation__tool-part > summary {
    cursor: pointer;
    margin-bottom: var(--sp-space-1);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}

.sp-conversation__tool-part .sp-code-block { max-height: 20rem; }

.sp-conversation__tool-artifact {
    margin: 0;
    font-size: var(--sp-text-xs);
}

.sp-conversation__meta {
    order: 3;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-conversation__meta-model {
    font-family: var(--sp-font-mono);
    color: var(--sp-text-secondary);
}

.sp-conversation__meta-sep { color: var(--sp-border-default); }

.sp-conversation__meta-status--error {
    color: var(--sp-danger-strong);
    font-weight: var(--sp-font-semibold);
}

.sp-conversation__meta-link {
    color: var(--sp-text-tertiary);
    text-decoration: none;
    border: 1px solid var(--sp-border-subtle);
}

.sp-conversation__meta-link:hover {
    color: var(--sp-accent-text);
    border-color: var(--sp-accent);
}

.sp-conversation__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1) var(--sp-space-3);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
}

.sp-conversation__chip {
    font-family: var(--sp-font-mono);
    color: var(--sp-text-secondary);
}

.sp-conversation__chip-count {
    margin-inline-start: var(--sp-space-1);
    color: var(--sp-text-tertiary);
}

}

@layer components {

.sp-conversation__side {
    margin-top: var(--sp-space-2);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
    scroll-margin-top: var(--sp-space-4);
}

.sp-conversation__side-summary {
    cursor: pointer;
    padding: var(--sp-space-3) var(--sp-space-4);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}

.sp-conversation__side-summary::-webkit-details-marker { display: none; }

.sp-conversation__side-note {
    margin-inline-start: var(--sp-space-2);
    font-weight: var(--sp-font-normal);
    color: var(--sp-text-tertiary);
}

.sp-conversation__side .sp-table {
    border: none;
    box-shadow: none;
    border-radius: 0;
}

.sp-conversation__redaction {
    margin: 0 0 var(--sp-space-3);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-conversation__ids {
    margin: var(--sp-space-2) 0 var(--sp-space-4);
    font-size: var(--sp-text-xs);
}

.sp-conversation__ids-summary {
    cursor: pointer;
    color: var(--sp-text-tertiary);
}

.sp-conversation__ids .sp-kv-list {
    margin-top: var(--sp-space-2);
    padding: var(--sp-space-3);
    background: var(--sp-bg-surface-alt);
    border-radius: var(--sp-radius-sm);
}

.sp-conversation__ids .sp-code-inline {
    user-select: all;
    font-family: var(--sp-font-mono);
}

.sp-conversation__facts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2) var(--sp-space-3);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-conversation__facts a { color: var(--sp-text-primary); }

.sp-conversation__facts-sep { color: var(--sp-border-default); }

@media (max-width: 900px) {
    .sp-conversation {
        grid-template-columns: minmax(0, 1fr);
    }

    .sp-conversation__nav {
        position: static;
        max-height: none;
    }

    .sp-conversation__nav-summary {
        display: block;
    }

    .sp-conversation__nav[open] .sp-conversation__nav-summary {
        margin-bottom: var(--sp-space-2);
    }

    .sp-conversation__nav-list {
        max-height: 40vh;
        overflow-y: auto;
    }
}

@media print {
    .sp-conversation { display: block; }
    .sp-conversation__nav { display: none; }
    .sp-conversation__turn { break-inside: avoid; box-shadow: none; }
    .sp-conversation__more { display: none; }
    .sp-conversation__more:not([open]) + .sp-conversation__text,
    .sp-conversation__more:not([open]) + .sp-conversation__prompt-text {
        display: block;
        overflow: visible;
    }
    .sp-conversation__tool[open] .sp-code-block { max-height: none; overflow: visible; }
}

}

@layer components {
.sp-conversation__nav-heading {
    display: flex;
    justify-content: space-between;
    gap: var(--sp-space-2);
    padding: var(--sp-space-2);
    margin-block-end: var(--sp-space-3);
    font-size: var(--sp-text-sm);
    font-weight: 600;
}
.sp-conversation__nav-heading span { color: var(--sp-text-tertiary); font-weight: 400; }
.sp-conversation__nav-link { padding-block: var(--sp-space-3); }
.sp-conversation__nav-text { white-space: normal; line-height: 1.5; }
.sp-conversation__turn { padding: var(--sp-space-5); gap: var(--sp-space-5); box-shadow: none; }
.sp-conversation__turn-head {
    padding-block-end: var(--sp-space-3);
    border-block-end: 1px solid var(--sp-border-subtle);
}
.sp-conversation__prompt {
    white-space: normal;
    border-inline-start: 0;
    background: var(--sp-bg-surface-alt);
    padding: var(--sp-space-4);
}
.sp-conversation__prompt-text { white-space: pre-wrap; }
.sp-conversation__step--assistant {
    border-inline-start: 0;
    background: transparent;
    padding: 0 var(--sp-space-4);
}
.sp-conversation__speaker {
    font-size: var(--sp-text-xs);
    font-weight: 600;
    color: var(--sp-text-secondary);
    line-height: 1.5;
}
.sp-conversation__text,
.sp-conversation__prompt-text { max-inline-size: 78ch; line-height: 1.75; }
.sp-conversation__activity { margin-inline-start: auto; max-inline-size: 100%; }
.sp-conversation__activity > summary,
.sp-conversation__request > summary {
    cursor: pointer;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-xs);
}
.sp-conversation__chips { padding-block-start: var(--sp-space-3); }
.sp-conversation__chip {
    padding: var(--sp-space-1) var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    overflow-wrap: anywhere;
}
.sp-conversation__tool { border-inline-start: 1px solid var(--sp-border-subtle); }
.sp-conversation__tool-summary { padding: var(--sp-space-3) var(--sp-space-4); }
.sp-conversation__tool-name { overflow-wrap: anywhere; min-inline-size: 0; }
.sp-conversation__tool-kind {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}
.sp-conversation__request { order: 3; margin-block-start: var(--sp-space-2); }
.sp-conversation__request[open] > summary { margin-block-end: var(--sp-space-3); }
.sp-conversation__meta { margin: 0; line-height: 1.6; }
.sp-conversation__tool-body { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
.sp-conversation__tool-part { min-inline-size: 0; }
.sp-conversation__system-summary { text-transform: none; letter-spacing: normal; padding: var(--sp-space-3); }
}

@layer responsive {
@media (max-width: 40rem) {
    .sp-conversation__turn { padding: var(--sp-space-3); }
    .sp-conversation__step--assistant { padding-inline: var(--sp-space-1); }
    .sp-conversation__tool-body { grid-template-columns: minmax(0, 1fr); }
    .sp-conversation__activity { margin-inline-start: 0; inline-size: 100%; }
}
}

@layer components {

/* The stats above the transcript are one-line facts, so they are a strip and
   not a grid of tiles. Six KPI tiles cost roughly a screen-height of vertical
   space directly above the thing the page exists to show. */

.sp-conversation-facts {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2) var(--sp-space-5);
    margin: 0 0 var(--sp-density-section);
    padding: var(--sp-space-3) var(--sp-space-4);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    font-size: var(--sp-text-sm);
    font-variant-numeric: tabular-nums;
}

.sp-conversation-facts__item {
    display: flex;
    align-items: baseline;
    gap: var(--sp-space-2);
    min-width: 0;
}

.sp-conversation-facts__item dt {
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}

.sp-conversation-facts__item dd {
    margin: 0;
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}

.sp-conversation-facts__item--err dd {
    color: var(--sp-danger-strong);
}

.sp-conversation__toolbar {
    display: flex;
    justify-content: flex-end;
    gap: var(--sp-space-2);
}

/* Prose keeps a measure whatever the transcript column is given; payloads,
   tables and tool output take the whole width, which is the point of letting
   the reader bleed to the shell edge in the first place. */

.sp-conversation__prompt-text,
.sp-conversation__text {
    max-inline-size: 78ch;
}

}

@layer responsive {

@media (max-width: 900px) {
    .sp-conversation-facts {
        gap: var(--sp-space-2) var(--sp-space-4);
    }
}

}

@layer components {

[data-section="demo-skills"] .sp-shell__main > .sp-timeseries {
    margin-block-end: var(--sp-space-6);
}

}

@layer components {

/* The device-link and device-code pages are the only console screens a user
   meets outside the shell, so they borrow the sign-in page's light ground and
   nothing else: one centred card, the wordmark at reading size, and a single
   pair of actions. The card is width-capped here because these pages have no
   sidebar to constrain it. */

.sp-device-page {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    margin: 0;
    padding: var(--sp-space-6);
    background: linear-gradient(180deg, var(--sp-bg-canvas) 0%, var(--sp-bg-base) 100%);
    color: var(--sp-text-primary);
    font-family: var(--sp-font-body);
}

.sp-device-card {
    width: 100%;
    max-width: 30rem;
    padding: var(--sp-space-6);
}

.sp-device-card__brand {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-4);
    padding-bottom: var(--sp-space-4);
    border-bottom: 1px solid var(--sp-border-subtle);
    margin-bottom: var(--sp-space-5);
}

.sp-device-card__logo {
    display: block;
    width: auto;
    height: 1.5rem;
}

.sp-device-card__eyebrow {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
}

.sp-device-card__title {
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-xl);
    font-weight: 700;
    letter-spacing: -0.01em;
}

.sp-device-card__lede {
    margin: 0 0 var(--sp-space-5);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    line-height: 1.55;
}

.sp-device-facts {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: var(--sp-space-2) var(--sp-space-4);
    margin: 0 0 var(--sp-space-5);
    padding: var(--sp-space-4);
    background: var(--sp-bg-surface-alt);
    border-radius: var(--sp-corners-sm);
    font-size: var(--sp-text-sm);
}

.sp-device-facts__key {
    margin: 0;
    color: var(--sp-text-tertiary);
}

.sp-device-facts__value {
    margin: 0;
    color: var(--sp-text-primary);
    font-weight: 600;
    overflow-wrap: anywhere;
}

.sp-device-note {
    margin: 0 0 var(--sp-space-5);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    line-height: 1.6;
}

.sp-device-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--sp-space-3);
}

.sp-device-actions__form {
    display: block;
    margin: 0;
}

.sp-device-actions .sp-btn {
    width: 100%;
}

.sp-device-footnote {
    margin: var(--sp-space-5) 0 0;
    padding-top: var(--sp-space-4);
    border-top: 1px solid var(--sp-border-subtle);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    text-align: center;
}

@media (max-width: 30rem) {
    .sp-device-actions {
        grid-template-columns: 1fr;
    }
}

}

@layer components {

.sp-p-devices__estate {
    min-inline-size: 0;
    padding: var(--sp-space-5);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
}

/* Why: the bars are neutral. Brand red is for branding and interactive
   things, and a rollout chart has nothing to click; the one build worth
   noticing is the newest, and it is the only one drawn in colour. */
.sp-p-devices__versions {
    display: grid;
    gap: var(--sp-space-3);
    margin: var(--sp-space-4) 0 0;
    padding: 0;
    list-style: none;
}

.sp-p-devices__version {
    display: grid;
    grid-template-columns: 8rem minmax(0, 1fr) 3rem;
    align-items: center;
    gap: var(--sp-space-3);
    padding-block: var(--sp-space-2);
    border-block-end: 1px solid var(--sp-border-subtle);
}

.sp-p-devices__version-label {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-xs);
    flex-wrap: wrap;
    overflow-wrap: anywhere;
    min-inline-size: 0;
}

.sp-p-devices__version-count {
    text-align: end;
    color: var(--sp-text-primary);
    font-size: var(--sp-text-sm);
}

/* Why: the SVG stretches to the column, so a corner radius on the rect
   stretches with it. Rounding the viewport instead keeps the ends crisp. */
.sp-p-devices__bar {
    display: block;
    inline-size: 100%;
    block-size: var(--sp-space-3);
    clip-path: inset(0 round var(--sp-radius-sm));
}

.sp-p-devices__bar-track {
    fill: var(--sp-bg-tertiary);
}

.sp-p-devices__bar-fill {
    fill: var(--sp-text-tertiary);
}

.sp-p-devices__version.is-latest .sp-p-devices__bar-fill {
    fill: var(--sp-success);
}

.sp-p-devices__summary,
.sp-p-devices__sessions {
    display: block;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    white-space: normal;
}

.sp-col-items {
    min-inline-size: 12rem;
    max-inline-size: 22rem;
}

[data-section="devices"] .sp-table__el--nested {
    width: 100%;
    margin: 0;
    background: transparent;
    border: none;
}

[data-section="devices"] .sp-table__el--nested th {
    background: transparent;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: var(--sp-space-2) var(--sp-space-4);
    border-bottom: 1px solid var(--sp-border-subtle);
}

[data-section="devices"] .sp-table__el--nested td {
    padding: var(--sp-space-2) var(--sp-space-4);
    border-bottom: 1px dashed var(--sp-border-subtle);
}

.sp-p-devices__os {
    margin-inline-start: var(--sp-space-2);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}

.sp-p-devices__expiry {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    margin-inline-end: var(--sp-space-2);
}

.sp-p-devices__expiry .sp-search-input {
    inline-size: 10rem;
}

.sp-col-host,
.sp-col-token,
.sp-col-user {
    min-inline-size: 11rem;
    white-space: nowrap;
}

.sp-col-fingerprint {
    max-inline-size: 14rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-col-status,
.sp-col-version {
    inline-size: 1%;
    white-space: nowrap;
}

/* Why: scoped to this page rather than changed in the shared cell. Three of
   the four tabs carry two date columns, and the shared 11rem gives a quarter
   of the table to timestamps that are sixteen characters wide. */
[data-section="devices"] .sp-table__cell--date {
    inline-size: 8.5rem;
}

/* Why: the sort link is inline, so on a wide column it occupies the left of
   its header and a click at the header's centre lands on padding and does
   nothing. Filling the header makes the whole cell the control it looks like. */
[data-section="devices"] .sp-table__sort {
    display: block;
}

}

@layer responsive {
    @media (max-width: 40rem) {
        .sp-p-devices__version {
            grid-template-columns: minmax(0, 1fr) 3rem;
        }

        .sp-p-devices__version-count {
            grid-column: 2;
            grid-row: 1;
        }

        .sp-p-devices__bar {
            grid-column: 1 / -1;
            grid-row: 2;
        }
    }
}

[data-section="devices"] .sp-table__detail-inner {
    padding-left: var(--sp-space-8);
}

@layer components {

.sp-entity-access {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-5);
    scroll-margin-top: var(--sp-space-6);
}

.sp-entity-access__headline {
    font-size: var(--sp-text-base);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}

.sp-entity-access__headline--nobody {
    padding: var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    color: var(--sp-danger-strong);
    background: var(--sp-danger-dim);
}

.sp-entity-access__drift {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    padding: var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    box-shadow: var(--sp-shadow-card), inset 2px 0 0 var(--sp-warning);
}

.sp-entity-access__drift-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
}

.sp-entity-access__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-2);
}

.sp-entity-access__band {
    margin-top: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    text-transform: capitalize;
    color: var(--sp-text-secondary);
}

.sp-entity-access__rules td {
    vertical-align: top;
}

.sp-entity-access__add,
.sp-entity-access__why {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--sp-space-2);
    padding: var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface-alt);
}

.sp-entity-access__field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-entity-access__field[hidden] {
    display: none;
}

.sp-entity-access__field--wide {
    flex: 1 1 16rem;
}

.sp-access-review__lines td {
    vertical-align: top;
}

.sp-access-why {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-access-why__verdict {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2);
}

.sp-access-why__bands td {
    vertical-align: top;
}

.sp-access-review__row {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    padding: var(--sp-space-3);
    margin-bottom: var(--sp-space-3);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    box-shadow: var(--sp-shadow-card);
}

.sp-access-review__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2);
}

.sp-access-review__kept {
    margin-block: var(--sp-space-3);
}

}

@layer components {

/* An agent page lays its definition, remote execution and recent runs in one column. */

.sp-farm-agent {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
}

.sp-farm-agent__meta {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    margin-right: var(--sp-space-3);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-farm-agent__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr));
    gap: var(--sp-space-4);
}

.sp-farm-agent__card {
    min-width: 0;
}

.sp-farm-agent__label {
    margin: var(--sp-space-3) 0 var(--sp-space-1);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    color: var(--sp-text-tertiary);
}

.sp-farm-agent__lede {
    margin: var(--sp-space-2) 0 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

/* The entry prompt keeps its line breaks but never widens the card. */
.sp-farm-agent__prompt {
    margin: 0 0 var(--sp-space-3);
    padding: var(--sp-space-3);
    max-height: 16rem;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    background: var(--sp-bg-surface-alt);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
}

.sp-farm-agent__tool {
    display: inline-block;
    margin: 0 var(--sp-space-1) var(--sp-space-1) 0;
    padding: 0 var(--sp-space-1);
    background: var(--sp-bg-surface-alt);
    border-radius: var(--sp-radius-sm);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
}

.sp-farm-agent__matrix {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 16rem), 1fr));
    gap: var(--sp-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-farm-agent__case {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-2) var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
}

.sp-farm-agent__case-id {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-sm);
}

.sp-farm-agent__score {
    font-variant-numeric: tabular-nums;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

/* The launch dialog is wider than the default so a long prompt stays readable. */
.sp-farm-launch {
    max-width: min(40rem, 92vw);
}

.sp-farm-launch textarea {
    resize: vertical;
    font-family: var(--sp-font-mono);
}

.sp-farm-launch select {
    font: inherit;
    font-weight: 400;
    padding: var(--sp-space-2) var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    color: var(--sp-text-primary);
}

.sp-farm-launch__row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    gap: var(--sp-space-3);
}

.sp-farm-launch__count {
    margin: calc(-1 * var(--sp-space-2)) 0 0;
    text-align: right;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-farm-launch__count.is-over {
    color: var(--sp-danger-strong);
}

}

@layer components {

/* The evals pages: KPI strip, case matrix, trends, suite list, one gap apart. */

.sp-farm-evals {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
}

.sp-farm-evals__filters,
.sp-farm-evals__run {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0;
}

.sp-farm-evals__section {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-farm-evals__title {
    margin: 0;
    font-size: var(--sp-text-md);
}

.sp-farm-evals__lede {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-farm-evals__trends {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--sp-space-3);
}

.sp-farm-evals__last {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    color: inherit;
    text-decoration: none;
}

.sp-farm-evals__spark {
    width: 7rem;
}

/* The judge score chip, toned by the same 80 / 50 bands as the AI score dot. */
.sp-farm-evals__score {
    display: inline-block;
    min-width: 2.25rem;
    padding: 0 var(--sp-space-1);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-xs);
    font-variant-numeric: tabular-nums;
    text-align: center;
    border: 1px solid var(--sp-border-subtle);
}

.sp-farm-evals__score--ok {
    color: var(--sp-success-strong);
    background: var(--sp-success-dim);
}

.sp-farm-evals__score--warn {
    color: var(--sp-warning-strong);
    background: var(--sp-warning-dim);
}

.sp-farm-evals__score--err {
    color: var(--sp-danger-strong);
    background: var(--sp-danger-dim);
}

.sp-farm-evals__score--muted {
    color: var(--sp-text-tertiary);
}

/* Case matrix: rows are suite › case, columns are agents. */
.sp-farm-matrix__agent,
.sp-farm-matrix__slot {
    text-align: center;
}

.sp-farm-matrix__case {
    font-weight: normal;
    text-align: start;
    white-space: nowrap;
}

.sp-farm-matrix__cell {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    color: inherit;
    text-decoration: none;
}

.sp-farm-matrix__glyph {
    font-weight: 600;
}

.sp-farm-matrix__cell--ok .sp-farm-matrix__glyph {
    color: var(--sp-success-strong);
}

.sp-farm-matrix__cell--warn .sp-farm-matrix__glyph {
    color: var(--sp-warning-strong);
}

.sp-farm-matrix__cell--err .sp-farm-matrix__glyph {
    color: var(--sp-danger-strong);
}

.sp-farm-matrix__none {
    color: var(--sp-text-tertiary);
}

/* Eval run page: header facts, then expandable per-case rows. */
.sp-farm-eval-run__meta {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
    gap: var(--sp-space-3);
    margin: 0;
}

.sp-farm-eval-run__meta dt {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-farm-eval-run__meta dd {
    margin: 0;
}

.sp-farm-eval-run__assertions {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-farm-eval-run__assertion {
    display: grid;
    grid-template-columns: auto minmax(8rem, auto) 1fr;
    align-items: baseline;
    gap: var(--sp-space-2);
}

.sp-farm-eval-run__kind {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
}

.sp-farm-eval-run__detail {
    color: var(--sp-text-secondary);
    overflow-wrap: anywhere;
}

.sp-farm-eval-run__judge {
    display: flex;
    align-items: baseline;
    gap: var(--sp-space-2);
    margin-top: var(--sp-space-3);
}

.sp-farm-eval-run__rationale {
    margin: 0;
}

}

@layer components {

/* The farms overview: the live KPI strip and running board above a grid of
   farm cards. A farm page shares the one-column stack. */

.sp-farm-overview,
.sp-farm-detail {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
}

.sp-farm-overview__kpis,
.sp-farm-overview__running,
.sp-farm-overview__farms {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-farm-overview__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
    gap: var(--sp-space-3);
}

/* The Cancel form sits inline in its table cell. */
.sp-farm-run-row__cancel { display: inline; }

.sp-farm-card { min-inline-size: 0; }

.sp-farm-card__body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-farm-card__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-2);
}

.sp-farm-card__title {
    margin: 0;
    font-size: var(--sp-text-md);
    font-weight: var(--sp-font-weight-semibold);
    overflow-wrap: anywhere;
}

.sp-farm-card__desc {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-farm-card__facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: var(--sp-space-1) var(--sp-space-3);
    margin: 0;
    font-size: var(--sp-text-sm);
}

.sp-farm-card__term { color: var(--sp-text-tertiary); }

.sp-farm-card__value {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

}

@layer components {

/* The by-person leaderboard: share-of-runs bar and trigger split per person. */

.sp-farm-people {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
}

.sp-farm-people__row:hover td {
    background: var(--sp-accent-dim);
}

.sp-farm-people__name {
    font-weight: 600;
    text-decoration: none;
}

.sp-farm-people__name:hover {
    text-decoration: underline;
}

.sp-farm-people__runs {
    white-space: nowrap;
}

.sp-farm-people__share {
    display: inline-block;
    inline-size: 5rem;
    block-size: 0.5rem;
    margin-inline-end: var(--sp-space-2);
    vertical-align: middle;
    border-radius: var(--sp-radius-sm);
    background:
        linear-gradient(
            to right,
            var(--sp-accent) 0,
            var(--sp-accent) var(--sp-share),
            color-mix(in oklch, var(--sp-warm-900) 6%, transparent) var(--sp-share)
        );
}

.sp-farm-people__num {
    font-variant-numeric: tabular-nums;
}

.sp-farm-people__num--err {
    color: var(--sp-danger);
}

.sp-farm-people__pct {
    margin-inline-start: var(--sp-space-1);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-farm-people__agent {
    font-size: var(--sp-text-xs);
}

.sp-farm-people__split {
    display: inline-flex;
    inline-size: 5rem;
    block-size: 0.5rem;
    overflow: hidden;
    vertical-align: middle;
    border-radius: var(--sp-radius-sm);
    background: color-mix(in oklch, var(--sp-warm-900) 6%, transparent);
}

.sp-farm-people__seg {
    inline-size: var(--sp-share);
}

.sp-farm-people__seg--dashboard {
    background: var(--sp-info);
}

.sp-farm-people__seg--api {
    background: var(--sp-accent);
}

.sp-farm-people__seg--eval {
    background: var(--sp-text-tertiary);
}

.sp-farm-people__legend {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-farm-people__key {
    display: inline-block;
    inline-size: 0.625rem;
    block-size: 0.625rem;
    border-radius: var(--sp-radius-sm);
}

}

@layer components {

/* A run page holds the header, KPI strip and the tabbed views in one column. */
.sp-farm-run {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-4);
}

.sp-farm-run__inline-form { display: inline; }

.sp-farm-run__ids {
    padding: var(--sp-space-2) var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
}

.sp-farm-run__ids-summary {
    cursor: pointer;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-farm-run__toolbar {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin-block: var(--sp-space-3);
}

.sp-farm-run__follow {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    margin-inline-end: auto;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

/* The transcript reads as prose: the prompt, each assistant turn, then the result. */
.sp-farm-run__transcript {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
    margin-top: var(--sp-space-3);
    max-inline-size: 72ch;
}

.sp-farm-run__turn {
    padding: var(--sp-space-3) var(--sp-space-4);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
}

.sp-farm-run__turn--prompt { background: var(--sp-bg-surface-alt); }
.sp-farm-run__turn--result { border-inline-start: 3px solid var(--sp-success); }
.sp-farm-run__turn--error { border-inline-start: 3px solid var(--sp-danger); }

.sp-farm-run__turn-head {
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-weight-semibold);
}

.sp-farm-run__muted {
    font-weight: var(--sp-font-weight-regular);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-farm-run__prose {
    margin: 0;
    white-space: pre-wrap;
    line-height: var(--sp-leading-relaxed);
}

.sp-farm-run__diff-stats {
    display: flex;
    gap: var(--sp-space-2);
    margin-block: var(--sp-space-3);
}

/* Timeline strip: one short SVG at full width, lanes drawn in viewBox units. */
.sp-farm-run__strip {
    margin: var(--sp-space-3) 0 0;
    padding: var(--sp-space-3) var(--sp-space-4);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
}

.sp-farm-run__legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-3);
    margin-bottom: var(--sp-space-2);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
}

.sp-farm-run__key {
    display: inline-block;
    inline-size: 10px;
    block-size: 10px;
    border-radius: var(--sp-radius-xs);
    vertical-align: middle;
}

.sp-farm-run__key--assistant { background: var(--sp-accent); }
.sp-farm-run__key--tool { background: var(--sp-success); }
.sp-farm-run__key--err { background: var(--sp-danger); }
.sp-farm-run__key--open { background: var(--sp-info); }
.sp-farm-run__key--tick { background: var(--sp-warning); }

.sp-farm-run__svg {
    display: block;
    inline-size: 100%;
    block-size: 56px;
    background: var(--sp-bg-surface-alt);
    border-radius: var(--sp-radius-xs);
}

.sp-farm-run__grid line {
    stroke: var(--sp-border-subtle);
    stroke-width: 1;
}

.sp-farm-run__mark {
    cursor: pointer;
    transition: opacity var(--sp-duration-fast) var(--sp-ease-in-out);
}

.sp-farm-run__mark:hover { opacity: 0.7; }
.sp-farm-run__mark--assistant { fill: var(--sp-accent); }
.sp-farm-run__mark--tool.sp-farm-run__mark--ok { fill: var(--sp-success); }
.sp-farm-run__mark--tool.sp-farm-run__mark--err { fill: var(--sp-danger); }
.sp-farm-run__mark--tool.sp-farm-run__mark--open { fill: var(--sp-info); }

.sp-farm-run__tick { fill: var(--sp-warning); }
.sp-farm-run__tick--stderr { fill: var(--sp-text-tertiary); }

.sp-farm-run__axis {
    display: flex;
    justify-content: space-between;
    list-style: none;
    margin: var(--sp-space-1) 0 0;
    padding: 0;
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

}

@layer components {

/* The event rail lists a run's stream-json events in arrival order, tightly spaced. */
.sp-run-events {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-run-event {
    display: grid;
    grid-template-columns: var(--sp-space-6) minmax(0, 1fr);
    gap: var(--sp-space-2);
    padding: var(--sp-space-2) var(--sp-space-3);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    scroll-margin-block: var(--sp-space-6);
}

.sp-run-event:target { border-color: var(--sp-accent); }
.sp-run-event--tool_use { border-inline-start: 3px solid var(--sp-success); }
.sp-run-event--tool_result { margin-inline-start: var(--sp-space-6); }
.sp-run-event--hook { border-inline-start: 3px solid var(--sp-warning); }
.sp-run-event--runner,
.sp-run-event--init { background: var(--sp-bg-surface-alt); }
.sp-run-event--error { border-inline-start: 3px solid var(--sp-danger); }

/* stderr is diagnostic noise next to the transcript, so it reads muted. */
.sp-run-event--stderr {
    background: var(--sp-bg-surface-alt);
    color: var(--sp-text-tertiary);
}

/* The result closes the run, so it is drawn as a card the rail ends on. */
.sp-run-event--result {
    margin-top: var(--sp-space-2);
    padding: var(--sp-space-3) var(--sp-space-4);
    border: 1px solid var(--sp-success);
}

.sp-run-event--result.sp-run-event--error { border-color: var(--sp-danger); }

/* A freshly polled event fades in so the eye catches what arrived. */
.sp-run-event--new { animation: sp-run-event-in var(--sp-duration-slow) var(--sp-ease-in-out); }

@keyframes sp-run-event-in {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: none; }
}

.sp-run-event__glyph {
    font-family: var(--sp-font-mono);
    color: var(--sp-text-tertiary);
    text-align: center;
}

.sp-run-event__main { min-inline-size: 0; }

.sp-run-event__head {
    display: flex;
    align-items: baseline;
    gap: var(--sp-space-2);
    margin: 0;
}

.sp-run-event__title {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-weight-medium);
}

.sp-run-event__offset,
.sp-run-event__pair {
    flex: none;
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-run-event__body {
    margin: var(--sp-space-1) 0 0;
    max-block-size: 32rem;
    overflow: auto;
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    white-space: pre-wrap;
    word-break: break-word;
}

.sp-run-event--assistant_text .sp-run-event__body,
.sp-run-event--result .sp-run-event__body {
    font-family: inherit;
    font-size: var(--sp-text-sm);
    line-height: var(--sp-leading-relaxed);
}

.sp-run-event__fold { margin-top: var(--sp-space-1); }

.sp-run-event__preview {
    cursor: pointer;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

}

@layer components {

/* The runs explorer keeps its filters and table in one column so polling never reflows them. */

.sp-farm-runs {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-3);
}

.sp-farm-runs > .sp-live { align-self: flex-end; }

.sp-farm-runs__table { inline-size: 100%; }

.sp-farm-run-row .sp-link {
    color: var(--sp-accent);
    text-decoration: none;
}

.sp-farm-run-row .sp-link:hover,
.sp-farm-run-row .sp-link:focus-visible { text-decoration: underline; }

/* A live run marks its row with an accent edge that breathes while the
   process runs, so the rows a refresh can still change are visible at a
   glance; reduced motion keeps the edge and drops the breathing. */
.sp-farm-run-row[data-run-status="queued"] > :first-child,
.sp-farm-run-row[data-run-status="preparing"] > :first-child,
.sp-farm-run-row[data-run-status="running"] > :first-child {
    box-shadow: inset 2px 0 0 var(--sp-accent);
}

.sp-farm-run-row[data-run-status="running"] > :first-child {
    animation: sp-farm-run-pulse var(--sp-duration-slower) var(--sp-ease-in-out) infinite;
}

@keyframes sp-farm-run-pulse {
    50% { box-shadow: inset 2px 0 0 color-mix(in oklch, var(--sp-accent) 30%, transparent); }
}

@media (prefers-reduced-motion: reduce) {
    .sp-farm-run-row[data-run-status="running"] > :first-child { animation: none; }
}

}

@layer components {

/* The sync card on a farm page: the commit the last sync recorded beside the
   pinned bundle that ships the farm's marketplace. A farm behind its bundle
   carries a warning bar on its inline start. */

.sp-farm-sync-card { min-inline-size: 0; }

.sp-farm-sync-card--behind {
    border-inline-start: var(--sp-space-1) solid var(--sp-warning);
}

.sp-farm-sync-card__body {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}

.sp-farm-sync-card__head {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-farm-sync-card__title {
    margin: 0;
    font-size: var(--sp-text-md);
    font-weight: var(--sp-font-weight-semibold);
}

.sp-farm-sync-card__message {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-farm-sync-card__error {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-danger);
    overflow-wrap: anywhere;
}

.sp-farm-sync-card__facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: var(--sp-space-1) var(--sp-space-4);
    margin: 0;
    font-size: var(--sp-text-sm);
}

.sp-farm-sync-card__term { color: var(--sp-text-tertiary); }

.sp-farm-sync-card__value {
    margin: 0;
    overflow-wrap: anywhere;
}

.sp-farm-sync-card__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    margin: 0;
}

}

/* /admin/gateway/policies — one card per policy row, each a plain form. */
@layer components {

.sp-gwp {
    margin-block: var(--sp-space-6);
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-gwp__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-space-2) var(--sp-space-4);
    margin-bottom: var(--sp-space-3);
}

.sp-gwp__title { margin: 0; font-size: var(--sp-text-lg); }

.sp-gwp__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-gwp__form { display: grid; gap: var(--sp-space-4); }

.sp-gwp__fieldset {
    margin: 0;
    padding: var(--sp-space-3) var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
}

/* Why: a disabled fieldset is the read-only view; the fields keep their
   values and lose their affordance, which is the honest rendering of "you
   may look". */
.sp-gwp__fieldset:disabled { opacity: 0.8; }

.sp-gwp__windows { display: grid; gap: var(--sp-space-2); }

/* Why: six columns on one line per window so a row reads left to right as
   "who · how long · the ceilings"; on a narrow screen the row stacks and the
   header row, which only labels the columns, is dropped. */
.sp-gwp__window {
    display: grid;
    grid-template-columns: 9rem 11rem repeat(4, minmax(6rem, 1fr));
    gap: var(--sp-space-2);
    align-items: start;
}

.sp-gwp__window--head {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.sp-gwp__period { display: grid; gap: var(--sp-space-1); }

.sp-gwp__custom[hidden] { display: none; }

.sp-gwp__checks {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--sp-space-4);
    margin-bottom: var(--sp-space-3);
}

.sp-gwp__check-group {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-gwp__check-group .sp-form-label { inline-size: 100%; margin: 0; }

.sp-gwp__delete { margin-top: var(--sp-space-3); }

.sp-gwp__summary {
    cursor: pointer;
    font-weight: 600;
}

.sp-gwp--new[open] .sp-gwp__summary { margin-bottom: var(--sp-space-3); }

@media (max-width: 60rem) {
    .sp-gwp__window { grid-template-columns: 1fr 1fr; }
    .sp-gwp__window--head { display: none; }
}

}

@layer components {

.sp-p-gateway__routes,
.sp-p-gateway__dispatch,
.sp-p-gateway__providers {
    table-layout: auto;
}

.sp-p-gateway__routes th:first-child,
.sp-p-gateway__routes td:first-child,
.sp-p-gateway__dispatch th:first-child,
.sp-p-gateway__dispatch td:first-child {
    width: 3rem;
}

/* Why: the ordinal is the dispatch position, so it must stay legible as a
   sequence rather than reflow with the id beside it. */
.sp-p-gateway__routes td:first-child,
.sp-p-gateway__dispatch td:first-child {
    font-variant-numeric: tabular-nums;
    color: var(--sp-text-tertiary);
}

/* Why: the reorder, edit and delete controls sit on one line so the row keeps
   the compact height the density bar measures; without this the four buttons
   wrap and set the height for every other row on the page. */
.sp-p-gateway__row-actions {
    display: inline-flex;
    gap: var(--sp-space-1);
    flex-wrap: nowrap;
    white-space: nowrap;
}

/* Why: the id (or a route's description) sits under the display name as a
   second line, so a row is one name wide instead of name-plus-id wide. */
.sp-p-gateway__sub {
    display: block;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-p-gateway__endpoint {
    max-width: 24rem;
    overflow-wrap: anywhere;
}

/* Why: a provider with no route is priced but unreachable; the dashed edge
   marks it in the table the way the old card's dashed border did. */
.sp-p-gateway__providers tr.is-unreachable td:first-child {
    box-shadow: inset 3px 0 0 var(--sp-border-strong);
}

/* Why: the two restart sentences used to be two full-width banners on every
   visit. A <details> keeps them one line once read. */
.sp-p-gateway__explain {
    margin-block: var(--sp-space-3);
    padding: var(--sp-space-2) var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-p-gateway__explain > summary {
    cursor: pointer;
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-primary);
}

.sp-p-gateway__explain-body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--sp-space-3) var(--sp-space-5);
    margin: var(--sp-space-3) 0 var(--sp-space-1);
    font-size: var(--sp-text-sm);
}

.sp-p-gateway__explain-body dt { font-weight: 500; }

.sp-p-gateway__explain-body dd {
    margin: var(--sp-space-05) 0 0;
    color: var(--sp-text-secondary);
}

/* Why: the expanded provider row is the old card, laid out as facts then a
   nested routes table, inside the table's own detail panel. */
.sp-p-gateway__detail {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--sp-space-2) var(--sp-space-4);
    margin: 0 0 var(--sp-space-3);
    font-size: var(--sp-text-sm);
}

.sp-p-gateway__detail dt {
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--sp-text-tertiary);
}

.sp-p-gateway__detail dd { margin: 0; overflow-wrap: anywhere; }

.sp-p-gateway__models {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-p-gateway__empty {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
}

/* Why: settings and the probe are two short forms; side by side they fill
   the row instead of stacking into a page of whitespace. */
.sp-p-gateway__settings {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr));
    gap: var(--sp-space-5);
}

.sp-p-gateway__probe {
    margin-top: var(--sp-space-3);
}

}

@layer components {

/* The governed-call row: the chain strip that makes the fold lossless, the
   stripe that finds an objection without a filter, and the band that lifts the
   denials and warnings above the log. Split from 20-page-governance.css, which
   carries the page's column budgets and toolbar, to stay under the per-file
   line ceiling. */

/* Why: the row still reads as an ordinary audit row — a filled background would
   make a handful of denials louder than the log they belong to — but a call
   that objected has to be findable while scrolling, with no filter applied. */
.sp-t-decisions__row--attention td:first-child {
    box-shadow: inset 2px 0 0 var(--sp-danger-strong);
}

/* The chain strip: one pill per policy evaluation the row folded in. It is what
   makes the fold lossless, so it never wraps and never grows the row. */
.sp-p-governance__chain {
    white-space: nowrap;
    overflow: hidden;
}

.sp-p-governance__pill {
    display: inline-block;
    padding: 0 var(--sp-space-1);
    margin-inline-end: var(--sp-space-1);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-secondary);
    text-decoration: none;
}

.sp-p-governance__pill:hover { border-color: var(--sp-accent); }
.sp-p-governance__pill--err { border-color: var(--sp-danger-strong); color: var(--sp-danger-strong); }
.sp-p-governance__pill--warn { border-color: var(--sp-warning-strong); color: var(--sp-warning-strong); }
.sp-p-governance__pill--ok { color: var(--sp-text-tertiary); }

.sp-p-governance__pill-more {
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
}

/* Tones for the policy chips. A policy that only ever allowed still earns a
   chip — "this ran and objected to nothing" is a reading too — but it earns a
   muted one. */
.sp-p-governance__stage--err { border-color: var(--sp-danger-strong); }
.sp-p-governance__stage--warn { border-color: var(--sp-warning-strong); }
.sp-p-governance__stage--muted { color: var(--sp-text-tertiary); }

/* Why: the denials and warnings, above the log rather than somewhere inside
   twenty pages of allows. A list and not a second table: it is a pointer into
   the log, and giving it columns would make it compete with the thing it points
   at. */
.sp-p-governance__attention {
    margin-block-end: var(--sp-density-section);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-danger-strong);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-p-governance__attention-head {
    display: flex;
    align-items: baseline;
    gap: var(--sp-space-3);
    margin-block-end: var(--sp-space-2);
}

.sp-p-governance__attention-title {
    margin: 0;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}

.sp-p-governance__attention-count {
    font-weight: 600;
    color: var(--sp-danger-strong);
}

.sp-p-governance__attention-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-p-governance__attention-item {
    display: flex;
    align-items: baseline;
    gap: var(--sp-space-2);
    padding-block: var(--sp-space-05);
    font-size: var(--sp-text-xs);
    border-block-start: 1px solid var(--sp-border-subtle);
}

.sp-p-governance__attention-item:first-child { border-block-start: none; }

.sp-p-governance__attention-who { color: var(--sp-text-secondary); }

/* The reason takes the slack and is the one thing allowed to be clipped: the
   badge, the target and the time are what make the entry findable in the log. */
.sp-p-governance__attention-why {
    flex: 1 1 auto;
    min-inline-size: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--sp-text-tertiary);
}

.sp-p-governance__attention-when {
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

}

/* /admin/governance/quotas — one card per quota window, a meter per subject. */
@layer components {

.sp-quota {
    margin-block: var(--sp-space-6);
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

.sp-quota__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-space-2) var(--sp-space-4);
    margin-bottom: var(--sp-space-3);
}

.sp-quota__title { margin: 0; font-size: var(--sp-text-lg); }

.sp-quota__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-1) var(--sp-space-4);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-quota__table { table-layout: fixed; inline-size: 100%; }

/* Why: the meter is the point of the page — a subject's distance from its
   ceiling at a glance — so it gets the widest column and the fill is a
   custom property the template sets, never an inline width. */
.sp-quota__table th:nth-child(6) { inline-size: 22%; }

.sp-quota__bar {
    position: relative;
    block-size: 0.5rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-tertiary);
    overflow: hidden;
}

.sp-quota__fill {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inline-size: var(--sp-fill, 0%);
    border-radius: inherit;
}

.sp-quota__fill--ok   { background: var(--sp-success); }
.sp-quota__fill--warn { background: var(--sp-warning); }
.sp-quota__fill--err  { background: var(--sp-danger); }

.sp-quota__row--breached td:first-child { color: var(--sp-danger-strong); }

}

@layer components {

/* Why: fixed layout is what keeps these tables inside the viewport. With auto
   layout a single long reason or JSON argument widens its column until the
   card scrolls sideways, and the row grows to two lines. Percentages here are
   a budget: every column has a share and none can take another's. */
.sp-t-decisions,
.sp-t-findings,
.sp-t-hooks,
.sp-t-approvals,
.sp-t-secrets {
    table-layout: fixed;
    inline-size: 100%;
}

.sp-t-decisions td,
.sp-t-findings td,
.sp-t-hooks td,
.sp-t-approvals td,
.sp-t-secrets td {
    block-size: var(--sp-density-row);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Seven columns now that a row is a whole call: the policy and stage columns
   were folded into the chain strip, and the scope column was an em-dash on
   every row this instance has ever written. */
.sp-t-decisions th:nth-child(1) { inline-size: 15%; }
.sp-t-decisions th:nth-child(2) { inline-size: 8%; }
.sp-t-decisions th:nth-child(3) { inline-size: 18%; }
.sp-t-decisions th:nth-child(4) { inline-size: 13%; }
.sp-t-decisions th:nth-child(5) { inline-size: 21%; }
.sp-t-decisions th:nth-child(6) { inline-size: 19%; }
.sp-t-decisions th:nth-child(7) { inline-size: 6%; }

.sp-t-findings th:nth-child(1) { inline-size: 15%; }
.sp-t-findings th:nth-child(2) { inline-size: 13%; }
.sp-t-findings th:nth-child(3) { inline-size: 11%; }
.sp-t-findings th:nth-child(4) { inline-size: 8%; }
.sp-t-findings th:nth-child(5) { inline-size: 9%; }
.sp-t-findings th:nth-child(6) { inline-size: 8%; }
.sp-t-findings th:nth-child(7) { inline-size: 12%; }
.sp-t-findings th:nth-child(8) { inline-size: 15%; }
.sp-t-findings th:nth-child(9) { inline-size: 9%; }

.sp-t-approvals th:nth-child(1) { inline-size: 15%; }
.sp-t-approvals th:nth-child(2) { inline-size: 6%; }
.sp-t-approvals th:nth-child(3) { inline-size: 8%; }
.sp-t-approvals th:nth-child(4) { inline-size: 11%; }
.sp-t-approvals th:nth-child(5) { inline-size: 9%; }
.sp-t-approvals th:nth-child(6) { inline-size: 13%; }
.sp-t-approvals th:nth-child(7) { inline-size: 14%; }
.sp-t-approvals th:nth-child(8) { inline-size: 9%; }
.sp-t-approvals th:nth-child(9) { inline-size: 15%; }

.sp-t-hooks th:nth-child(1) { inline-size: 15%; }
.sp-t-hooks th:nth-child(2) { inline-size: 14%; }
.sp-t-hooks th:nth-child(3) { inline-size: 20%; }
.sp-t-hooks th:nth-child(4) { inline-size: 16%; }
.sp-t-hooks th:nth-child(5) { inline-size: 20%; }
.sp-t-hooks th:nth-child(6) { inline-size: 15%; }

.sp-t-secrets th:nth-child(1) { inline-size: 14%; }
.sp-t-secrets th:nth-child(3) { inline-size: 14%; }
.sp-t-secrets th:nth-child(7) { inline-size: 10%; }

/* Why: the decision buttons must stay reachable, so this one cell keeps its
   overflow visible rather than clipping. Its column is sized to hold all three
   controls; if it ever cannot, that shows up as a measured overflow rather
   than as a button nobody can click. */
.sp-t-approvals .sp-table__cell--actions {
    overflow: visible;
    white-space: nowrap;
}

.sp-p-governance__reason,
.sp-p-approvals__args,
.sp-p-approvals__who {
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-xs);
}

/* Why: the tab strip, the stage counts and the window share one row. Each was
   its own band and the three together pushed the table 130px down the page,
   which is four rows of the log — and the log is what the page is for. */
.sp-p-governance__controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--sp-space-4);
}

/* Why: both children carry a bottom margin sized for standing alone. Side by
   side in one row that margin is measured twice and buys nothing. */
.sp-p-governance__controls > * {
    margin-block: 0;
}

/* Why: the shared band leaves a section-sized gap under itself, which is the
   right default for a page whose next element is a heading. The next element
   here is a control row, so it takes the gap spacing instead. */
[data-section="governance-warnings"] .sp-kpi-grid {
    margin-block-end: var(--sp-density-gap);
}

/* Why: the toolbar's five controls have to share one row with the export
   links, so the selects take their width from the budget rather than from
   their widest option, and the search box stops flexing into the space the
   others need. */
[data-section="governance-warnings"] .sp-toolbar__filter {
    max-inline-size: 11rem;
}

[data-section="governance-warnings"] .sp-toolbar .sp-filter-select {
    min-inline-size: 0;
    max-inline-size: 7rem;
}

[data-section="governance-warnings"] .sp-toolbar__search {
    max-inline-size: 16rem;
}

/* Why: the four chain stages as one line rather than four tiles. The band has
   a height budget and four more tiles broke it; these numbers still have to be
   readable without a click, because "which stage is doing the work" is the
   first question the page answers. */
.sp-p-governance__stages {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-2);
    margin-block: var(--sp-space-1) var(--sp-space-2);
}

.sp-p-governance__stage {
    display: inline-flex;
    align-items: baseline;
    gap: var(--sp-space-2);
    padding: var(--sp-space-05) var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-xs);
    text-decoration: none;
}

.sp-p-governance__stage:hover,
.sp-p-governance__stage.is-active {
    border-color: var(--sp-accent);
    color: var(--sp-text-primary);
}

.sp-p-governance__stage-label {
    white-space: nowrap;
}

.sp-p-governance__stage-count {
    color: var(--sp-text-primary);
    font-weight: 600;
}

.sp-p-governance__ranks {
    margin-block-start: var(--sp-space-8);
}

}

@layer components {

/* Why: the reason field appears only once allow or deny is chosen, inline with
   the select, so the row asks for the why at the moment the decision is made. */
.sp-group-rule {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    justify-content: flex-end;
}

.sp-group-rule__reason {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
}

.sp-group-rule__reason .sp-search-input {
    inline-size: 16rem;
}

.sp-group-rule__reason input[type="date"] {
    inline-size: 10rem;
}

}

@layer components {

.sp-group-cell {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    color: var(--sp-text-primary);
    text-decoration: none;
    white-space: nowrap;
}

.sp-group-cell:hover .sp-group-cell__name {
    text-decoration: underline;
}

.sp-group-cell__name {
    font-weight: 600;
}

.sp-group-member-count {
    display: block;
    font-variant-numeric: tabular-nums;
}

.is-unassigned {
    box-shadow: inset 3px 0 0 0 var(--sp-warning);
}

.sp-group-chips {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
}

.sp-group-chips__chip {
    padding: 0.1rem var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-tertiary);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-xs);
    white-space: nowrap;
}

.sp-share-bar {
    display: inline-block;
    inline-size: 5rem;
    block-size: 0.5rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-tertiary);
    overflow: hidden;
    vertical-align: middle;
}

.sp-share-bar__fill {
    --sp-share-pct: 0%;
    display: block;
    block-size: 100%;
    inline-size: var(--sp-share-pct);
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent-fill);
}

.sp-source-badge {
    margin-inline-end: var(--sp-space-1);
}

.sp-member-actions {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    justify-content: flex-end;
}

.sp-member-actions__label {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    white-space: nowrap;
}

.sp-unassigned-callout {
    margin-block-end: var(--sp-space-6);
    padding: var(--sp-space-4) var(--sp-space-5);
    border-inline-start: 4px solid var(--sp-warning);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-warning);
}

.sp-unassigned-callout__title {
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-primary);
}

.sp-unassigned-callout__body {
    margin: 0;
    max-inline-size: 80ch;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    line-height: 1.6;
}

.sp-group-panel {
    min-inline-size: 0;
    margin-block-end: var(--sp-space-8);
}

.sp-group-panel__note {
    margin-block: 0 var(--sp-space-4);
    max-inline-size: 90ch;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    line-height: 1.6;
}

.sp-rank-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: var(--sp-space-2);
}

.sp-group-rankings {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 30rem), 1fr));
    gap: var(--sp-space-5);
    margin-block-end: var(--sp-space-8);
}

.sp-group-rankings .sp-group-panel {
    margin: 0;
    padding: var(--sp-space-5);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
}

.sp-group-rankings .sp-section__title {
    margin-block-end: var(--sp-space-4);
}

.sp-rank-list__item {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 5rem 3ch;
    align-items: center;
    gap: var(--sp-space-3);
    font-size: var(--sp-text-sm);
    padding-block: var(--sp-space-2);
    border-block-end: 1px solid var(--sp-border-subtle);
}

.sp-rank-list__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--sp-text-secondary);
}

.sp-rank-list__count {
    text-align: end;
    font-variant-numeric: tabular-nums;
    color: var(--sp-text-primary);
}

.sp-access-layer {
    color: var(--sp-text-primary);
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

}

@layer responsive {

@media (max-width: 40rem) {
    .sp-rank-list__item {
        grid-template-columns: minmax(0, 1fr) auto;
    }

    .sp-rank-list__item .sp-share-bar {
        display: none;
    }
}

}

@layer components {

.sp-p-groups__ranges {
    display: inline-flex;
    gap: var(--sp-space-1);
}

.sp-p-groups__remainder {
    border-block-start: 2px solid var(--sp-border-strong);
    background: var(--sp-bg-tertiary);
}

.sp-p-groups__note {
    margin-block: 0 var(--sp-space-3);
    max-inline-size: 70ch;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    line-height: 1.6;
}

.sp-group-panel__label {
    margin-inline-start: var(--sp-space-2);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
}

}

@layer components {

/* Why: the group name is the label every row is found by, so it gets the width
   first and the numeric columns take what they need and no more. Without this
   the browser shared the width evenly across ten columns and truncated every
   primary label to fit two-digit counts. */
.sp-t-groups th:first-child,
.sp-t-groups td:first-child {
    inline-size: 24%;
}

.sp-t-groups .sp-table__cell--num {
    inline-size: 1%;
    white-space: nowrap;
}

}

@layer components {

/* The title column carries the whole first prompt when nothing better was
   recorded; the stacked cell keeps it to one line with the id or snippet
   under it. */
.sp-p-history__table .sp-col-conversation {
    min-inline-size: 16rem;
    max-inline-size: 30rem;
}

/* A cell's max-inline-size is only advisory to the table algorithm, and a
   percentage bound on its child is circular when the cell is itself sized by
   content — so one 160-character opening prompt widened the column until
   Turns, Tokens, Cost and When were pushed off the page. The bound belongs on
   the clipped child, in absolute units. */
.sp-p-history__table .sp-col-conversation > * {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-inline-size: 28rem;
}

/* The row-selection box: as narrow as the checkbox, never stretched. */
.sp-p-history__table .sp-col-select { inline-size: 1.6rem; }

.sp-p-history__table th.sp-table__cell--num,
.sp-p-history__table td.sp-table__cell--num { min-inline-size: 4.5rem; }

}

@layer components {
.sp-visibility-badge {
    display: inline-flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    align-items: center;
}

.sp-visibility-badge--scoped {
    font-size: var(--sp-text-xs);
}

.sp-mkt-card__chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
}

.sp-mkt-audience {
    margin-top: var(--sp-space-8);
}

.sp-mkt-audience__heading {
    margin-bottom: var(--sp-space-1);
}

.sp-audience-matrix-wrap {
    overflow-x: auto;
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
}

.sp-audience-matrix {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--sp-text-sm);
}

.sp-audience-matrix__caption {
    padding: var(--sp-space-2) var(--sp-space-3);
    text-align: left;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-audience-matrix__col {
    padding: var(--sp-space-2) var(--sp-space-3);
    text-align: left;
    white-space: nowrap;
    color: var(--sp-text-secondary);
}

.sp-audience-matrix__subject {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-05);
    padding: var(--sp-space-2) var(--sp-space-3);
    text-align: left;
    white-space: nowrap;
}

.sp-audience-matrix__label {
    color: var(--sp-text-primary);
    font-weight: 600;
}

.sp-audience-matrix__kind {
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--sp-text-tertiary);
}

.sp-audience-matrix__row:hover {
    background: var(--sp-bg-surface-raised);
}

.sp-audience-matrix__cell {
    padding: var(--sp-space-2) var(--sp-space-3);
    border-top: 1px solid var(--sp-border-subtle);
    text-align: center;
}

.sp-audience-matrix__cell.is-allow {
    background: var(--sp-badge-accent-bg);
}

.sp-audience-matrix__cell.is-deny {
    background: var(--sp-bg-surface-raised);
}

.sp-audience-matrix__layer {
    font-size: var(--sp-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.sp-audience-matrix__cell.is-allow .sp-audience-matrix__layer {
    color: var(--sp-success-strong);
}

.sp-audience-matrix__cell.is-deny .sp-audience-matrix__layer {
    color: var(--sp-text-tertiary);
}

}

@layer components {

.sp-p-mcp__rate {
    font-variant-numeric: tabular-nums;
}

.sp-p-mcp__rate--ok {
    color: var(--sp-success-strong);
}

.sp-p-mcp__rate--warn {
    color: var(--sp-warning-strong);
}

.sp-p-mcp__rate--err {
    color: var(--sp-danger-strong);
}

.sp-p-mcp__rate--muted {
    color: var(--sp-text-tertiary);
}

.sp-p-mcp__footnote {
    margin-block-start: var(--sp-space-3);
}

}

/* /admin/system/observability — the declared exporter and one row per signal. */
@layer components {

.sp-obs-inline { display: inline; }

.sp-obs-exporter {
    margin-block: var(--sp-space-3) var(--sp-space-6);
    padding: var(--sp-space-3) var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

/* Why: a collector's refusal is the one line an operator came for; it is
   clipped to the cell with the full text in the title, never wrapped into
   a paragraph that pushes the counters off screen. */
.sp-obs-error {
    display: inline-block;
    max-width: 28ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
    color: var(--sp-danger-strong);
    font-size: var(--sp-text-xs);
    cursor: help;
}

.sp-obs-signals td { vertical-align: top; }

}

@layer components {

/* The live layer on the overview: a freshness indicator in the page header,
   the flip a delta makes when its direction changes, the fade a sparkline
   makes when it is redrawn, and the flash a table cell makes when its text
   changed under a silent refresh. Every one of these is a cue that something
   moved; none of them carries information a reader without motion would
   miss, so the whole file switches off under reduced motion. */

/* The live root is a plain wrapper; the rule exists so the class the client
   keys on is a real class and not an unstyled hook. */
.sp-p-overview__live { display: block; }

.sp-live {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-2xs);
    font-variant-numeric: tabular-nums;
    color: var(--sp-text-secondary);
}

.sp-live__dot {
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-success);
}

.sp-live--loading .sp-live__dot {
    animation: sp-live-pulse var(--sp-duration-slower) var(--sp-ease-in-out) infinite;
}

.sp-live--paused { color: var(--sp-text-tertiary); }
.sp-live--paused .sp-live__dot { background: var(--sp-text-disabled); }

.sp-live--error .sp-live__dot { background: var(--sp-danger); }
.sp-live--auth .sp-live__dot { background: var(--sp-warning); }

.sp-live__text { white-space: nowrap; }

.sp-live__toggle { margin-inline-start: var(--sp-space-1); }

@keyframes sp-live-pulse {
    50% { opacity: 0.25; }
}

.sp-delta.is-flipping {
    animation: sp-delta-flip var(--sp-duration-moderate) var(--sp-ease-out);
}

@keyframes sp-delta-flip {
    from { opacity: 0; transform: translateY(-0.35em); }
}

.sp-kpi__trend.is-updating .sp-spark {
    animation: sp-live-fade var(--sp-duration-normal) var(--sp-ease-out);
}

@keyframes sp-live-fade {
    from { opacity: 0.3; }
}

.sp-u-changed {
    animation: sp-live-flash var(--sp-duration-slower) var(--sp-ease-out);
}

@keyframes sp-live-flash {
    from { background: var(--sp-accent-dim); }
}

.sp-time-range__presets[aria-busy="true"] .sp-time-range__btn { cursor: progress; }

@media (prefers-reduced-motion: reduce) {
    .sp-live--loading .sp-live__dot,
    .sp-delta.is-flipping,
    .sp-kpi__trend.is-updating .sp-spark,
    .sp-u-changed {
        animation: none;
    }
}

}

@layer components {

/* The landing page adds no card of its own: everything on it is a KPI tile, a
   section head, a chart or a table from the system. The window control is
   the shared time-range pill, so the active window reads the same here as on
   every analytics page. What is left is the chart grid, the two-up
   leaderboard row and two one-line notes. */

/* Ten tiles: five to a row on a wide screen, so the strip is two rows and
   the charts still clear the fold. */
.sp-p-overview__kpis {
    grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
}

/* Six charts on one x axis, always three to a row so the six read as two
   bands — volume, models, clients / tokens, work, latency — never six thin
   strips across an ultrawide. They fold to two, then one. The card has a
   fixed height, not a minimum: the live chart draws its SVG at the host's
   pixel height, so a card that grows with its content would grow the SVG,
   which grows the card, without end. */
.sp-p-overview__charts {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--sp-density-gap);
    margin-block-end: var(--sp-density-section);
}

@media (max-width: 80rem) {
    .sp-p-overview__charts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 48rem) {
    .sp-p-overview__charts { grid-template-columns: minmax(0, 1fr); }
}

.sp-p-overview__chart {
    display: flex;
    min-inline-size: 0;
    block-size: 23rem;
    overflow: auto;
    padding: var(--sp-density-tile);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
}

/* Unattributed is a real row with no page behind it, so it reads as a value
   rather than as a link that lost its href. */
.sp-p-overview__unattributed {
    color: var(--sp-text-tertiary);
    font-style: italic;
}

/* Two panels to a row. A dashboard read in one column spends its fold on
   headings; side by side, twice the rows clear it. */

.sp-p-overview__two-up {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(28rem, 1fr));
    gap: var(--sp-density-gap);
    margin-block-end: var(--sp-density-section);
}

.sp-p-overview__two-up > * {
    min-inline-size: 0;
}

.sp-p-overview__board {
    min-inline-size: 0;
}

/* One line, not a bordered notice: the reason a percentage is missing is worth
   a sentence, not a box that costs the fold three table rows. */

.sp-p-overview__note {
    margin-block: 0 var(--sp-space-2);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}

}

@layer components {

.sp-trace-row {
    cursor: pointer;
}

}

@layer components {

/* The latest-conversation card: title and facts on the left, one action on
   the right, so the thing a person opens their profile for is one click away. */
.sp-p-profile__latest-body {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-4);
}

.sp-p-profile__latest-main {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    min-width: 0;
}

.sp-p-profile__latest-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--sp-text-md);
}

.sp-p-profile__latest-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-3);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
}

.sp-p-profile__latest { margin-block: 0 var(--sp-space-4); }

.sp-p-profile__side-note {
    margin-block: var(--sp-space-2) 0;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}

}

@layer components {

.sp-p-profile__more { margin-block: var(--sp-space-6) 0; }

.sp-p-profile__more summary {
    cursor: pointer;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    font-weight: 600;
}

.sp-p-profile__more[open] summary { margin-bottom: var(--sp-space-4); }

.sp-p-profile__more section + section { margin-top: var(--sp-space-5); }

.sp-p-profile__settings { display: block; margin-block: var(--sp-space-5) 0; }

.sp-p-profile__settings-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: var(--sp-space-5);
}

.sp-p-profile__settings input:disabled {
    border-style: dashed;
    color: var(--sp-text-tertiary);
    cursor: not-allowed;
}

.sp-p-profile__avatar-row {
    display: flex;
    align-items: center;
    gap: var(--sp-space-3);
}

.sp-p-profile__avatar-row input { flex: 1; }

.sp-p-profile__avatar {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    inline-size: 2.5rem;
    block-size: 2.5rem;
    overflow: hidden;
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface-raised);
}

.sp-p-profile__avatar img {
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
}

.sp-p-profile__avatar-fallback {
    color: var(--sp-text-tertiary);
    font-weight: 600;
}

.sp-p-profile__danger { margin-block-start: var(--sp-space-6); }

}

@layer components {

.sp-p-projects__col-name {
    min-inline-size: 12rem;
}

/* The description trails the name on the same line, clipped to the room the
   row has left. A flex td was the earlier form and cost the column its
   table-cell layout; an inline-block with a ceiling keeps the row a row. */
.sp-p-projects__sub {
    display: inline-block;
    max-inline-size: 7rem;
    margin-inline-start: var(--sp-space-2);
    overflow: hidden;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    text-overflow: ellipsis;
    white-space: nowrap;
    vertical-align: bottom;
}

/* The listing is twelve columns wide. The name column takes the slack (the
   table's own first-column rule) and every other column sizes to its content,
   so a header is never asked to wrap and a count never drifts away from its
   heading; "Tool success" used to break onto two lines because the numeric
   column's 7ch ceiling was narrower than the words. */
.sp-t-projects th,
.sp-t-projects td {
    padding-inline: var(--sp-space-2);
    white-space: nowrap;
}

.sp-t-projects .sp-table__sort {
    margin-inline: calc(-1 * var(--sp-space-2));
    padding-inline: var(--sp-space-2);
}

.sp-t-projects .sp-table__cell--num,
.sp-t-projects .sp-p-projects__col-mix {
    inline-size: 1%;
}

.sp-t-projects .sp-p-projects__col-mix {
    max-inline-size: none;
}

/* The secondary figure sits on the same line as its number — "1 · 1 active",
   "73% · 15" — in the tertiary colour, so the primary value stays where the
   header put it. */
.sp-p-projects__meta {
    margin-inline-start: var(--sp-space-1);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-normal);
}

.sp-p-projects__meta::before {
    content: "· ";
}

.sp-p-project {
    margin-block-end: var(--sp-space-6);
}
.sp-p-project__note {
    margin: 0;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}
.sp-p-project__usage {
    display: grid;
    gap: var(--sp-space-6);
}
.sp-p-project__split {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--sp-space-6);
}
.sp-p-project__form {
    display: grid;
    gap: var(--sp-space-2);
    max-inline-size: 40rem;
    margin-block-end: var(--sp-space-6);
}
.sp-p-project__form-actions {
    display: flex;
    gap: var(--sp-space-2);
    margin-block-start: var(--sp-space-2);
}

}

@layer responsive {

@media (max-width: 64rem) {
    .sp-p-project__split {
        grid-template-columns: minmax(0, 1fr);
    }
}

}

@layer components {

/* The report is the detail page laid end to end for paper. The facts block is
   the one thing it adds on screen: a definition list a manager can read
   without scrolling, before the tiles restate the numbers with tone. */
.sp-p-report {
    display: grid;
    gap: var(--sp-space-6);
}

.sp-p-report__summary,
.sp-p-report__section {
    display: grid;
    gap: var(--sp-space-3);
    break-inside: avoid;
}

.sp-p-report__facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: var(--sp-space-3) var(--sp-space-6);
    margin: 0;
    padding: var(--sp-space-4) var(--sp-space-5);
    background: var(--sp-bg-surface);
    border-radius: var(--sp-corners-md);
    box-shadow: var(--sp-shadow-card);
}

.sp-p-report__fact dt {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    letter-spacing: var(--sp-tracking-wide);
    text-transform: uppercase;
}

.sp-p-report__fact dd {
    margin: 0;
    color: var(--sp-text-primary);
    font-size: var(--sp-text-sm);
    overflow-wrap: anywhere;
}


/* A report is read, not scanned: a timestamp is printed whole. */
.sp-p-report .sp-table__cell--date {
    inline-size: auto;
    max-inline-size: none;
    white-space: nowrap;
}

.sp-p-report__foot {
    padding-block-start: var(--sp-space-4);
    border-block-start: 1px solid var(--sp-border-subtle);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}

.sp-p-report__foot p {
    margin: 0;
}

}

@layer responsive {

@media print {
    .sp-p-report {
        gap: 6mm;
    }

    .sp-p-report__facts {
        box-shadow: none;
        border: 1px solid #ccc;
    }

    /* A4 is too narrow for two tables side by side at a readable size. */
    .sp-p-report .sp-p-project__split {
        grid-template-columns: minmax(0, 1fr);
    }

    .sp-p-report .sp-section__head {
        break-after: avoid;
    }
}

}

@layer components {

/* The request page's Tool schemas section: the client's tools beside the
   provider's. The two full arrays are one block each; the side-by-side tab is
   one collapsible per tool, with the schemas in two columns so a sanitizer
   rewrite is read as a diff rather than hunted for across two scrolls. */
.sp-p-request-schemas {
    min-width: 0;
}

.sp-p-request-schemas__digests {
    margin-block-end: var(--sp-space-4);
}

.sp-p-request-schemas__json {
    max-height: 32rem;
    overflow: auto;
}

.sp-p-request-schemas__tools {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: var(--sp-space-2);
}

.sp-p-request-schemas__tool {
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}

/* Why: a rewritten tool has to be findable in a list of thirty without
   opening each one; the stripe is the same signal the governance log uses. */
.sp-p-request-schemas__tool--changed {
    box-shadow: inset 2px 0 0 var(--sp-info);
}

.sp-p-request-schemas__tool summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-p-request-schemas__desc {
    flex-basis: 100%;
    font-size: var(--sp-text-xs);
    font-weight: 400;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-p-request-schemas__hits {
    margin: var(--sp-space-2) 0 0;
    padding-inline-start: var(--sp-space-5);
    font-size: var(--sp-text-sm);
    color: var(--sp-warning-strong);
}

.sp-p-request-schemas__pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--sp-space-3);
    margin-block-start: var(--sp-space-2);
}

.sp-p-request-schemas__pair .sp-code-block {
    max-height: 24rem;
    overflow: auto;
}

.sp-p-request-schemas__side {
    margin: 0 0 var(--sp-space-1);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--sp-text-tertiary);
}

}

@layer components {

.sp-requests-section {
    display: block;
    margin-bottom: var(--sp-space-8);
}

.sp-requests-section .sp-section__sub {
    margin: 0 0 var(--sp-space-4);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    max-width: 68ch;
}

.sp-table__el th.sp-col-share {
    width: 12rem;
    min-width: 9rem;
}

.sp-table__el td.sp-col-share {
    display: table-cell;
    white-space: nowrap;
}

.sp-share-bar {
    display: inline-block;
    width: 6.5rem;
    height: 0.5rem;
    margin-right: var(--sp-space-2);
    vertical-align: middle;
    border-radius: var(--sp-radius-sm);
    background:
        linear-gradient(
            to right,
            var(--sp-accent) 0,
            var(--sp-accent) var(--v, 0%),
            color-mix(in oklch, var(--sp-warm-900) 6%, transparent) var(--v, 0%)
        );
}

.sp-share-bar__value {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-breakdown-row:hover td {
    background: var(--sp-accent-dim);
}

.sp-breakdown-row__key {
    text-decoration: none;
}

.sp-breakdown-row__key:hover {
    text-decoration: underline;
}

.sp-breakdown-row--errors .sp-share-bar {
    background:
        linear-gradient(
            to right,
            var(--sp-danger) 0,
            var(--sp-danger) var(--v, 0%),
            color-mix(in oklch, var(--sp-warm-900) 6%, transparent) var(--v, 0%)
        );
}

}

@layer components {

/* Why: the person's name is what says which row this is, so it takes the
   slack. Every other column is sized to its own content and no wider; the
   roles column gets enough for four pills so a platform admin's row does not
   wrap the pills into a second line. */
.sp-p-roles__table .sp-col-roles { width: 22rem; }
.sp-p-roles__table .sp-col-status { width: 6rem; }
.sp-p-roles__table .sp-col-rowactions { width: 14rem; }

.sp-p-roles__pills,
.sp-p-roles__revokes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
}

.sp-p-roles__revokes {
    justify-content: flex-end;
}

/* Why: the role card an operator clicked is the one filter the table is
   under, so the matching pill on every row is the one that reads as pressed. */
.sp-p-roles__pills .sp-badge.is-active {
    outline: 1px solid var(--sp-accent);
    outline-offset: 1px;
}
.sp-p-roles__kind-table .sp-col-access { width: 6rem; }
.sp-p-roles__kind-table .sp-col-default { width: 10rem; }

/* Why: entitlements read as a catalogue per role — a kind is one line when
   the role reaches all of it, and opens to the individual entities. */
.sp-p-roles__groups {
    display: grid;
    gap: var(--sp-space-4);
}

.sp-p-roles__group { min-width: 0; }

.sp-p-roles__kind { min-width: 0; }

.sp-p-roles__group-title {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-sm);
}

.sp-p-roles__group-count {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-p-roles__kinds {
    display: grid;
    gap: var(--sp-space-1);
    margin: 0;
    padding: 0;
    list-style: none;
}

.sp-p-roles__kind-details {
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
}

.sp-p-roles__kind-summary {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-2) var(--sp-space-3);
    cursor: pointer;
}

.sp-p-roles__kind-label { font-weight: 500; }

.sp-p-roles__kind-note {
    flex: 1 1 auto;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}

.sp-p-roles__kind-link { font-size: var(--sp-text-xs); }

.sp-p-roles__kind-table {
    width: 100%;
    border-collapse: collapse;
    font-size: var(--sp-text-xs);
}

.sp-p-roles__kind-table th,
.sp-p-roles__kind-table td {
    padding: var(--sp-space-1) var(--sp-space-3);
    text-align: left;
    border-top: 1px solid var(--sp-border-subtle);
}

.sp-p-roles__kind-table th {
    color: var(--sp-text-tertiary);
    font-weight: 500;
}

.sp-p-roles__error,
.sp-p-roles__toast {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}
.sp-p-roles__field {
    display: grid;
    gap: var(--sp-space-1);
    margin-block: var(--sp-space-3);
}
.sp-p-roles__results {
    display: grid;
    gap: var(--sp-space-1);
    max-block-size: 12rem;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    list-style: none;
}
.sp-p-roles__dialog-actions {
    display: flex;
    gap: var(--sp-space-2);
    justify-content: flex-end;
}

}

@layer components {

/* Service accounts: the credential chips in the listing and the write-only
   secret field on the detail page. */

.sp-p-service-accounts {
  display: grid;
  gap: var(--sp-space-4);
}

.sp-p-service-accounts__attach {
  display: grid;
  gap: var(--sp-space-3);
}

.sp-p-service-accounts__credential {
  display: inline-block;
  margin-inline-end: var(--sp-space-1);
  padding: 0 var(--sp-space-2);
  border: 1px solid var(--sp-border-subtle);
  border-radius: var(--sp-radius-sm);
  font-family: var(--sp-font-mono);
  font-size: var(--sp-text-xs);
}

.sp-p-service-accounts__note {
  color: var(--sp-text-secondary);
  font-size: var(--sp-text-sm);
}

.sp-p-service-accounts__secret {
  font-family: var(--sp-font-mono);
  min-block-size: 6rem;
}

}

@layer components {

/* Floors, never ceilings: a header must be able to draw its own label, which
   is what took this table to eleven clipped headings. Nine columns at these
   widths fit 1440 without the table scrolling sideways. */
.sp-p-sessions__table .sp-col-date         { min-inline-size: 11rem; }
.sp-p-sessions__table .sp-col-conversation { min-inline-size: 16rem; }
.sp-p-sessions__table .sp-col-owner        { min-inline-size: 7rem; }
.sp-p-sessions__table .sp-col-status       { min-inline-size: 6rem; }

/* A cell's max-inline-size is only advisory to the table algorithm, so a
   ceiling set here bounded the painted cell without bounding the column, and
   the difference showed as a dead band between the title and Group. The bound
   belongs on the clipped child, in absolute units — the same correction
   20-page-history.css already carries for the same column. */
.sp-p-sessions__table .sp-col-conversation > * { max-inline-size: 34rem; }

.sp-p-sessions__table th.sp-table__cell--num,
.sp-p-sessions__table td.sp-table__cell--num { min-inline-size: 4.5rem; }

}

@layer components {

.sp-kpi-grid + .sp-toolbar,
[data-page="contexts"] {
    margin-bottom: var(--sp-space-4);
}

[data-page="contexts"] .sp-table__el--nested {
    width: 100%;
    margin: 0;
    background: transparent;
    border: none;
}

[data-page="contexts"] .sp-table__el--nested th {
    background: transparent;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: var(--sp-space-2) var(--sp-space-4);
    border-bottom: 1px solid var(--sp-border-subtle);
}

[data-page="contexts"] .sp-table__el--nested td {
    padding: var(--sp-space-2) var(--sp-space-4);
    border-bottom: 1px dashed var(--sp-border-subtle);
}

}

/* /admin/sync — Code sync: the sources table, the archive cards, a
   participant's per-marketplace cards and the sync history. */
@layer components {

.sp-sync-sources__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
}

.sp-sync-sources__owns {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-sync-pin {
    margin: var(--sp-space-2) 0 0;
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-sunken);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* Why: two cards, export and import, wide enough that the file list under
   export does not wrap into a column of one-word lines. */
.sp-sync-archive {
    grid-template-columns: repeat(auto-fit, minmax(22rem, 1fr));
}

.sp-sync-archive__files {
    margin: 0;
    padding-left: var(--sp-space-5);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-sync-archive__upload {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin-top: auto;
}

/* Why: a participant's page stacks one access-control card per marketplace;
   the title line names the marketplace and links its version history so the
   card below it never has to say which marketplace it is. */
.sp-sync-marketplace {
    margin-block: var(--sp-space-4);
}

.sp-sync-marketplace__title {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-base);
}

.sp-sync-history td:nth-child(4) {
    overflow-wrap: anywhere;
}

.sp-sync-manifest {
    margin-block: var(--sp-space-3);
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

}

@layer components {

.sp-p-trace-detail__timeline {
    margin-block: var(--sp-space-4);
}

/* Timeline strip: one short SVG over the full width. Marks are gateway calls
   in the top lane and hook events / standalone decisions in the bottom lane,
   coloured by outcome — the kind is already in the table beneath. */
.sp-p-trace-detail__strip {
    margin-top: var(--sp-space-3);
    padding: var(--sp-space-3) var(--sp-space-4);
    background: var(--sp-bg-surface);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
}

.sp-p-trace-detail__svg {
    display: block;
    inline-size: 100%;
    block-size: 42px;
    background: var(--sp-bg-surface-alt);
    border-radius: var(--sp-radius-xs);
}

.sp-p-trace-detail__grid line {
    stroke: var(--sp-border-subtle);
    stroke-width: 1;
}

.sp-p-trace-detail__mark {
    fill: var(--sp-success);
    cursor: pointer;
    transition: opacity var(--sp-duration-fast) var(--sp-ease-in-out);
}

.sp-p-trace-detail__mark:hover { opacity: 0.7; }
.sp-p-trace-detail__mark.is-error,
.sp-p-trace-detail__mark.is-deny { fill: var(--sp-danger); }
.sp-p-trace-detail__mark.is-rejected,
.sp-p-trace-detail__mark.is-warn { fill: var(--sp-warning); }
.sp-p-trace-detail__mark.is-pending { fill: var(--sp-text-tertiary); }
.sp-p-trace-detail__mark--tool,
.sp-p-trace-detail__mark--spawn { fill: var(--sp-info); }
.sp-p-trace-detail__mark--governance { fill: var(--sp-warning); }

.sp-p-trace-detail__axis {
    display: flex;
    justify-content: space-between;
    list-style: none;
    margin: var(--sp-space-1) 0 0;
    padding: 0;
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-p-trace-detail__key {
    display: inline-block;
    inline-size: 10px;
    block-size: 10px;
    border-radius: 2px;
    background: var(--sp-success);
}

.sp-p-trace-detail__key--ok { background: var(--sp-success); }
.sp-p-trace-detail__key--error { background: var(--sp-danger); }
.sp-p-trace-detail__key--rejected { background: var(--sp-warning); }
.sp-p-trace-detail__key--deny { background: var(--sp-danger); }
.sp-p-trace-detail__key--event { background: var(--sp-info); }

/* Turns table. The call cell stacks name, client and (when it failed) the
   error, so a failed row explains itself without opening. */
.sp-p-trace-detail__table .sp-p-trace-detail__call {
    max-inline-size: 36rem;
}

.sp-p-trace-detail__name {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    margin-inline-start: var(--sp-space-1);
}

.sp-p-trace-detail__sub,
.sp-p-trace-detail__offset {
    display: block;
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}

.sp-p-trace-detail__error {
    display: block;
    margin-top: var(--sp-space-05);
    font-size: var(--sp-text-xs);
    color: var(--sp-danger-strong);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.sp-table__el tbody .sp-p-trace-detail__row.is-error td:first-child,
.sp-table__el tbody .sp-p-trace-detail__row.is-deny td:first-child {
    box-shadow: inset 3px 0 0 var(--sp-danger);
}

.sp-table__el tbody .sp-p-trace-detail__row.is-rejected td:first-child,
.sp-table__el tbody .sp-p-trace-detail__row.is-warn td:first-child {
    box-shadow: inset 3px 0 0 var(--sp-warning);
}

/* A pause between turns is a row of its own: a thin rule with the length of
   the pause in the middle, so a burst reads as a burst. */
.sp-table__el tbody .sp-p-trace-detail__gap td {
    padding: var(--sp-space-1) var(--sp-space-3);
    text-align: center;
    font-size: var(--sp-text-2xs);
    color: var(--sp-text-tertiary);
    background: var(--sp-bg-surface-alt);
}

.sp-p-trace-detail__gap span {
    display: inline-block;
    padding: 0 var(--sp-space-2);
    background: var(--sp-bg-surface-alt);
}

/* Expanded panel: one article per decision, its policy chain as a nested
   table. */
.sp-p-trace-detail__panel {
    display: grid;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3) var(--sp-space-4) var(--sp-space-4);
}

.sp-p-trace-detail__check {
    display: grid;
    gap: var(--sp-space-2);
}

.sp-p-trace-detail__check-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
}

.sp-p-trace-detail__check-subject {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    max-inline-size: 28rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-p-trace-detail__check-head .sp-p-trace-detail__offset {
    display: inline;
}

.sp-p-trace-detail__check-link {
    margin-inline-start: auto;
    font-size: var(--sp-text-xs);
    color: var(--sp-accent-text);
    text-decoration: none;
}

.sp-p-trace-detail__check-link:hover { text-decoration: underline; }

.sp-p-trace-detail__check-reason {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

}

@layer components {

/* Floors, never ceilings: a header must never be narrower than its own label,
   which is what took this table to eleven clipped headings. The Started cell
   was ellipsizing the timestamp that says which trace a row is, and the status
   cell wrapped its badges onto a second line — that was the 57px row. */
.sp-trace-table .sp-col-started  { inline-size: auto; min-inline-size: 10rem; }
.sp-trace-table .sp-col-trace    { inline-size: auto; min-inline-size: 11rem; }
.sp-trace-table .sp-col-identity { inline-size: auto; min-inline-size: 9rem; }
.sp-trace-table .sp-col-model    { inline-size: auto; min-inline-size: 9rem; }
.sp-trace-table .sp-col-spans    { inline-size: auto; min-inline-size: 5rem; }
.sp-trace-table .sp-col-tokens   { inline-size: auto; min-inline-size: 6rem; }
.sp-trace-table .sp-col-cost     { inline-size: auto; min-inline-size: 8.5rem; }
.sp-trace-table .sp-col-duration { inline-size: auto; min-inline-size: 6rem; }
.sp-trace-table .sp-col-status   { inline-size: auto; min-inline-size: 11rem; }

.sp-trace-row__badges { white-space: nowrap; }

}

@layer components {

/* The tab panes. The edit forms inside them are the shared form-section, and
   everything else the page draws is a shared component. */

.sp-p-user-detail__pane {
  display: flex;
  flex-direction: column;
  gap: var(--sp-space-4);
}

.sp-p-user-detail__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-space-2);
  margin: 0;
}

}

@layer components {

/* The latest-conversation card: title and facts on the left, one action on
   the right, so the thing an admin opened the tab for is one click away. */
.sp-p-user-detail__latest-body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-space-4);
}

.sp-p-user-detail__latest-main {
  display: flex;
  flex-direction: column;
  gap: var(--sp-space-1);
  min-width: 0;
}

.sp-p-user-detail__latest-title {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--sp-text-md);
}

.sp-p-user-detail__latest-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-space-3);
  color: var(--sp-text-secondary);
  font-size: var(--sp-text-sm);
}

.sp-p-user-detail__latest { margin-bottom: var(--sp-space-2); }

}

@layer components {
.sp-p-access__summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--sp-space-4);
}
.sp-p-access__card {
  min-width: 0;
  padding: var(--sp-space-4);
  border: 1px solid var(--sp-border-subtle);
  border-radius: var(--sp-radius-md);
  background: var(--sp-bg-surface);
  overflow-wrap: anywhere;
}
.sp-p-access__card h3,
.sp-p-access__card h4 { margin: 0 0 var(--sp-space-2); }
.sp-p-access__card p { margin: var(--sp-space-2) 0; color: var(--sp-text-secondary); }
.sp-p-access__value { display: block; font-size: var(--sp-text-xl); }
.sp-p-access__card summary { cursor: pointer; font-weight: 600; }
.sp-p-access__card summary:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }
.sp-p-access__card[open] > summary { margin-bottom: var(--sp-space-4); }
.sp-p-access__workspace summary .sp-badge { margin-left: var(--sp-space-2); }
.sp-p-access__reason { display: block; margin-top: var(--sp-space-2); color: var(--sp-text-secondary); font-weight: 400; }
.sp-p-access__stack { display: flex; flex-direction: column; gap: var(--sp-space-2); }
.sp-p-access__plugins,
.sp-p-access__other { list-style: none; margin: var(--sp-space-3) 0 0; padding: 0; }
.sp-p-access__plugins li,
.sp-p-access__other li { display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-space-3); padding: var(--sp-space-2) 0; }
.sp-p-access__plugins li > :last-child { white-space: nowrap; }
.sp-p-access__actions { display: flex; gap: var(--sp-space-2); margin: var(--sp-space-3) 0; }
.sp-p-access__rule-editor { display: none; }
[data-access][data-editing="true"] .sp-p-access__rule-editor { display: inline-block; }
[data-access][data-editing="true"] .sp-p-access__rule-state { display: none; }
}

@layer responsive {

@media (max-width: 48rem) {
  .sp-p-access__summary { grid-template-columns: 1fr; }
  .sp-p-access__plugins li, .sp-p-access__other li { flex-wrap: wrap; }
}

}

@layer components {

.sp-scope-chips {
    max-width: 220px;
}

.sp-source-badge {
    padding: 0 var(--sp-space-15);
    border-radius: var(--sp-corners-sm);
    font-size: var(--sp-text-xs);
    background: var(--sp-bg-surface-raised);
    color: var(--sp-text-tertiary);
}

}

@layer components {

/* The roster. The table, KPIs and toolbar are shared components; what the page
   adds is the filter chip row, the search form, and the column discipline that
   holds every row to one line so a screenful is people rather than padding. */

.sp-p-users__chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-space-2);
}

.sp-p-users__search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-space-2);
}

/* Every data cell is one line. A wrapped name or a second row of badges is
   what turns a 32px row into an 80px one, and the full value stays reachable
   on the cell's title. */
.sp-p-users__cell {
  max-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sp-p-users__identity {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-space-2);
  max-width: 100%;
  color: inherit;
}

.sp-p-users__name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The shell's main element carries `contain: layout style`, which makes it the
   containing block for fixed descendants. The create-user panel is
   `position: fixed` and parks itself off-canvas with `translateX(100%)`, so
   while it is closed it extends the shell's scroll width by its full 640px and
   the page reports a sideways scroll it does not have. `visibility: hidden`
   does not remove that; only taking it out of layout does. This page is the
   only one that renders a side panel, so the rule lives here — the general fix
   is to stop main containing fixed positioning at all. */
.sp-side-panel:not(.is-open) { display: none; }

.sp-p-users__select {
  width: var(--sp-space-8);
  text-align: center;
}

/* Percentages summing to 100, so the table fits any width without an inner
   scrollbar and no column is squeezed to nothing. Widths hang off the column
   classes the header builder emits, not off nth-child: the select column is
   only rendered for writers, and an index-based width shifts every column by
   one the moment it is absent. Roles gets the room a second and third badge
   need; the name column gave it up, since it was sized past its longest value. */
.sp-p-users__table { table-layout: fixed; width: 100%; }
.sp-p-users__table th.sp-p-users__select { width: 3%; }
.sp-p-users__table th.sp-col-user { width: 17%; }
.sp-p-users__table th.sp-col-email { width: 14%; }
.sp-p-users__table th.sp-col-roles { width: 15%; }
.sp-p-users__table th.sp-col-scope { width: 13%; }
.sp-p-users__table th.sp-table__cell--date { width: 8%; }
.sp-p-users__table th.sp-table__cell--num { width: 7%; }
.sp-p-users__table th.sp-col-status { width: 8%; }
.sp-p-users__table th.sp-table__cell--actions { width: 8%; }

/* Status and the row action share one inline padding so the last two columns
   read as a pair rather than a badge adrift from a link. */
.sp-p-users__table td.sp-col-status,
.sp-p-users__table td.sp-table__cell--actions {
  padding-inline: var(--sp-density-cell-x);
  max-width: none;
}

.sp-p-users__table td.sp-col-status .sp-badge { overflow: visible; }

}

@layer responsive {

@media (max-width: 48rem) {
  .sp-p-users__search { width: 100%; }
}

}

@layer components {
.sp-analysis-pagination {
    display: flex;
    gap: var(--sp-space-4);
    margin: var(--sp-space-4) 0;
}
.sp-analysis-definitions {
    margin: var(--sp-space-6) 0;
    max-width: 75rem;
    line-height: var(--sp-leading-relaxed);
}
.sp-analysis-definitions summary {
    cursor: pointer;
    font-weight: var(--sp-font-semibold);
}
.sp-analysis-table td {
    white-space: normal;
    overflow-wrap: anywhere;
    text-overflow: clip;
}
.sp-analysis-table .sp-table__cell--num {
    white-space: nowrap;
}
[data-section="analysis-versions"] form {
    margin-bottom: var(--sp-space-4);
}
.sp-analysis-file-preview {
    max-height: 30rem;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
}
[data-section="analysis-versions"] code,
[data-section="analysis-versions"] dd {
    overflow-wrap: anywhere;
}
.sp-analysis-form {
    display: grid;
    gap: var(--sp-space-3);
    max-width: 48rem;
    margin: var(--sp-space-4) 0;
}
.sp-analysis-form label {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-medium);
}
.sp-analysis-form input:not([type="checkbox"]),
.sp-analysis-form select,
.sp-analysis-form textarea {
    min-width: 0;
    padding: var(--sp-space-2);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    color: var(--sp-text-primary);
    font: inherit;
    font-weight: var(--sp-font-normal);
}
.sp-analysis-form label:has(input[type="checkbox"]) {
    flex-direction: row;
    align-items: center;
}
}

.sp-analysis-strip {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-4);
    margin-block-end: var(--sp-space-3);
}
.sp-analysis-strip .sp-breadcrumbs {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
}
.sp-analysis-strip__guide {
    flex: none;
}

@layer components {
/* The line that says which marketplace you are looking at. It reads as a
   sentence, so it is one line and never a row of controls. */
.sp-inventory-summary {
    margin: 0 0 var(--sp-space-2);
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-xs);
}

/* Compact tiles: a band of context above dense rows, not a card each. */
.sp-kpi-grid--compact .sp-kpi {
    min-height: 0;
    padding: var(--sp-space-2) var(--sp-space-3);
}

.sp-inventory-inline {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
}

/* A version is its hash. The chip is the one mono token on a row of
   numbers, so it is quiet by default and only reads as a link on hover. */
.sp-hash--chip {
    display: inline-block;
    padding: 0 var(--sp-space-1);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    text-decoration: none;
    color: var(--sp-text-secondary);
}
.sp-hash--chip:hover,
.sp-hash--chip:focus-visible {
    color: var(--sp-text-primary);
    border-color: var(--sp-border-strong);
}
}

@layer components {
/* A version is its hash: the one mono token on every row, quiet by default. */
.sp-hash {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}
.sp-p-versions .sp-page-header {
    margin-block: var(--sp-space-3) var(--sp-space-3);
    padding-bottom: var(--sp-space-2);
}
.sp-p-versions .sp-tabs {
    margin-bottom: var(--sp-space-3);
}
.sp-p-versions .sp-kpi-grid {
    margin-bottom: var(--sp-space-3);
}
.sp-versions-table {
    font-size: var(--sp-text-sm);
    min-width: 58rem;
}
.sp-versions-table th[scope="col"] {
    white-space: nowrap;
}
/* One version is one line; the inline diff sits behind a <details> in the
   Change cell so the timeline stays scannable and needs no script. */
.sp-versions-row td {
    white-space: nowrap;
    vertical-align: top;
}
.sp-versions-row--current td {
    background: color-mix(in oklch, var(--sp-success) 6%, transparent);
}
.sp-generation-delta {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
}
.sp-generation-delta__add {
    color: var(--sp-success-strong);
}
.sp-generation-delta__remove {
    color: var(--sp-danger-strong);
}
.sp-generation-delta__change {
    color: var(--sp-text-tertiary);
}
.sp-versions-diff {
    margin-top: var(--sp-space-1);
    font-size: var(--sp-text-xs);
}
.sp-versions-diff__summary {
    cursor: pointer;
    color: var(--sp-text-secondary);
}
.sp-versions-diff__list {
    display: grid;
    gap: var(--sp-space-1);
    margin: var(--sp-space-2) 0 0;
    padding: 0;
    list-style: none;
}
.sp-versions-diff__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    white-space: normal;
}
.sp-versions-up {
    color: var(--sp-success-strong);
}
/* Compare: the two versions' tiles sit side by side above one skill table
   whose paired columns read before · after. */
.sp-versions-pick {
    margin-bottom: var(--sp-space-3);
}
.sp-versions-pair {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: var(--sp-space-4);
    margin-bottom: var(--sp-space-4);
}
.sp-versions-side {
    min-width: 0;
}
.sp-versions-side__title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
}
/* Distribution: the delivery tables carried over from the publication page. */
.sp-pub-section {
    min-width: 0;
    margin-block: var(--sp-space-3) var(--sp-space-5);
}
.sp-pub-table td {
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 18rem;
    vertical-align: middle;
}
.sp-pub-receipts {
    table-layout: fixed;
}
.sp-pub-receipts th:nth-child(1) { width: 15%; }
.sp-pub-receipts th:nth-child(2) { width: 18%; }
.sp-pub-receipts th:nth-child(3) { width: 11%; }
.sp-pub-receipts th:nth-child(4) { width: 11%; }
.sp-pub-receipts th:nth-child(5) { width: 12%; }
.sp-pub-receipts th:nth-child(6) { width: 15%; }
.sp-pub-receipts th:nth-child(7) { width: 18%; }
.sp-pub-receipts td {
    max-width: 0;
}
.sp-pub-consumer,
.sp-pub-verified {
    white-space: nowrap;
}
.sp-pub-table .sp-badge {
    padding-block: 0;
    line-height: 1;
}
.sp-pub-table .sp-u-mono,
.sp-pub-table .sp-pub-note,
.sp-pub-table .sp-pub-meta {
    line-height: var(--sp-density-cell-line);
    white-space: nowrap;
}
.sp-pub-meta {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}
.sp-pub-note {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    border-bottom: 1px dotted var(--sp-border-default);
    cursor: help;
}
.sp-pub-table td:has(.sp-pub-details) {
    white-space: normal;
    overflow: visible;
}
.sp-pub-details summary {
    cursor: pointer;
    font-size: var(--sp-text-sm);
}
.sp-pub-evidence {
    max-height: 20rem;
    max-width: 100%;
    overflow: auto;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    margin-top: var(--sp-space-2);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    font-size: var(--sp-text-xs);
}
.sp-pub-field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-2);
}
.sp-pub-field__help {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}
/* The one link out of Code ↔ Instance into the version history. */
.sp-sync-sources__versions {
    font-size: var(--sp-text-xs);
}
}

@layer components {
/* The judge's means beside a version's figures on the Compare tab. */
.sp-versions-side__eval {
    margin-block-start: var(--sp-space-3);
}
.sp-versions-side__eval-note {
    margin: var(--sp-space-1) 0 0;
    font-size: var(--sp-text-2xs);
}
}

@layer components {
/* Evaluation: the selected version's headline figures, each with its change
   from the baseline; the same deltas recur in the version and skill tables. */
.sp-eval-kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--sp-space-3);
    margin: 0 0 var(--sp-space-3);
}
.sp-eval-kpi {
    display: grid;
    gap: var(--sp-space-1);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-md);
}
.sp-eval-kpi dt {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
}
.sp-eval-kpi dd {
    margin: 0;
    font-size: var(--sp-text-lg);
    font-variant-numeric: tabular-nums;
}
.sp-eval-delta {
    font-size: var(--sp-text-xs);
    font-variant-numeric: tabular-nums;
}
.sp-eval-delta--good {
    color: var(--sp-success-strong);
}
.sp-eval-delta--bad {
    color: var(--sp-danger-strong);
}
.sp-eval-delta--flat {
    color: var(--sp-text-tertiary);
}
}

@layer components {
/* Analysis › Conversation detail: the record's facts on the left, the
   judge's card on the right, then one table per plane. */
/* Detail: the record's facts on the left, the judge's card on the right. */
.sp-aconvd-head {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(18rem, 1fr);
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-2) var(--sp-space-3);
}
@media (max-width: 60rem) {
    .sp-aconvd-head {
        grid-template-columns: 1fr;
    }
}
.sp-aconvd-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
    gap: var(--sp-space-2) var(--sp-space-3);
    margin: 0;
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}
.sp-aconvd-facts dt {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.sp-aconvd-facts dd {
    margin: 0;
    font-size: var(--sp-text-sm);
    overflow-wrap: anywhere;
}
.sp-aconvd-id {
    font-size: var(--sp-text-xs);
}
.sp-aconvd-judge {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-inline-start: 4px solid var(--sp-border-strong);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}
.sp-aconvd-judge--ok { border-inline-start-color: var(--sp-success-strong); }
.sp-aconvd-judge--warn { border-inline-start-color: var(--sp-warning-strong); }
.sp-aconvd-judge--err { border-inline-start-color: var(--sp-danger-strong); }
.sp-aconvd-judge__score {
    display: flex;
    align-items: baseline;
    font-family: var(--sp-font-mono);
}
.sp-aconvd-judge__num {
    font-size: var(--sp-text-3xl);
    font-weight: var(--sp-font-bold);
    line-height: 1;
}
.sp-aconvd-judge--ok .sp-aconvd-judge__num { color: var(--sp-success-strong); }
.sp-aconvd-judge--warn .sp-aconvd-judge__num { color: var(--sp-warning-strong); }
.sp-aconvd-judge--err .sp-aconvd-judge__num { color: var(--sp-danger-strong); }
.sp-aconvd-judge--muted .sp-aconvd-judge__num { color: var(--sp-text-tertiary); }
.sp-aconvd-judge__of {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-sm);
}
.sp-aconvd-judge__body {
    display: grid;
    gap: var(--sp-space-2);
    min-width: 0;
}
.sp-aconvd-judge__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-1);
}
.sp-aconvd-judge__label {
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    margin-inline-end: var(--sp-space-1);
}
.sp-aconvd-judge__summary,
.sp-aconvd-judge__rationale {
    margin: 0;
    font-size: var(--sp-text-sm);
}
.sp-aconvd-judge__rationale {
    color: var(--sp-text-secondary);
}
.sp-aconvd-judge__meta {
    margin: 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}
.sp-aconvd-turn--side td {
    color: var(--sp-text-tertiary);
}
.sp-aconvd-model {
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
}
.sp-aconvd-reason {
    max-width: 24rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* The five planes under the ledger, one tab each: a single full-width table
   at a time, so no plane is squeezed beside another; a long plane scrolls
   inside itself rather than stretching the page. */
.sp-aconvd-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--sp-space-3);
}
.sp-aconvd-grid > .sp-section {
    min-width: 0;
}
.sp-aconvd-grid .sp-table__scroll {
    max-block-size: 40rem;
    overflow: auto;
}
.sp-aconvd-grid .sp-table__el thead th {
    position: sticky;
    inset-block-start: 0;
    background: var(--sp-bg-surface);
    z-index: 1;
}
.sp-aconvd-plane__head {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin-block-end: var(--sp-space-2);
    color: var(--sp-text-tertiary);
}
.sp-aconvd-plane__title {
    margin: 0;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}
.sp-aconvd-plane__head .sp-btn {
    margin-inline-start: auto;
}
.sp-aconvd-tools td,
.sp-aconvd-artifacts td,
.sp-aconvd-gov td,
.sp-aconvd-skills td,
.sp-aconvd-safety td {
    font-size: var(--sp-text-sm);
}
}

@layer components {
/* Analysis › Conversations: dense rows of the deterministic record, every
   figure coloured by the same four tones the badges use, a trend slot per
   tile, a sparkline per row and one judge score per conversation. The row
   and cell rules are in 79-analysis-conversations2.css, the detail page in
   79-analysis-conversation-detail.css. */
.sp-aconv-range {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-2);
    margin-block: var(--sp-space-2) var(--sp-space-3);
}
.sp-aconv-range .sp-tabs {
    margin: 0;
}

.sp-aconv-kpis {
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
}

/* Charts share one x axis in a row; four fold to two columns. */
.sp-aconv-charts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-3) var(--sp-space-4);
}
.sp-aconv-chart {
    display: flex;
    min-width: 0;
    height: 19rem;
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}
.sp-aconv-charts--four {
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.sp-aconv-block {
    min-width: 0;
    margin-block: var(--sp-space-3) var(--sp-space-5);
}
.sp-aconv-block__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2) var(--sp-space-3);
    margin-block-end: var(--sp-space-2);
}
.sp-aconv-block__head > .sp-icon {
    color: var(--sp-text-tertiary);
}
.sp-aconv-block__head .sp-tabs {
    margin: 0 0 0 auto;
}
.sp-aconv-block__title {
    margin: 0;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}
.sp-aconv-block > .sp-table {
    max-width: 100%;
}

/* Toned numbers: the same value is the same colour on every page. */
.sp-aconv-num {
    font-variant-numeric: tabular-nums;
}
.sp-aconv-num--ok { color: var(--sp-success-strong); }
.sp-aconv-num--warn { color: var(--sp-warning-strong); }
.sp-aconv-num--err { color: var(--sp-danger-strong); font-weight: var(--sp-font-semibold); }
.sp-aconv-num--muted { color: var(--sp-text-tertiary); }
.sp-aconv-num--accent { color: var(--sp-text-primary); }

/* The judge's one number. */
.sp-aconv-score {
    display: inline-block;
    min-width: 2.4em;
    padding: 0 var(--sp-space-1);
    border-radius: var(--sp-radius-sm);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    text-align: center;
    text-decoration: none;
    line-height: 1.7;
}
.sp-aconv-score--ok { color: var(--sp-success-strong); background: var(--sp-success-dim); }
.sp-aconv-score--warn { color: var(--sp-warning-strong); background: var(--sp-warning-dim); }
.sp-aconv-score--err { color: var(--sp-danger-strong); background: var(--sp-danger-dim); }
.sp-aconv-score--muted { color: var(--sp-text-tertiary); border: 1px dashed var(--sp-border-subtle); }
.sp-aconv-score--lg {
    font-size: var(--sp-text-2xl);
    padding: var(--sp-space-1) var(--sp-space-3);
}
a.sp-aconv-score:hover,
a.sp-aconv-score:focus-visible {
    outline: 1px solid currentColor;
}

/* Share and cache bars: a track with a filled inline-start portion, the
   width carried on --sp-fill so the template prints one number. */
.sp-aconv-bar,
.sp-aconv-cache {
    display: inline-block;
    vertical-align: middle;
    width: 6rem;
    height: 0.45rem;
    border-radius: 2px;
    background: var(--sp-bg-surface-alt);
    overflow: hidden;
}
.sp-aconv-bar i,
.sp-aconv-cache i {
    display: block;
    height: 100%;
    width: var(--sp-fill, 0%);
    background: var(--sp-accent);
}
.sp-aconv-bar__label {
    margin-inline-start: var(--sp-space-1);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
    font-variant-numeric: tabular-nums;
}
.sp-aconv-col-share {
    white-space: nowrap;
}
.sp-aconv-cell-tokens {
    min-width: 4.5rem;
}
.sp-aconv-cache {
    display: block;
    width: 100%;
    height: 0.25rem;
    margin-block-start: 2px;
}
.sp-aconv-cache--ok i { background: var(--sp-success-strong); }
.sp-aconv-cache--warn i { background: var(--sp-warning-strong); }
.sp-aconv-cache--err i { background: var(--sp-danger-strong); }
.sp-aconv-cache--muted i { background: var(--sp-border-strong); }
}

@layer components {
/* The rows. Fixed layout keeps fourteen columns from fighting; the title
   column takes what the numbers leave. */
.sp-aconv-table {
    table-layout: fixed;
}
/* Sixteen columns; the widths sum to 95% + the select gutter, so nothing is
   squeezed below its header. */
.sp-aconv-table th.sp-aconv-col-select { width: 1.6rem; }
.sp-aconv-table th.sp-aconv-col-title { width: 15%; }
.sp-aconv-table th.sp-aconv-col-person { width: 8%; }
.sp-aconv-table th.sp-aconv-col-client { width: 8%; }
.sp-aconv-table th.sp-aconv-col-spark { width: 4.5%; }
.sp-aconv-table th.sp-aconv-col-skills { width: 9%; }
.sp-aconv-table th.sp-aconv-col-judge { width: 3%; }
.sp-aconv-table th.sp-col-date { width: 7.5%; }
.sp-aconv-table th.sp-table__cell--num { width: 5%; }
.sp-aconv-table td.sp-table__cell--num,
.sp-aconv-table td.sp-col-date {
    max-width: none;
    white-space: nowrap;
    overflow: visible;
}
.sp-aconv-table th,
.sp-aconv-breakdown th,
.sp-askill-table th,
.sp-tools-table th,
.sp-tools-breakdown th {
    white-space: nowrap;
    overflow-wrap: normal;
    hyphens: none;
}
/* Breakdown tables lay out by content: with a fixed layout their ten
   equal columns clipped every header to three letters. */
.sp-aconv-breakdown,
.sp-tools-breakdown {
    table-layout: auto;
}
.sp-aconv-breakdown th:first-child,
.sp-tools-breakdown th:first-child { min-width: 12rem; }
.sp-aconv-breakdown th.sp-aconv-col-share,
.sp-tools-breakdown th.sp-tools-col-share { min-width: 8.5rem; }
.sp-aconv-table td {
    vertical-align: top;
    max-width: 0;
    font-size: var(--sp-text-sm);
    font-variant-numeric: tabular-nums;
}
.sp-aconv-table thead th,
.sp-aconv-breakdown thead th {
    position: sticky;
    top: 0;
    z-index: var(--sp-z-sticky);
    background: var(--sp-bg-surface);
}
.sp-aconv-table tbody tr:hover > td,
.sp-aconv-breakdown tbody tr:hover > td {
    background: var(--sp-bg-surface-alt);
}
.sp-aconv-table th .sp-icon,
.sp-aconv-breakdown th .sp-icon {
    color: var(--sp-text-tertiary);
    vertical-align: -0.15em;
}
.sp-aconv-cell-link {
    text-decoration: none;
}
.sp-aconv-cell-link:hover,
.sp-aconv-cell-link:focus-visible {
    text-decoration: underline;
}
.sp-aconv-col-export {
    width: 1.8rem;
    text-align: end;
}
.sp-aconv-export {
    display: inline-flex;
    color: var(--sp-text-tertiary);
}
.sp-aconv-export:hover,
.sp-aconv-export:focus-visible {
    color: var(--sp-accent-text);
}
/* Why: a td may never carry a display other than table-cell (06-table-cell.css);
   the flex box that wraps the chips is the inner div, so the cell keeps its
   column width and the chips wrap inside it instead of collapsing. */
.sp-aconv-table td.sp-aconv-cell-skills,
.sp-aconv-table td.sp-aconv-cell-spark,
.sp-aconv-table td.sp-aconv-col-judge,
.sp-aconv-table td.sp-aconv-cell-title {
    display: table-cell;
    max-width: none;
    overflow: visible;
}
.sp-aconv-table td.sp-aconv-cell-title {
    max-width: 0;
}
.sp-aconv-cell-person,
.sp-aconv-cell-client {
    overflow: hidden;
}
.sp-aconv-cell-title .sp-table__link,
.sp-aconv-cell-person .sp-table__link {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
}
.sp-aconv-turns-toggle {
    margin-inline-start: auto;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}
.sp-aconv-turns-toggle:hover {
    color: var(--sp-accent-text);
}
.sp-aconv-continued {
    display: inline-block;
    padding: 0 var(--sp-space-2);
    border-radius: var(--sp-radius-sm);
    color: var(--sp-text-secondary);
    border: 1px solid var(--sp-border-subtle);
    font-size: var(--sp-text-xs);
    white-space: nowrap;
}

@layer components {
/* The verdict card opens on hover or keyboard focus of the AI cell — a
   title attribute truncated the summary and could not be read with a
   keyboard at all. It floats over the rows beneath, anchored to the row's
   right edge because the AI column is the last one. */
.sp-verdict {
    position: relative;
    min-width: 0;
}
.sp-verdict__card {
    display: none;
    position: absolute;
    inset-inline-end: 0;
    top: calc(100% + var(--sp-space-1));
    text-align: start;
    z-index: var(--sp-z-dropdown);
    width: min(28rem, 80vw);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface-overlay);
    box-shadow: var(--sp-shadow-float);
    white-space: normal;
}
.sp-verdict:hover .sp-verdict__card,
.sp-verdict:focus-within .sp-verdict__card {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--sp-space-1) var(--sp-space-3);
}
.sp-verdict__score {
    grid-row: span 3;
    align-self: start;
}
.sp-verdict__head {
    font-size: var(--sp-text-sm);
}
.sp-verdict__summary {
    margin: 0;
    font-size: var(--sp-text-xs);
    line-height: var(--sp-leading-relaxed);
}
.sp-aconv-cell-spark .sp-spark {
    width: 100%;
    height: 1.4rem;
}
.sp-aconv-meta {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.sp-aconv-intent {
    color: var(--sp-text-secondary);
}
.sp-aconv-outcome {
    font-weight: var(--sp-font-medium);
}
.sp-aconv-outcome--ok { color: var(--sp-success-strong); }
.sp-aconv-outcome--warn { color: var(--sp-warning-strong); }
.sp-aconv-outcome--err { color: var(--sp-danger-strong); }
.sp-aconv-outcome--muted { color: var(--sp-text-tertiary); }
.sp-aconv-model {
    font-family: var(--sp-font-mono);
}
.sp-aconv-more {
    color: var(--sp-accent-text);
}
.sp-aconv-model-chip {
    display: inline-block;
    margin-inline-end: var(--sp-space-1);
    padding: 0 var(--sp-space-1);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
}
.sp-aconv-summary {
    color: var(--sp-text-secondary);
}
.sp-aconv-tags,
.sp-aconv-skills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
}
.sp-aconv-tags {
    margin-block-start: var(--sp-space-1);
}
.sp-aconv-tag,
.sp-aconv-skill {
    display: inline-block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    text-decoration: none;
    padding: 0 var(--sp-space-2);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-xs);
    line-height: 1.6;
}
.sp-aconv-tag {
    color: var(--sp-text-secondary);
    background: var(--sp-bg-surface-alt);
    font-family: var(--sp-font-mono);
}
.sp-aconv-skill {
    color: var(--sp-text-secondary);
    border: 1px solid var(--sp-border-subtle);
    font-family: var(--sp-font-mono);
}
.sp-aconv-skill--hooked {
    color: var(--sp-accent-text);
    background: var(--sp-accent-dim);
    border-color: transparent;
}
a.sp-aconv-skill:hover,
a.sp-aconv-skill:focus-visible {
    text-decoration: underline;
}
}

@layer components {

/* Analysis › Skills › Overview: one row per marketplace. The funnel is three
   figures with the conversion beside each and one proportional track — the
   fills never carry text, which is what made the old bars unreadable. */
.sp-adopt {
    margin-block: var(--sp-space-3) var(--sp-space-4);
    min-width: 0;
}

.sp-adopt-table th.sp-adopt-table__col-name { width: 22%; }
.sp-adopt-table th.sp-adopt-table__col-track { width: 14%; min-width: 7rem; }
.sp-adopt-table th.sp-table__cell--num { width: 7%; }
.sp-adopt-table th.sp-col-date { width: 7%; }

.sp-adopt-table td {
    vertical-align: top;
}

.sp-adopt-table td.sp-table__cell--num,
.sp-adopt-table td.sp-col-date {
    padding-block-start: var(--sp-space-3);
}

.sp-adopt-table__col-name .sp-table__link b {
    font-size: var(--sp-text-base);
    font-weight: var(--sp-font-semibold);
}

.sp-adopt-table__col-track {
    padding-block-start: var(--sp-space-4);
}

/* One track, two overlaid fills from the same hue: installed as a wash,
   active solid, both as shares of entitled. */
.sp-adopt__track {
    position: relative;
    height: 0.4rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface-alt);
    overflow: hidden;
}

.sp-adopt__fill {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: var(--sp-fill, 0%);
    min-width: 2px;
    border-radius: var(--sp-radius-full);
    background: var(--sp-chart-blue);
    transition: width var(--sp-duration-normal) var(--sp-ease-out);
}

.sp-adopt__fill--installed {
    opacity: 0.35;
}

.sp-adopt__fill--active {
    opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
    .sp-adopt__fill {
        transition: none;
    }
}

}

@layer components {
/* Analysis › Skills: one scope strip (window, marketplace) over three tabs.
   Overview is the adoption table (80-analysis-adoption.css); Activity is the
   chart and its top-skills list; Skills is one table per marketplace with a
   plugin band per group. */

/* The scope strip: two labelled pill rows, wrapping on a narrow screen. The
   tab strip beneath it is the page's own — underlined, full width. */
.sp-askill-scope {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2) var(--sp-space-6);
    margin-block: var(--sp-space-2) var(--sp-space-3);
}

.sp-askill-scope__group {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    min-width: 0;
}

.sp-askill-scope__label {
    font-size: var(--sp-text-2xs);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
    white-space: nowrap;
}

.sp-askill-scope .sp-tabs {
    margin: 0;
    border-bottom: none;
    gap: var(--sp-space-1);
}

.sp-askill-scope .sp-tab {
    padding: var(--sp-space-1) var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface);
    font-size: var(--sp-text-xs);
    top: 0;
}

.sp-askill-scope .sp-tab--active {
    background: var(--sp-accent-fill);
    color: var(--sp-text-on-accent);
    border-color: var(--sp-accent);
}

.sp-askill-views .sp-tabs {
    margin-bottom: var(--sp-space-3);
}

.sp-askill-chart {
    min-height: 20rem;
    margin-block: var(--sp-space-3);
}

/* Activity: the skills the chart draws, share as a track beside the figure. */
.sp-askill-top {
    margin-block: var(--sp-space-3) var(--sp-space-4);
    min-width: 0;
}

.sp-askill-top-table th.sp-askill-top__col-share { width: 14%; min-width: 7rem; }

.sp-askill-top__share {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: var(--sp-space-2);
}

.sp-askill-group {
    min-width: 0;
    margin-block: var(--sp-space-3) var(--sp-space-4);
}
.sp-askill-group__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--sp-space-2);
    margin-block-end: var(--sp-space-2);
}
.sp-askill-group__title {
    margin: 0;
    font-size: var(--sp-text-base);
    font-weight: var(--sp-font-semibold);
}
.sp-askill-table {
    table-layout: fixed;
}
.sp-askill-table th.sp-askill-col-skill { width: 13%; }
.sp-askill-table th.sp-askill-col-spark { width: 5%; }
.sp-askill-table th.sp-askill-col-models { width: 9%; min-width: 8rem; }
.sp-askill-table th.sp-askill-col-agents { width: 7%; min-width: 6rem; }
.sp-askill-table th.sp-aconv-col-select { width: 1.6rem; }
.sp-askill-table th.sp-col-date { width: 6%; }
.sp-askill-table th.sp-table__cell--num { width: 5%; }
.sp-askill-table th.sp-askill-col-done { width: 4.5rem; }
.sp-askill-table td.sp-table__cell--num,
.sp-askill-table td.sp-col-date {
    max-width: none;
    white-space: nowrap;
    overflow: visible;
}
.sp-askill-table td {
    vertical-align: top;
    max-width: 0;
    font-size: var(--sp-text-sm);
}
.sp-askill-table td.sp-askill-col-spark,
.sp-askill-table td.sp-askill-col-models {
    display: table-cell;
    max-width: none;
    overflow: visible;
}
.sp-askill-col-skill {
    overflow: hidden;
}
.sp-askill-col-spark .sp-spark {
    width: 100%;
    height: 1.4rem;
}
/* The plugin band inside a marketplace table: one row spanning every
   column, quieter than a header, louder than a row. */
.sp-askill-plugin th {
    padding-block: var(--sp-space-1);
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-semibold);
    text-align: start;
    color: var(--sp-text-secondary);
    background: var(--sp-bg-surface-alt);
}
.sp-askill-plugin__name {
    font-family: var(--sp-font-mono);
    color: var(--sp-text-primary);
}

.sp-askill-col-done {
    white-space: nowrap;
}
.sp-askill-judged {
    display: inline;
    font-variant-numeric: tabular-nums;
}
.sp-askill-table thead th {
    position: sticky;
    top: 0;
    z-index: var(--sp-z-sticky);
    background: var(--sp-bg-surface);
}
.sp-askill-table th .sp-icon {
    color: var(--sp-text-tertiary);
    vertical-align: -0.15em;
}
.sp-askill-table tbody tr:hover > td {
    background: var(--sp-bg-surface-alt);
}
}

@layer components {
/* The unused-skills list lives behind a toolbar pill, not at the page foot:
   it is a lookup, and the page ends with its table. */
.sp-askill-unused {
    position: relative;
}
.sp-askill-unused__summary {
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    cursor: pointer;
}
.sp-askill-unused__summary::-webkit-details-marker {
    display: none;
}
.sp-askill-unused__panel {
    position: absolute;
    inset-inline-end: 0;
    top: calc(100% + var(--sp-space-1));
    z-index: var(--sp-z-dropdown);
    width: min(36rem, 90vw);
    max-height: 22rem;
    overflow: auto;
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-default);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface-overlay);
    box-shadow: var(--sp-shadow-float);
}
.sp-askill-unused__list {
    columns: 2 14rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: var(--sp-text-xs);
}
.sp-askill-unused__list li {
    break-inside: avoid;
    padding-block: var(--sp-space-05);
}
}

@layer components {

/* The explanations used to sit at the foot of every Analysis page as a
   <details>; they are reference, not reading, so they live behind one `?`
   and open as a two-column glossary the reader can scan while the table is
   still in view underneath. */
.sp-help {
    max-width: min(760px, 94vw);
}

.sp-help__frame {
    display: flex;
    flex-direction: column;
    max-height: 86vh;
}

.sp-help__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--sp-space-3);
    padding: var(--sp-space-4) var(--sp-space-5);
    border-bottom: 1px solid var(--sp-border-subtle);
}

.sp-help__title {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0;
    font-size: var(--sp-text-lg);
    font-weight: var(--sp-font-semibold);
}

.sp-help__title .sp-icon {
    color: var(--sp-accent-text);
}

.sp-help__close {
    flex-shrink: 0;
    font-size: var(--sp-text-lg);
    line-height: 1;
}

.sp-help__body {
    overflow: auto;
    padding: var(--sp-space-4) var(--sp-space-5);
    display: grid;
    gap: var(--sp-space-5);
}

.sp-help__intro {
    margin: 0;
    color: var(--sp-text-secondary);
    font-size: var(--sp-text-sm);
    line-height: var(--sp-leading-relaxed);
}

.sp-help__heading {
    margin: 0 0 var(--sp-space-2);
    font-size: var(--sp-text-2xs);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}

.sp-help__section {
    display: grid;
    gap: var(--sp-space-2);
}

.sp-help__list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
    gap: var(--sp-space-3) var(--sp-space-5);
    margin: 0;
}

.sp-help__item {
    display: grid;
    gap: var(--sp-space-05);
}

.sp-help__term {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
}

.sp-help__term .sp-icon {
    color: var(--sp-accent-text);
}

.sp-help__text {
    margin: 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    line-height: var(--sp-leading-relaxed);
}

.sp-help__foot {
    padding: var(--sp-space-3) var(--sp-space-5);
    border-top: 1px solid var(--sp-border-subtle);
    display: flex;
    justify-content: flex-end;
}

.sp-help-open {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    background: var(--sp-bg-surface);
    color: var(--sp-text-secondary);
    cursor: pointer;
}

.sp-help-open:hover,
.sp-help-open:focus-visible {
    color: var(--sp-accent-text);
    border-color: var(--sp-accent);
}

}

@layer components {

/* Tools & artifacts: one dense ledger of calls, the artifact subset beside
   it. Kind is carried by a glyph and a tint together so a colour-blind
   reader still tells a file from a card. */
.sp-tools-kpis {
    grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
}

.sp-tools-block__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-3);
    margin-block-end: var(--sp-space-2);
    color: var(--sp-text-tertiary);
}

.sp-tools-block__title {
    margin: 0;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-primary);
}

.sp-tools-block__head .sp-tabs {
    margin: 0 0 0 auto;
}

.sp-tools-tool {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    min-width: 0;
    max-width: 100%;
}

.sp-tools-tool .sp-icon {
    color: var(--sp-text-tertiary);
}

.sp-tools-tool code {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-tools-input {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-tools-path {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    max-width: 18rem;
    padding: 0 var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    font-family: var(--sp-font-mono);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    line-height: 1.7;
}

.sp-tools-kind {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-1);
    padding: 0 var(--sp-space-2);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-medium);
    line-height: 1.7;
    text-decoration: none;
    white-space: nowrap;
    color: var(--sp-text-secondary);
    background: var(--sp-bg-surface-alt);
}

.sp-tools-kind--file { color: var(--sp-accent-text); background: var(--sp-accent-dim); }
.sp-tools-kind--card { color: var(--sp-info-strong); background: color-mix(in oklch, var(--sp-info) 14%, transparent); }
.sp-tools-kind--ui { color: var(--sp-success-strong); background: var(--sp-success-dim); }
.sp-tools-kind--body { color: var(--sp-warning-strong); background: var(--sp-warning-dim); }
.sp-tools-kind--wrench { color: var(--sp-text-tertiary); }

a.sp-tools-kind:hover,
a.sp-tools-kind:focus-visible {
    outline: 1px solid currentColor;
}

.sp-tools-links {
    display: inline-flex;
    gap: var(--sp-space-1);
}

.sp-tools-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: var(--sp-radius-sm);
    color: var(--sp-text-tertiary);
    text-decoration: none;
}

.sp-tools-link:hover,
.sp-tools-link:focus-visible {
    color: var(--sp-accent-text);
    background: var(--sp-accent-dim);
}

.sp-tools-decision {
    text-decoration: none;
}

.sp-tools-export {
    display: inline-flex;
    color: var(--sp-text-tertiary);
    text-decoration: none;
}

.sp-tools-export:hover,
.sp-tools-export:focus-visible {
    color: var(--sp-accent-text);
}

.sp-tools-col-share {
    white-space: nowrap;
}

.sp-tools-col-export {
    width: 2rem;
    text-align: end;
}

}

@layer components {

/* The rows. Fixed layout keeps eleven columns from fighting; the input and
   title columns take what the fixed ones leave. The header sticks so a page
   of fifty calls keeps its column names in view. */
.sp-tools-table {
    table-layout: fixed;
}

.sp-tools-table thead th,
.sp-tools-breakdown thead th {
    position: sticky;
    top: 0;
    z-index: var(--sp-z-sticky);
    background: var(--sp-bg-surface);
}

.sp-tools-table th.sp-tools-col-select { width: 2rem; }
.sp-tools-table th.sp-col-date { width: 7rem; }
.sp-tools-table th.sp-tools-col-tool { width: 16%; }
.sp-tools-table th.sp-tools-col-server { width: 9%; }
.sp-tools-table th.sp-tools-col-input { width: 22%; }
.sp-tools-table th.sp-tools-col-person { width: 9%; }
.sp-tools-table th.sp-tools-col-links { width: 6rem; }
.sp-tools-table th.sp-tools-col-artifact { width: 9%; }
.sp-tools-table th.sp-tools-col-kind { width: 6rem; }
.sp-tools-table th.sp-tools-col-title { width: 26%; }
.sp-tools-table th.sp-tools-col-open { width: 9rem; }
.sp-tools-table th.sp-table__cell--num { width: 5.5rem; }

.sp-tools-table td {
    vertical-align: top;
    max-width: 0;
    font-size: var(--sp-text-sm);
    font-variant-numeric: tabular-nums;
}

/* Why: a td may never carry a display other than table-cell (06-table-cell.css);
   the inline boxes inside these cells overflow visibly rather than clip a
   badge or a glyph in half. */
.sp-tools-table td.sp-tools-col-select,
.sp-tools-table td.sp-tools-col-links,
.sp-tools-table td.sp-tools-col-kind,
.sp-tools-table td.sp-tools-col-artifact,
.sp-tools-table td.sp-tools-col-open {
    display: table-cell;
    max-width: none;
    overflow: visible;
}

.sp-tools-table td.sp-tools-col-tool,
.sp-tools-table td.sp-tools-col-input,
.sp-tools-table td.sp-tools-col-title,
.sp-tools-table td.sp-tools-col-server,
.sp-tools-table td.sp-tools-col-person {
    overflow: hidden;
}

.sp-tools-table td.sp-tools-col-person .sp-table__link {
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-tools-table .sp-table__cell--num {
    text-align: end;
}

.sp-tools-table tr:hover > td {
    background: var(--sp-bg-surface-alt);
}

/* The pinned-window chip beside the presets, when a row link set the range. */
.sp-tools-pinned {
    display: inline-flex;
    align-items: center;
    gap: var(--sp-space-2);
    padding: 0 var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-full);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    font-variant-numeric: tabular-nums;
    line-height: 1.9;
}

.sp-tools-pinned .sp-icon {
    color: var(--sp-text-tertiary);
}

.sp-tools-pinned__widen {
    color: var(--sp-accent-text);
    text-decoration: none;
}

.sp-tools-pinned__widen:hover,
.sp-tools-pinned__widen:focus-visible {
    text-decoration: underline;
}
}

@layer components {

/* Analysis › Reports. The verdict head, the theme cards and the banner all
   key their colour off the same three assessment tones the badges use, so a
   "watch" report reads amber everywhere it is mentioned. */
.sp-report-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    margin-block: var(--sp-space-2) var(--sp-space-3);
    padding: var(--sp-space-2) var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-inline-start: 3px solid var(--sp-border-strong);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    font-size: var(--sp-text-sm);
}
.sp-report-banner--ok { border-inline-start-color: var(--sp-success-strong); }
.sp-report-banner--warn { border-inline-start-color: var(--sp-warning-strong); }
.sp-report-banner--err { border-inline-start-color: var(--sp-danger-strong); }
.sp-report-banner__icon {
    display: inline-flex;
    color: var(--sp-accent-text);
}
.sp-report-banner__headline {
    flex: 1 1 20rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--sp-text-primary);
    text-decoration: none;
    font-weight: var(--sp-font-medium);
}
.sp-report-banner__headline--empty {
    color: var(--sp-text-tertiary);
    font-weight: var(--sp-font-normal);
}
.sp-report-banner__meta {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
    white-space: nowrap;
}
.sp-report-banner__form {
    display: inline-flex;
    margin-inline-start: auto;
}
.sp-report-banner .sp-btn .sp-icon {
    margin-inline-end: var(--sp-space-1);
}

.sp-report-request {
    margin-block: var(--sp-space-2) var(--sp-space-4);
}
.sp-report-request__form {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: var(--sp-space-3);
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}
.sp-report-request__field {
    display: flex;
    flex-direction: column;
    gap: var(--sp-space-1);
    font-size: var(--sp-text-xs);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
    min-width: 12rem;
}
.sp-report-table .sp-report-col-headline {
    max-width: 28rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sp-report-head {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--sp-space-3);
    margin-block: var(--sp-space-2) var(--sp-space-3);
    padding: var(--sp-space-4);
    border: 1px solid var(--sp-border-subtle);
    border-inline-start: 4px solid var(--sp-border-strong);
    border-radius: var(--sp-corners-md);
    background: var(--sp-bg-surface);
}
.sp-report-head--ok { border-inline-start-color: var(--sp-success-strong); }
.sp-report-head--warn { border-inline-start-color: var(--sp-warning-strong); }
.sp-report-head--err { border-inline-start-color: var(--sp-danger-strong); }
.sp-report-head__badge {
    display: inline-flex;
    font-size: var(--sp-text-2xl);
    color: var(--sp-text-tertiary);
}
.sp-report-head--ok .sp-report-head__badge { color: var(--sp-success-strong); }
.sp-report-head--warn .sp-report-head__badge { color: var(--sp-warning-strong); }
.sp-report-head--err .sp-report-head__badge { color: var(--sp-danger-strong); }
.sp-report-head__body {
    display: grid;
    gap: var(--sp-space-2);
    min-width: 0;
}
.sp-report-head__headline {
    margin: 0;
    font-size: var(--sp-text-lg);
    font-weight: var(--sp-font-semibold);
    line-height: var(--sp-leading-tight);
}
.sp-report-head__headline--empty {
    color: var(--sp-text-tertiary);
    font-weight: var(--sp-font-normal);
}
.sp-report-head__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-space-2);
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-report-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(18rem, 1fr);
    gap: var(--sp-space-3);
}
@media (max-width: 60rem) {
    .sp-report-grid {
        grid-template-columns: 1fr;
    }
}
.sp-report-section__title {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    margin: 0 0 var(--sp-space-3);
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}
.sp-report-themes {
    display: grid;
    gap: var(--sp-space-2);
    align-content: start;
}
.sp-report-theme {
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-inline-start: 3px solid var(--sp-border-strong);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
}
.sp-report-theme--ok { border-inline-start-color: var(--sp-success-strong); }
.sp-report-theme--warn { border-inline-start-color: var(--sp-warning-strong); }
.sp-report-theme--err { border-inline-start-color: var(--sp-danger-strong); }
.sp-report-theme__head {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
}
.sp-report-theme__icon { display: inline-flex; color: var(--sp-text-tertiary); }
.sp-report-theme--ok .sp-report-theme__icon { color: var(--sp-success-strong); }
.sp-report-theme--warn .sp-report-theme__icon { color: var(--sp-warning-strong); }
.sp-report-theme--err .sp-report-theme__icon { color: var(--sp-danger-strong); }
.sp-report-theme__title {
    flex: 1;
    margin: 0;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
}
.sp-report-theme__kind {
    font-size: var(--sp-text-2xs);
    text-transform: uppercase;
    letter-spacing: var(--sp-tracking-wide);
    color: var(--sp-text-tertiary);
}
.sp-report-theme__detail {
    margin: var(--sp-space-1) 0 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    line-height: var(--sp-leading-relaxed);
}

}

@layer components {

/* Evidence chips are the report's citations: each opens the console page for
   the id the model cited, so a claim is one click from the rows behind it. */
.sp-report-evidence {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-space-1);
    margin: var(--sp-space-2) 0 0;
    padding: 0;
    list-style: none;
}
.sp-report-evidence__chip {
    display: inline-block;
    max-width: 18rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 0 var(--sp-space-2);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-radius-sm);
    font-size: var(--sp-text-xs);
    line-height: 1.7;
    color: var(--sp-text-secondary);
    text-decoration: none;
}
.sp-report-evidence__chip--skill,
.sp-report-evidence__chip--tool,
.sp-report-evidence__chip--model {
    font-family: var(--sp-font-mono);
}
.sp-report-evidence__chip--conversation {
    color: var(--sp-accent-text);
    background: var(--sp-accent-dim);
    border-color: transparent;
}
.sp-report-evidence__chip--person {
    color: var(--sp-text-primary);
}
.sp-report-evidence__chip:hover,
.sp-report-evidence__chip:focus-visible {
    border-color: var(--sp-border-strong);
    text-decoration: underline;
}

.sp-report-recs {
    align-self: start;
}
.sp-report-recs__list {
    display: grid;
    gap: var(--sp-space-2);
    margin: 0;
    padding: 0;
    list-style: none;
}
.sp-report-rec {
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
}
.sp-report-rec--empty {
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-sm);
}
.sp-report-rec__head {
    display: flex;
    align-items: flex-start;
    gap: var(--sp-space-2);
}
.sp-report-rec__action {
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-medium);
}
.sp-report-rec__rationale {
    margin: var(--sp-space-1) 0 0;
    font-size: var(--sp-text-xs);
    color: var(--sp-text-secondary);
    line-height: var(--sp-leading-relaxed);
}

.sp-report-digest {
    margin-block: var(--sp-space-4);
}
.sp-report-digest > summary {
    display: flex;
    align-items: center;
    gap: var(--sp-space-2);
    cursor: pointer;
    font-size: var(--sp-text-sm);
    font-weight: var(--sp-font-semibold);
    color: var(--sp-text-secondary);
}
.sp-report-digest__text {
    max-height: 30rem;
    overflow: auto;
    margin: var(--sp-space-2) 0 0;
    padding: var(--sp-space-3);
    border: 1px solid var(--sp-border-subtle);
    border-radius: var(--sp-corners-sm);
    background: var(--sp-bg-surface);
    font-size: var(--sp-text-xs);
    line-height: var(--sp-leading-relaxed);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* The loading widget stands where the headline will be: what is being read,
   an indeterminate bar, and how long it has taken — so the wait is honest. */
.sp-report-loading {
    display: grid;
    gap: var(--sp-space-2);
}

.sp-report-loading__detail,
.sp-report-loading__hint {
    margin: 0;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
}

.sp-report-loading__hint {
    font-size: var(--sp-text-xs);
    color: var(--sp-text-tertiary);
}

.sp-report-loading__bar {
    position: relative;
    height: 0.35rem;
    max-width: 24rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent-dim);
    overflow: hidden;
}

.sp-report-loading__bar i {
    position: absolute;
    inset-block: 0;
    width: 35%;
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent);
    animation: sp-report-sweep 1.4s ease-in-out infinite;
}

.sp-report-loading.is-failed .sp-report-loading__bar i {
    animation: none;
    width: 100%;
    background: var(--sp-danger-strong);
}

@keyframes sp-report-sweep {
    0% { inset-inline-start: -35%; }
    100% { inset-inline-start: 100%; }
}

@media (prefers-reduced-motion: reduce) {
    .sp-report-loading__bar i {
        animation: none;
        width: 100%;
    }
}

}

@layer components {

.sp-login-container {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: var(--sp-space-5);
    background:
        linear-gradient(180deg, var(--sp-bg-canvas) 0%, var(--sp-bg-base) 100%);
}

.sp-login-subtitle {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-tertiary);
    margin: 0 0 var(--sp-space-5);
}

.sp-login-error {
    display: block;
    background: var(--sp-danger-dim);
    color: var(--sp-danger-strong);
    padding: var(--sp-space-2) var(--sp-space-4);
    border-radius: var(--sp-radius-md);
    font-size: var(--sp-text-sm);
    margin-bottom: var(--sp-space-4);
    text-align: left;
}

.sp-login-error[hidden] {
    display: none;
}

.sp-login-loading {
    flex-direction: column;
    align-items: center;
    gap: var(--sp-space-2);
    padding: var(--sp-space-5);
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-sm);
}

.sp-login-loading:not([hidden]) {
    display: flex;
}

.sp-login-spinner {
    width: 32px;
    height: 32px;
    border: 3px solid var(--sp-border-default);
    border-top-color: var(--sp-accent);
    border-radius: var(--sp-radius-full);
    animation: spin var(--sp-duration-slow) linear infinite;
}

.sp-login-retry {
    display: block;
    margin-top: var(--sp-space-2);
}

.sp-login-retry[hidden] {
    display: none;
}

.sp-login-retry a {
    color: var(--sp-accent-text);
    text-decoration: none;
    font-size: var(--sp-text-sm);
}

.sp-login-retry a:hover {
    text-decoration: underline;
}

.sp-login-logo img {
    max-width: 100%;
    height: auto;
}

.sp-login-logo .sp-logo-dark { display: none; }

.sp-login-container .sp-form-group input:focus-visible,
.sp-login-container .sp-form-group select:focus-visible,
.sp-login-container .sp-form-group textarea:focus-visible {
    outline: 2px solid var(--sp-accent);
    outline-offset: 2px;
}

.sp-login-container .sp-btn,
.sp-login-container button[type="submit"] {
    border-radius: var(--sp-corners-sm);
}

main.sp-login-container {
    display: flex;
}

.sp-auth-page {
    display: flex;
    min-height: 100vh;
    background:
        linear-gradient(180deg, var(--sp-bg-canvas) 0%, var(--sp-bg-base) 100%);
}

.sp-auth-info {
    flex: 1;
    max-width: 640px;
    padding: 3rem 3rem 3rem 4rem;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.sp-auth-form-col {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    min-width: 420px;
}

.sp-auth-info h2 {
    font-size: var(--sp-text-md);
    font-weight: 700;
    color: var(--sp-text-primary);
    margin: 1.5rem 0 0.5rem;
}

.sp-auth-info h3 {
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-primary);
    margin: 0.75rem 0 0.25rem;
}
}



@layer components {

.sp-auth-info p {
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    line-height: 1.6;
    margin: 0 0 0.5rem;
}

.sp-auth-info .sp-u-text-muted { color: var(--sp-text-tertiary); }

.sp-auth-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: var(--sp-accent-dim);
    color: var(--sp-accent-hover);
    font-size: var(--sp-text-xs);
    font-weight: 600;
    padding: 0.3rem 0.75rem;
    border-radius: var(--sp-radius-full);
    margin-bottom: 1rem;
}

.sp-auth-divider {
    border: none;
    border-top: 1px solid var(--sp-border-default);
    margin: 1.25rem 0;
}

.sp-auth-flow-steps {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin: 0.5rem 0;
}

.sp-auth-flow-step {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    font-size: var(--sp-text-sm);
    color: var(--sp-text-secondary);
    line-height: 1.5;
}

.sp-auth-flow-step .sp-step-num,
.sp-auth-page .sp-step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.4rem;
    height: 1.4rem;
    border-radius: var(--sp-radius-full);
    background: var(--sp-accent-fill);
    color: var(--sp-text-on-accent);
    font-size: var(--sp-text-xs);
    font-weight: 700;
    flex-shrink: 0;
    margin-top: 0.1rem;
}

@media (max-width: 900px) {
    .sp-auth-page { flex-direction: column; }
    .sp-auth-info { max-width: 100%; padding: 2rem 1.5rem 1rem; }
    .sp-auth-form-col { min-width: 0; padding: 1rem 1.5rem 2rem; }
}

@media (prefers-reduced-motion: reduce) {
    .sp-login-spinner {
        animation: none;
    }
}

.sp-auth-more > summary {
    cursor: pointer;
    font-size: var(--sp-text-sm);
    font-weight: 600;
    color: var(--sp-text-secondary);
    padding: var(--sp-space-2) 0;
    user-select: none;
}

.sp-auth-more > summary:hover {
    color: var(--sp-accent-text);
}
}

@layer components {

.sp-auth-light {
    margin: 0;
    background: var(--sp-bg-base);
    color: var(--sp-text-primary);
    font-family: var(--sp-font-family);
}

.sp-auth-light .sp-login-logo .sp-logo-light {
    display: block;
}

.sp-auth-light .sp-login-logo .sp-logo-dark {
    display: none;
}

.sp-login-container--bare {
    min-height: auto;
    padding: 0;
    background: none;
}

body.sp-auth-light {
    margin: 0;
    background: var(--sp-bg-base);
    color: var(--sp-text-primary);
    font-family: var(--sp-font-body);
}

.sp-login-switch {
    margin: 0.85rem 0 0;
    text-align: center;
    color: var(--sp-text-tertiary);
    font-size: var(--sp-text-xs);
}

.sp-login-switch a {
    color: var(--sp-accent-text);
    text-decoration: none;
}

.sp-login-switch a:hover {
    text-decoration: underline;
}
}
