/*
 * Platform-shell styles shared by every mounted engine, layered on top of
 * the Bootstrap CDN stylesheet linked in the layout. Bootstrap 5.3's CSS
 * custom properties are overridden below instead of recompiling Bootstrap's
 * Sass, since this app has no Node/Sass build step (Propshaft only).
 *
 * Redesign: native-macOS visual language -- San Francisco (system-ui/
 * -apple-system) type, macOS system blue (#007aff light / #0a84ff dark)
 * accent and system semantic colors (red/orange/green), a generous
 * macOS-scale corner radius (--bs-border-radius-lg for panels/cards,
 * -sm for controls/chips), translucent "vibrancy" chrome for the sidebar/
 * toolbar/footer (--vibrancy-bg + backdrop-filter blur, real page content
 * blurring through rather than a flat opaque panel), and a soft blue glow
 * for focus/hover instead of Fluent's sharp offset outline. Every class
 * name below is unchanged from the prior (Windows Fluent) pass -- dozens
 * of views across all 4 engines reference these by name, so this redesign
 * only touches property values here, never the HTML/JS that uses them.
 *
 * A second, explicit goal of this pass: nothing reads smaller than ~13px
 * anywhere. The previous pass had several 0.6x-0.7rem "technical readout"
 * sizes (stage-tool chips, LED labels, module stat labels) that were
 * genuinely hard to read -- every one of those is bumped here.
 *
 * --bs-danger/--bs-warning/--bs-success/--bs-secondary are reused as LED
 * status colors (crit/warn/ok/off) -- VariantLens's tier/severity code
 * (badges, VariantDensityTrackSvg, ACMG classifier output) references these
 * Bootstrap variable names directly, so refining values here again requires
 * no changes to that Ruby/JS, same as every prior pass.
 *
 * Light/dark tokens follow the same three-block pattern used throughout
 * this app: light defaults at :root, a prefers-color-scheme override, then
 * [data-theme] overrides in both directions so the in-app toggle always
 * wins over the OS setting. The layout's inline FOUC-guard script always
 * sets data-theme="light" on first visit regardless of OS preference (see
 * app/views/layouts/application.html.erb) -- dark is opt-in only, via the
 * platform menu's toggle, never automatic.
 *
 * Engine-specific styling (e.g. Folding's .workspace/.residue-* rules)
 * lives in that engine's own stylesheet, not here.
 */

:root {
  color-scheme: light;
  --bs-primary: #007aff;
  --bs-primary-rgb: 0, 122, 255;
  --bs-info: #0a84ff;
  --bs-info-rgb: 10, 132, 255;
  --bs-success: #34c759;
  --bs-success-rgb: 52, 199, 89;
  --bs-danger: #ff3b30;
  --bs-danger-rgb: 255, 59, 48;
  --bs-warning: #ff9500;
  --bs-warning-rgb: 255, 149, 0;
  --bs-secondary: #6e6e73;
  --bs-secondary-rgb: 110, 110, 115;
  --bs-link-color: #007aff;
  --bs-link-color-rgb: 0, 122, 255;
  --bs-link-hover-color: #0060cc;
  --bs-link-hover-color-rgb: 0, 96, 204;
  --bs-body-bg: #f5f5f7;
  --bs-body-color: #1d1d1f;
  --bs-border-color: #d2d2d7;
  --bs-border-radius: 10px;
  --bs-border-radius-sm: 7px;
  --bs-border-radius-lg: 14px;
  --bs-font-sans-serif: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Helvetica Neue", Helvetica, Arial, sans-serif;

  --brand-dark: #1d1d1f;
  --signal-dim: #0060cc;
  --accent-soft: #e8f2ff;
  --accent-soft-ink: #0060cc;
  --engine-folding-soft: #f3ecfd;
  --engine-folding-ink: #5b21b6;
  --engine-ngs-soft: #e6f7fa;
  --engine-ngs-ink: #0e7490;
  --engine-variants-soft: #fdf3e0;
  --engine-variants-ink: #92400e;
  --engine-rna-soft: #e3f8ef;
  --engine-rna-ink: #047857;
  --engine-metagenomics-soft: #f7fee7;
  --engine-metagenomics-ink: #3f6212;
  --engine-epigenomics-soft: #fdf2f8;
  --engine-epigenomics-ink: #9d174d;
  --font-mono: "SF Mono", "Cascadia Code", ui-monospace, Menlo, Consolas, monospace;

  /* macOS sidebar/toolbar "vibrancy" material -- a translucent panel that
     blurs whatever page content scrolls behind it (backdrop-filter), the
     signature look of Finder/Mail/Notes' persistent chrome. Two separate
     tokens since the sidebar sits over the plain page background while
     the toolbar sits over page content that may itself be colored. */
  --vibrancy-bg: rgba(246, 246, 248, 0.78);
  --vibrancy-border: rgba(0, 0, 0, 0.08);

  /* Per-engine brand colors -- one hue per mounted engine (Folding/NGS/
     Variants/RNA), each a two-stop gradient + matching glow shadow color
     so icon chips/pills can read as glossy/3D rather than flat swatches.
     Light-theme values here; the dark-theme blocks below (@media
     prefers-color-scheme + [data-theme="dark"]) re-point these to a
     darker step of the same hue so gradient chips/tiles/buttons don't
     glare against the dark surface. See [data-engine="..."] further down
     for how a whole engine's pages pick up their color as
     --bs-primary/--accent-soft. */
  --engine-folding-a: #7c3aed;
  --engine-folding-b: #a855f7;
  --engine-folding-a-rgb: 124, 58, 237;
  --engine-folding-glow: rgba(124, 58, 237, 0.35);

  --engine-ngs-a: #0891b2;
  --engine-ngs-b: #22d3ee;
  --engine-ngs-a-rgb: 8, 145, 178;
  --engine-ngs-glow: rgba(8, 145, 178, 0.35);

  --engine-variants-a: #b45309;
  --engine-variants-b: #f59e0b;
  --engine-variants-a-rgb: 180, 83, 9;
  --engine-variants-glow: rgba(180, 83, 9, 0.35);

  --engine-rna-a: #059669;
  --engine-rna-b: #34d399;
  --engine-rna-a-rgb: 5, 150, 105;
  --engine-rna-glow: rgba(5, 150, 105, 0.35);

  --engine-metagenomics-a: #65a30d;
  --engine-metagenomics-b: #a3e635;
  --engine-metagenomics-a-rgb: 101, 163, 13;
  --engine-metagenomics-glow: rgba(101, 163, 13, 0.35);

  --engine-epigenomics-a: #db2777;
  --engine-epigenomics-b: #f472b6;
  --engine-epigenomics-a-rgb: 219, 39, 119;
  --engine-epigenomics-glow: rgba(219, 39, 119, 0.35);

  /* Fixed width, not swapped by theme -- the nav pane's own surface color
     already reads correctly in both themes via --app-surface below. */
  --nav-pane-width: 224px;

  --led-ok-bg: #dff6dd;
  --led-warn-bg: #fff4ce;
  --led-crit-bg: #fde7e9;
  --led-off-bg: #edebe9;

  /* Card/table content leans on --app-shadow-sm (a hairline lift, not a
     real drop shadow) plus their own 1px border for definition against
     the page background -- a stacked page of bare sections with no
     shadow at all read as one undifferentiated block, confirmed live.
     --app-shadow (heavier, softer/more diffuse) stays reserved for
     genuinely floating macOS-style chrome (dropdowns, the command
     palette sheet, toasts) -- a bigger, airier jump than any
     page content should have. */
  --app-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 1px rgba(0, 0, 0, 0.04);
  --app-shadow: 0 6.4px 14.4px rgba(0, 0, 0, 0.132), 0 1.2px 3.6px rgba(0, 0, 0, 0.108);
  --app-surface: #ffffff;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --bs-body-bg: #1e1e1e;
    --bs-body-color: #f5f5f7;
    --bs-border-color: #38383a;
    --bs-primary: #0a84ff;
    --bs-primary-rgb: 10, 132, 255;
    --bs-link-color: #0a84ff;
    --bs-link-color-rgb: 10, 132, 255;
    --bs-link-hover-color: #409cff;
    --bs-link-hover-color-rgb: 64, 156, 255;
    --bs-info: #64d2ff;
    --bs-info-rgb: 100, 210, 255;
    --bs-danger: #ff453a;
    --bs-danger-rgb: 255, 69, 58;
    --bs-warning: #ff9f0a;
    --bs-warning-rgb: 255, 159, 10;
    --bs-success: #30d158;
    --bs-success-rgb: 48, 209, 88;
    --bs-secondary: #98989d;
    --bs-secondary-rgb: 152, 152, 157;
    --signal-dim: #409cff;
    --accent-soft: #102540;
    --accent-soft-ink: #64b5ff;
    --vibrancy-bg: rgba(30, 30, 32, 0.72);
    --vibrancy-border: rgba(255, 255, 255, 0.08);
    --led-ok-bg: #14301b;
    --led-warn-bg: #3a2e12;
    --led-crit-bg: #3a1f20;
    --led-off-bg: #2b2a29;
    --engine-folding-soft: #2a1f3d;
    --engine-folding-ink: #c4b5fd;
    --engine-ngs-soft: #0e2e33;
    --engine-ngs-ink: #67e8f9;
    --engine-variants-soft: #3a2a12;
    --engine-variants-ink: #fbbf24;
    --engine-rna-soft: #0e2e22;
    --engine-rna-ink: #6ee7b7;
    --engine-folding-a: #5b21b6;
    --engine-folding-b: #7c3aed;
    --engine-folding-a-rgb: 91, 33, 182;
    --engine-folding-glow: rgba(91, 33, 182, 0.45);
    --engine-ngs-a: #0e5f73;
    --engine-ngs-b: #0891b2;
    --engine-ngs-a-rgb: 14, 95, 115;
    --engine-ngs-glow: rgba(14, 95, 115, 0.45);
    --engine-variants-a: #7c3a06;
    --engine-variants-b: #b45309;
    --engine-variants-a-rgb: 124, 58, 6;
    --engine-variants-glow: rgba(124, 58, 6, 0.45);
    --engine-rna-a: #065f46;
    --engine-rna-b: #059669;
    --engine-rna-a-rgb: 6, 95, 70;
    --engine-rna-glow: rgba(6, 95, 70, 0.45);
    --engine-metagenomics-soft: #1a2e05;
    --engine-metagenomics-ink: #bef264;
    --engine-metagenomics-a: #3f6212;
    --engine-metagenomics-b: #65a30d;
    --engine-metagenomics-a-rgb: 63, 98, 18;
    --engine-metagenomics-glow: rgba(63, 98, 18, 0.45);
    --engine-epigenomics-soft: #500724;
    --engine-epigenomics-ink: #f9a8d4;
    --engine-epigenomics-a: #9d174d;
    --engine-epigenomics-b: #db2777;
    --engine-epigenomics-a-rgb: 157, 23, 77;
    --engine-epigenomics-glow: rgba(157, 23, 77, 0.45);
    --app-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 1px rgba(0, 0, 0, 0.3);
    --app-shadow: 0 6.4px 14.4px rgba(0, 0, 0, 0.36), 0 1.2px 3.6px rgba(0, 0, 0, 0.32);
    --app-surface: #2d2d2d;
  }
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --bs-body-bg: #1e1e1e;
  --bs-body-color: #f5f5f7;
  --bs-border-color: #38383a;
  --bs-primary: #0a84ff;
  --bs-primary-rgb: 10, 132, 255;
  --bs-link-color: #0a84ff;
  --bs-link-color-rgb: 10, 132, 255;
  --bs-link-hover-color: #409cff;
  --bs-link-hover-color-rgb: 64, 156, 255;
  --bs-info: #64d2ff;
  --bs-info-rgb: 100, 210, 255;
  --bs-danger: #ff453a;
  --bs-danger-rgb: 255, 69, 58;
  --bs-warning: #ff9f0a;
  --bs-warning-rgb: 255, 159, 10;
  --bs-success: #30d158;
  --bs-success-rgb: 48, 209, 88;
  --bs-secondary: #98989d;
  --bs-secondary-rgb: 152, 152, 157;
  --signal-dim: #409cff;
  --accent-soft: #102540;
  --accent-soft-ink: #64b5ff;
  --vibrancy-bg: rgba(30, 30, 32, 0.72);
  --vibrancy-border: rgba(255, 255, 255, 0.08);
  --led-ok-bg: #14301b;
  --led-warn-bg: #3a2e12;
  --led-crit-bg: #3a1f20;
  --led-off-bg: #2b2a29;
  --engine-folding-soft: #2a1f3d;
  --engine-folding-ink: #c4b5fd;
  --engine-ngs-soft: #0e2e33;
  --engine-ngs-ink: #67e8f9;
  --engine-variants-soft: #3a2a12;
  --engine-variants-ink: #fbbf24;
  --engine-rna-soft: #0e2e22;
  --engine-rna-ink: #6ee7b7;
  --engine-folding-a: #5b21b6;
  --engine-folding-b: #7c3aed;
  --engine-folding-a-rgb: 91, 33, 182;
  --engine-folding-glow: rgba(91, 33, 182, 0.45);
  --engine-ngs-a: #0e5f73;
  --engine-ngs-b: #0891b2;
  --engine-ngs-a-rgb: 14, 95, 115;
  --engine-ngs-glow: rgba(14, 95, 115, 0.45);
  --engine-variants-a: #7c3a06;
  --engine-variants-b: #b45309;
  --engine-variants-a-rgb: 124, 58, 6;
  --engine-variants-glow: rgba(124, 58, 6, 0.45);
  --engine-rna-a: #065f46;
  --engine-rna-b: #059669;
  --engine-rna-a-rgb: 6, 95, 70;
  --engine-rna-glow: rgba(6, 95, 70, 0.45);
  --engine-metagenomics-soft: #1a2e05;
  --engine-metagenomics-ink: #bef264;
  --engine-metagenomics-a: #3f6212;
  --engine-metagenomics-b: #65a30d;
  --engine-metagenomics-a-rgb: 63, 98, 18;
  --engine-metagenomics-glow: rgba(63, 98, 18, 0.45);
  --engine-epigenomics-soft: #500724;
  --engine-epigenomics-ink: #f9a8d4;
  --engine-epigenomics-a: #9d174d;
  --engine-epigenomics-b: #db2777;
  --engine-epigenomics-a-rgb: 157, 23, 77;
  --engine-epigenomics-glow: rgba(157, 23, 77, 0.45);
  --app-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4), 0 1px 1px rgba(0, 0, 0, 0.3);
  --app-shadow: 0 6.4px 14.4px rgba(0, 0, 0, 0.36), 0 1.2px 3.6px rgba(0, 0, 0, 0.32);
  --app-surface: #2d2d2d;
}
:root[data-theme="light"] {
  color-scheme: light;
  --bs-body-bg: #f5f5f7;
  --bs-body-color: #1d1d1f;
  --bs-border-color: #d2d2d7;
  --bs-primary: #007aff;
  --bs-primary-rgb: 0, 122, 255;
  --bs-info: #0a84ff;
  --bs-info-rgb: 10, 132, 255;
  --bs-link-color: #007aff;
  --bs-link-color-rgb: 0, 122, 255;
  --bs-link-hover-color: #0060cc;
  --bs-link-hover-color-rgb: 0, 96, 204;
  --bs-danger: #ff3b30;
  --bs-danger-rgb: 255, 59, 48;
  --bs-warning: #ff9500;
  --bs-warning-rgb: 255, 149, 0;
  --bs-success: #34c759;
  --bs-success-rgb: 52, 199, 89;
  --bs-secondary: #6e6e73;
  --bs-secondary-rgb: 110, 110, 115;
  --signal-dim: #0060cc;
  --accent-soft: #e8f2ff;
  --accent-soft-ink: #0060cc;
  --vibrancy-bg: rgba(246, 246, 248, 0.78);
  --vibrancy-border: rgba(0, 0, 0, 0.08);
  --led-ok-bg: #dff6dd;
  --led-warn-bg: #fff4ce;
  --led-crit-bg: #fde7e9;
  --led-off-bg: #edebe9;
  --engine-folding-soft: #f3ecfd;
  --engine-folding-ink: #5b21b6;
  --engine-ngs-soft: #e6f7fa;
  --engine-ngs-ink: #0e7490;
  --engine-variants-soft: #fdf3e0;
  --engine-variants-ink: #92400e;
  --engine-rna-soft: #e3f8ef;
  --engine-rna-ink: #047857;
  --engine-metagenomics-soft: #f7fee7;
  --engine-metagenomics-ink: #3f6212;
  --engine-epigenomics-soft: #fdf2f8;
  --engine-epigenomics-ink: #9d174d;
  --engine-folding-a: #7c3aed;
  --engine-folding-b: #a855f7;
  --engine-folding-a-rgb: 124, 58, 237;
  --engine-folding-glow: rgba(124, 58, 237, 0.35);
  --engine-ngs-a: #0891b2;
  --engine-ngs-b: #22d3ee;
  --engine-ngs-a-rgb: 8, 145, 178;
  --engine-ngs-glow: rgba(8, 145, 178, 0.35);
  --engine-variants-a: #b45309;
  --engine-variants-b: #f59e0b;
  --engine-variants-a-rgb: 180, 83, 9;
  --engine-variants-glow: rgba(180, 83, 9, 0.35);
  --engine-rna-a: #059669;
  --engine-rna-b: #34d399;
  --engine-rna-a-rgb: 5, 150, 105;
  --engine-rna-glow: rgba(5, 150, 105, 0.35);
  --engine-metagenomics-a: #65a30d;
  --engine-metagenomics-b: #a3e635;
  --engine-metagenomics-a-rgb: 101, 163, 13;
  --engine-metagenomics-glow: rgba(101, 163, 13, 0.35);
  --engine-epigenomics-a: #db2777;
  --engine-epigenomics-b: #f472b6;
  --engine-epigenomics-a-rgb: 219, 39, 119;
  --engine-epigenomics-glow: rgba(219, 39, 119, 0.35);
  --app-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 1px rgba(0, 0, 0, 0.04);
  --app-shadow: 0 6.4px 14.4px rgba(0, 0, 0, 0.132), 0 1.2px 3.6px rgba(0, 0, 0, 0.108);
  --app-surface: #ffffff;
}

/* Full-page brand scoping: application.html.erb stamps .app-content with
   data-engine="folding|ngs|variants|rna" (via #current_engine_key, keyed
   off the same path prefixes _nav_pane.html.erb uses for its own active
   link) whenever the current request is inside one engine's own routes.
   Re-pointing --bs-primary/--accent-soft* here means every page inside
   that engine -- buttons, links, focus rings, badges that lean on these
   tokens -- picks up its brand color for free, with no per-engine
   stylesheet changes. Left unscoped (dashboard, settings, admin) still
   get the platform's own blue. */
.app-content[data-engine="folding"] {
  --bs-primary: var(--engine-folding-a);
  --bs-primary-rgb: var(--engine-folding-a-rgb);
  --bs-link-color: var(--engine-folding-a);
  --bs-link-color-rgb: var(--engine-folding-a-rgb);
  --bs-link-hover-color: var(--engine-folding-b);
  --signal-dim: var(--engine-folding-a);
  --accent-soft: var(--engine-folding-soft);
  --accent-soft-ink: var(--engine-folding-ink);
}
.app-content[data-engine="ngs"] {
  --bs-primary: var(--engine-ngs-a);
  --bs-primary-rgb: var(--engine-ngs-a-rgb);
  --bs-link-color: var(--engine-ngs-a);
  --bs-link-color-rgb: var(--engine-ngs-a-rgb);
  --bs-link-hover-color: var(--engine-ngs-b);
  --signal-dim: var(--engine-ngs-a);
  --accent-soft: var(--engine-ngs-soft);
  --accent-soft-ink: var(--engine-ngs-ink);
}
.app-content[data-engine="variants"] {
  --bs-primary: var(--engine-variants-a);
  --bs-primary-rgb: var(--engine-variants-a-rgb);
  --bs-link-color: var(--engine-variants-a);
  --bs-link-color-rgb: var(--engine-variants-a-rgb);
  --bs-link-hover-color: var(--engine-variants-b);
  --signal-dim: var(--engine-variants-a);
  --accent-soft: var(--engine-variants-soft);
  --accent-soft-ink: var(--engine-variants-ink);
}
.app-content[data-engine="rna"] {
  --bs-primary: var(--engine-rna-a);
  --bs-primary-rgb: var(--engine-rna-a-rgb);
  --bs-link-color: var(--engine-rna-a);
  --bs-link-color-rgb: var(--engine-rna-a-rgb);
  --bs-link-hover-color: var(--engine-rna-b);
  --signal-dim: var(--engine-rna-a);
  --accent-soft: var(--engine-rna-soft);
  --accent-soft-ink: var(--engine-rna-ink);
}
.app-content[data-engine="metagenomics"] {
  --bs-primary: var(--engine-metagenomics-a);
  --bs-primary-rgb: var(--engine-metagenomics-a-rgb);
  --bs-link-color: var(--engine-metagenomics-a);
  --bs-link-color-rgb: var(--engine-metagenomics-a-rgb);
  --bs-link-hover-color: var(--engine-metagenomics-b);
  --signal-dim: var(--engine-metagenomics-a);
  --accent-soft: var(--engine-metagenomics-soft);
  --accent-soft-ink: var(--engine-metagenomics-ink);
}
.app-content[data-engine="epigenomics"] {
  --bs-primary: var(--engine-epigenomics-a);
  --bs-primary-rgb: var(--engine-epigenomics-a-rgb);
  --bs-link-color: var(--engine-epigenomics-a);
  --bs-link-color-rgb: var(--engine-epigenomics-a-rgb);
  --bs-link-hover-color: var(--engine-epigenomics-b);
  --signal-dim: var(--engine-epigenomics-a);
  --accent-soft: var(--engine-epigenomics-soft);
  --accent-soft-ink: var(--engine-epigenomics-ink);
}

body {
  min-height: 100vh;
  font-size: 1rem;
}

h1, .h3, h2, .h4, .h6 {
  letter-spacing: -0.01em;
  font-weight: 600;
}

/* ---------- app shell: nav pane + content column ---------- */
.app-shell {
  display: flex;
  min-height: 100vh;
}

/* flex:1 regardless of auth state -- when signed out there's no .nav-pane
   sibling, so this alone fills the row; the login page's own centering
   (.login-page) is unaffected, it just renders one level deeper. */
.app-content {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* Page content itself (main > .container-fluid) is otherwise unbounded
   width -- fine on a laptop, but on a real wide desktop monitor tables/
   forms/activity rows stretch edge-to-edge, spreading related content
   so far apart it stops reading as organized sections at all. Capped
   and centered instead, same "readable measure" reasoning as any
   article/text layout, just wide enough that this app's own
   many-column tables (VariantLens tier tables in particular) aren't
   cramped. */
.app-content > main > .container-fluid {
  max-width: 1560px;
  margin-inline: auto;
}

/* ---------- nav pane: macOS sidebar (Finder/Mail/Notes) ---------- */
/* Fixed-width, full-height, persistent -- the one piece of chrome on every
   authenticated page. Translucent "vibrancy" material (backdrop-filter
   blur over a semi-opaque tint) is the signature of a native macOS
   sidebar -- page content scrolling behind it should show through,
   softened, not be fully hidden by a flat opaque panel. */
.nav-pane {
  width: var(--nav-pane-width);
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  height: 100vh;
  position: sticky;
  top: 0;
  background-color: var(--vibrancy-bg);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  border-right: 1px solid var(--vibrancy-border);
}

/* Extra top padding -- not decorative filler, it's the space a real macOS
   window reserves above sidebar content for its traffic-light window
   controls (this being a browser tab, there are none to draw, but leaving
   their room is what actually reads as "native window chrome" rather than
   a plain flat panel). */
.nav-pane-header {
  padding: 2.1rem 1rem 0.85rem;
}

.nav-pane-brand {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--bs-body-color);
  text-decoration: none;
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  opacity: 0.6;
}

.nav-pane-brand svg {
  color: var(--bs-primary);
  flex-shrink: 0;
}

/* Shown next to the LOCUS wordmark -- every pipeline here runs against
   synthetic/de-identified data only (see each report's own disclaimer
   text), and this keeps that visible at a glance, not just in fine
   print. Styled like a rubber ink stamp (double ring, rotated, open
   background) rather than a flat pill badge, so it actually reads as
   "stamped on" instead of blending in as just another UI chip. */
.demo-badge {
  display: inline-block;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--bs-warning);
  background: transparent;
  border: 1.5px solid var(--bs-warning);
  border-radius: 4px;
  outline: 1px solid var(--bs-warning);
  outline-offset: 2px;
  padding: 0.15rem 0.4rem;
  vertical-align: middle;
  line-height: 1.2;
  transform: rotate(-6deg);
}

/* ---------- sidebar list (Dashboard / Folding / NGS / Variants / RNA) ---------- */
/* One consistent macOS sidebar list -- compact rows (~30px), a small
   rounded-square icon glyph per item, a soft tinted-pill selection state.
   Same list treatment for Dashboard and the 4 engines (no more a separate
   "engine grid" of full-bleed color tiles -- that read as 4 giant buttons,
   not a sidebar); each engine still keeps its own identity via its icon
   chip's color and its selected-row tint. */
.nav-pane-links {
  flex: 1 1 auto;
  padding: 0.4rem 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-height: 0;
  overflow-y: auto;
}

.nav-pane-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--bs-body-color);
  text-decoration: none;
  font-size: 0.9375rem;
  font-weight: 500;
  padding: 0.5rem 0.7rem;
  border-radius: var(--bs-border-radius-sm);
}

.nav-pane-link-icon {
  flex-shrink: 0;
  width: 26px;
  height: 26px;
  border-radius: 7px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: var(--bs-secondary);
}

.nav-pane-link-icon i {
  font-size: 0.875rem;
}

.nav-pane-link-label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav-pane-link:hover {
  background-color: rgba(0, 0, 0, 0.05);
}
:root[data-theme="dark"] .nav-pane-link:hover {
  background-color: rgba(255, 255, 255, 0.08);
}
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .nav-pane-link:hover {
    background-color: rgba(255, 255, 255, 0.08);
  }
}

.nav-pane-link.active {
  font-weight: 600;
  background-color: var(--nav-active-tint, var(--accent-soft));
}

.nav-pane-link-folding { --nav-active-tint: var(--engine-folding-soft); }
.nav-pane-link-ngs { --nav-active-tint: var(--engine-ngs-soft); }
.nav-pane-link-variants { --nav-active-tint: var(--engine-variants-soft); }
.nav-pane-link-rna { --nav-active-tint: var(--engine-rna-soft); }
.nav-pane-link-metagenomics { --nav-active-tint: var(--engine-metagenomics-soft); }
.nav-pane-link-epigenomics { --nav-active-tint: var(--engine-epigenomics-soft); }

/* Icon chips stay colored regardless of active state -- a sidebar's icons
   (Mail's colored mailboxes, Notes' folders) are how each row is
   identified at a glance even before you've selected it. */
.nav-pane-link-folding .nav-pane-link-icon { background: linear-gradient(135deg, var(--engine-folding-a), var(--engine-folding-b)); }
.nav-pane-link-ngs .nav-pane-link-icon { background: linear-gradient(135deg, var(--engine-ngs-a), var(--engine-ngs-b)); }
.nav-pane-link-variants .nav-pane-link-icon { background: linear-gradient(135deg, var(--engine-variants-a), var(--engine-variants-b)); }
.nav-pane-link-rna .nav-pane-link-icon { background: linear-gradient(135deg, var(--engine-rna-a), var(--engine-rna-b)); }
.nav-pane-link-metagenomics .nav-pane-link-icon { background: linear-gradient(135deg, var(--engine-metagenomics-a), var(--engine-metagenomics-b)); }
.nav-pane-link-epigenomics .nav-pane-link-icon { background: linear-gradient(135deg, var(--engine-epigenomics-a), var(--engine-epigenomics-b)); }

.nav-pane-section-label {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--bs-secondary);
  padding: 0.9rem 0.65rem 0.3rem;
}

/* ---------- nav pane footer: user / platform menu ---------- */
.nav-pane-footer {
  padding: 0.6rem;
  border-top: 1px solid var(--vibrancy-border);
}

.nav-pane-user {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 0.65rem;
  background: none;
  border: none;
  padding: 0.5rem;
  border-radius: var(--bs-border-radius-sm);
  text-align: left;
}

.nav-pane-user:hover {
  background-color: var(--bs-body-bg);
}

.nav-pane-user-info {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}

.nav-pane-user-email {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--bs-body-color);
}

.nav-pane-user-org {
  font-size: 0.8125rem;
  color: var(--bs-secondary);
}

/* Bootstrap's own dropdown component, restyled as a small card -- dropup
   since the trigger is pinned to the pane's bottom edge. */
.nav-pane .dropdown-menu {
  width: 16rem;
  padding: 0.5rem;
  border-radius: var(--bs-border-radius);
  border-color: var(--bs-border-color);
  box-shadow: var(--app-shadow);
  font-size: 0.9375rem;
}

.nav-pane .dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.55rem 0.65rem;
  border-radius: var(--bs-border-radius-sm);
  font-size: 0.9375rem;
}

.nav-pane .dropdown-item i {
  font-size: 1rem;
  opacity: 0.75;
  flex-shrink: 0;
}

.nav-pane .dropdown-item.active {
  background-color: var(--bs-primary);
  color: #fff;
}

.nav-pane .dropdown-item.text-danger:hover {
  background-color: var(--led-crit-bg);
}

.avatar-trigger {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  background-color: var(--bs-primary);
  color: #fff;
  border: none;
  display: grid;
  place-items: center;
  font-size: 0.8rem;
  font-weight: 700;
  flex-shrink: 0;
}

@media (max-width: 767.98px) {
  .nav-pane {
    width: 64px;
  }
  .nav-pane-brand span:not(.demo-badge), .nav-pane-link-label, .nav-pane-section-label,
  .nav-pane-user-info, .demo-badge {
    display: none;
  }
  .nav-pane-link {
    justify-content: center;
    padding: 0.5rem;
  }
}

/* ---------- command bar: macOS unified toolbar ---------- */
/* A slim translucent strip at the top of the content column, same vibrancy
   material as the sidebar -- a native macOS window's toolbar and sidebar
   share one continuous piece of glass, not two different opaque panels. */
.command-bar {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  background-color: var(--vibrancy-bg);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid var(--vibrancy-border);
  padding: 0.65rem 1.5rem;
  position: sticky;
  top: 0;
  z-index: 1015;
}

.command-bar .breadcrumb {
  margin: 0;
  font-size: 0.9rem;
}

.command-bar .breadcrumb-item {
  color: var(--bs-secondary);
}

.command-bar .breadcrumb-item a {
  color: var(--bs-secondary);
  text-decoration: none;
}

.command-bar .breadcrumb-item a:hover {
  color: var(--bs-body-color);
}

.command-bar .breadcrumb-item + .breadcrumb-item::before {
  color: var(--bs-border-color);
}

.command-bar .breadcrumb-item.active {
  color: var(--bs-body-color);
  font-weight: 600;
}

/* ---------- jump-to / command palette trigger ---------- */
/* macOS's own search field convention: a soft filled pill (not a bordered
   box), fully rounded ends, magnifying glass leading the placeholder. */
.jump-trigger {
  flex: 1 1 auto;
  max-width: 22rem;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  background-color: rgba(0, 0, 0, 0.05);
  border: none;
  border-radius: 999px;
  padding: 0.4rem 0.85rem;
  color: var(--bs-secondary);
  font-size: 0.8125rem;
}

:root[data-theme="dark"] .jump-trigger { background-color: rgba(255, 255, 255, 0.09); }
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .jump-trigger { background-color: rgba(255, 255, 255, 0.09); }
}

.jump-trigger:hover {
  background-color: rgba(0, 0, 0, 0.08);
  color: var(--bs-body-color);
}
:root[data-theme="dark"] .jump-trigger:hover { background-color: rgba(255, 255, 255, 0.14); }
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) .jump-trigger:hover { background-color: rgba(255, 255, 255, 0.14); }
}

.jump-trigger .jump-label {
  flex: 1 1 auto;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.jump-trigger kbd {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  background-color: var(--app-surface);
  border: 1px solid var(--bs-border-color);
  border-radius: 4px;
  padding: 0.05rem 0.4rem;
  color: var(--bs-secondary);
}

@media (max-width: 767.98px) {
  .jump-trigger .jump-label, .jump-trigger kbd { display: none; }
  .jump-trigger { max-width: none; flex: 0 0 auto; padding: 0.5rem; }
  .command-bar .breadcrumb { display: none; }
}

.topbar-icon-btn {
  background: none;
  border: none;
  color: var(--bs-body-color);
  padding: 0.35rem 0.45rem;
  border-radius: var(--bs-border-radius-sm);
  line-height: 1;
  flex-shrink: 0;
}

.topbar-icon-btn:hover {
  background-color: var(--bs-body-bg);
}

/* ---------- command palette (Bootstrap modal, see _command_palette.html.erb) ---------- */
.command-palette .modal-content {
  border-radius: var(--bs-border-radius-lg);
  border-color: var(--bs-border-color);
  overflow: hidden;
}

.cp-input-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 1rem 1.1rem;
  border-bottom: 1px solid var(--bs-border-color);
}

.cp-input-row i {
  color: var(--bs-secondary);
}

.cp-input {
  flex: 1 1 auto;
  border: none;
  outline: none;
  background: none;
  font-size: 1.0625rem;
  color: var(--bs-body-color);
}

.cp-input-row kbd {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  background-color: var(--bs-body-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 4px;
  padding: 0.1rem 0.4rem;
  color: var(--bs-secondary);
}

.cp-body {
  max-height: 22rem;
  overflow-y: auto;
  padding: 0.5rem;
}

.cp-group-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--bs-secondary);
  font-weight: 700;
  padding: 0.5rem 0.6rem 0.3rem;
}

.cp-result {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.6rem 0.65rem;
  border-radius: var(--bs-border-radius-sm);
  color: var(--bs-body-color);
  text-decoration: none;
  font-size: 0.9375rem;
}

.cp-result:hover, .cp-result.cp-highlight {
  background-color: var(--accent-soft);
}

.cp-result i {
  color: var(--bs-secondary);
  flex-shrink: 0;
}

/* One color per engine, keyed off the same bi-* icon class every result
   of that type already carries (dynamic results from SearchController via
   command_palette_controller.js, and the static "Go to" quick links
   above them) -- these render outside .app-content, so the
   [data-engine="..."] scoping that recolors --bs-primary per engine
   elsewhere never reaches them; every result used the same flat
   --bs-primary here regardless of which engine it belonged to. Dashboard's
   own bi-grid-1x2 quick link isn't an engine, so it keeps the neutral
   color above instead of getting one of its own. */
.cp-result i.bi-diagram-3, .cp-result i.bi-diagram-2 {
  color: var(--engine-folding-a);
}
.cp-result i.bi-clipboard-data {
  color: var(--engine-ngs-a);
}
.cp-result i.bi-file-earmark-medical {
  color: var(--engine-variants-a);
}
.cp-result i.bi-clipboard2-pulse {
  color: var(--engine-rna-a);
}
.cp-result i.bi-bug-fill {
  color: var(--engine-metagenomics-a);
}
.cp-result i.bi-toggle2-on {
  color: var(--engine-epigenomics-a);
}

.cp-result-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cp-result-sub {
  color: var(--bs-secondary);
  font-size: 0.8125rem;
  flex-shrink: 0;
}

.cp-empty {
  padding: 1.5rem;
  text-align: center;
  color: var(--bs-secondary);
  font-size: 0.9rem;
}

/* ---------- per-page "what can I do here?" help trigger ---------- */
.page-help-trigger {
  font-size: 0.875rem;
  color: var(--bs-secondary);
  text-decoration: underline;
  text-decoration-style: dashed;
  text-underline-offset: 3px;
  white-space: nowrap;
}

.page-help-trigger:hover {
  color: var(--bs-primary);
}

.page-help-trigger i {
  font-size: 0.9rem;
}

/* Bootstrap appends the popover element as a sibling wherever Popper.js
   decides to mount it (not as a descendant of the trigger), so this can't
   be scoped under .page-help-trigger -- fine in practice, since page_help
   is the only Popover this app uses. */
.popover {
  max-width: 22rem;
  font-size: 0.9375rem;
  border-color: var(--bs-border-color);
  box-shadow: var(--app-shadow-sm);
}

.popover-body strong {
  color: var(--brand-dark);
}

.popover-body ul {
  padding-left: 1.1rem;
}

.popover-body p:last-child,
.popover-body ul:last-child {
  margin-bottom: 0;
}

/* Bootstrap's .text-bg-info hardcodes black text, tuned for its default
   light cyan -- unreadable against the more saturated blue --bs-info is
   repurposed as here. background-color is left alone (it already reads
   var(--bs-info-rgb), so it re-themes correctly on its own). */
.text-bg-info {
  color: #fff !important;
}

.card {
  border-color: var(--bs-border-color);
  box-shadow: var(--app-shadow-sm);
  border-radius: var(--bs-border-radius);
}

.card .card {
  border-left: none;
  border-right: none;
  border-bottom: none;
  box-shadow: none;
}

/* Native <details>/<summary> disclosures (e.g. a run's "All steps") drop
   their default marker via list-style: none so the row lines up with the
   rest of the page, but that also removes the only built-in signal that
   the row is clickable -- a CSS-drawn chevron replaces it, rotating open
   the same way a real disclosure triangle would. currentColor/opacity
   instead of a fixed hex so it reads correctly against any text color,
   light or dark theme, with no separate dark-mode rule needed. */
.disclosure-summary {
  cursor: pointer;
}

.disclosure-summary::before {
  content: "";
  display: inline-block;
  width: 0;
  height: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
  border-left: 6px solid currentColor;
  opacity: 0.6;
  margin-right: 0.5rem;
  vertical-align: middle;
  transition: transform 0.15s ease;
}

details[open] > .disclosure-summary::before {
  transform: rotate(90deg);
}

.btn {
  border-radius: var(--bs-border-radius-sm);
  font-weight: 600;
  font-size: 0.9375rem;
}

.btn-primary {
  --bs-btn-bg: var(--bs-primary);
  --bs-btn-border-color: var(--bs-primary);
  --bs-btn-hover-bg: var(--signal-dim);
  --bs-btn-hover-border-color: var(--signal-dim);
}

.table {
  --bs-table-hover-bg: var(--bs-body-bg);
  font-size: 1rem;
}

/* Bootstrap's .table-light (used for header rows across every engine)
   hardcodes a fixed light-gray background regardless of theme -- swap it
   for the real theme tokens so table headers actually go dark in dark
   mode instead of staying a stray white/light band. */
.table-light {
  --bs-table-bg: var(--bs-body-bg);
  --bs-table-color: var(--bs-body-color);
  --bs-table-border-color: var(--bs-border-color);
}

.table > :not(caption) > * > * {
  padding: 0.75rem 0.9rem;
}

/* Explorer-"Details view"-style sortable column header (see each engine's
   ApplicationHelper#sortable_column) -- a plain link until it's the active
   sort column, then it gets weight + the accent color so the small ▲/▼
   arrow reads as "this is how the list is ordered right now," not just
   another link. */
.sortable-th {
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
}

.sortable-th:hover {
  color: var(--bs-primary);
}

.sortable-th.active {
  color: var(--bs-primary);
  font-weight: 700;
}

.status-badge {
  text-transform: uppercase;
  font-weight: 700;
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  border-radius: 999px;
  padding: 0.3rem 0.7rem;
}

.sequence-mono {
  font-family: var(--font-mono);
  font-size: 0.9375rem;
  word-break: break-all;
}

/* ---------- LED status indicator (icon+label+color, never color alone) ---------- */
.led {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font-size: 0.875rem;
  font-weight: 600;
}

.led i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  display: inline-block;
  flex-shrink: 0;
}

.led-ok { color: var(--bs-success); }
.led-ok i { background-color: var(--bs-success); box-shadow: 0 0 0 3px var(--led-ok-bg); }
.led-warn { color: var(--bs-warning); }
.led-warn i { background-color: var(--bs-warning); box-shadow: 0 0 0 3px var(--led-warn-bg); }
.led-crit { color: var(--bs-danger); }
.led-crit i { background-color: var(--bs-danger); box-shadow: 0 0 0 3px var(--led-crit-bg); }
.led-off { color: var(--bs-secondary); }
.led-off i { background-color: var(--bs-secondary); box-shadow: 0 0 0 3px var(--led-off-bg); }

/* ---------- dashboard ---------- */
.readout {
  border: 1px solid var(--vibrancy-border);
  border-radius: var(--bs-border-radius-lg);
  background-color: var(--app-surface);
  box-shadow: var(--app-shadow-sm);
  padding: 1.25rem 1.5rem;
  margin-bottom: 1.75rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
}

.readout-label {
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--bs-secondary);
}

.readout-org {
  font-size: 1.25rem;
  font-weight: 700;
  margin-top: 0.15rem;
}

.readout-stat {
  text-align: right;
  text-decoration: none;
  color: inherit;
}

.readout-stat .num {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 1.5rem;
  color: var(--bs-primary);
}

.readout-stat .lbl {
  font-size: 0.8125rem;
  color: var(--bs-secondary);
  font-weight: 600;
}

.deck-label {
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--bs-secondary);
  font-weight: 700;
  margin-bottom: 0.85rem;
}

/* Engine cards -- clean card with a soft shadow that lifts on hover, the
   primary way to enter an engine since there's no side nav. */
.modules {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.1rem;
  margin-bottom: 2.5rem;
}

@media (max-width: 900px) {
  .modules { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .modules { grid-template-columns: 1fr; }
}

/* No top brand stripe (a web-card convention, not a macOS one) -- the
   already-glossy colored icon chip below is the one signature brand
   moment per card, matching how a macOS widget or System Settings row
   identifies itself: through its icon, not an edge accent. */
.module-tile {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--vibrancy-border);
  border-radius: var(--bs-border-radius-lg);
  background-color: var(--app-surface);
  box-shadow: var(--app-shadow-sm);
  padding: 1.4rem 1.4rem 1.5rem;
  text-decoration: none;
  color: var(--bs-body-color);
  display: block;
  transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.module-tile:hover {
  box-shadow: var(--app-shadow);
  transform: translateY(-2px);
}

.module-tile-folding:hover { box-shadow: var(--app-shadow), 0 10px 24px -8px var(--engine-folding-glow); }
.module-tile-ngs:hover { box-shadow: var(--app-shadow), 0 10px 24px -8px var(--engine-ngs-glow); }
.module-tile-variants:hover { box-shadow: var(--app-shadow), 0 10px 24px -8px var(--engine-variants-glow); }
.module-tile-rna:hover { box-shadow: var(--app-shadow), 0 10px 24px -8px var(--engine-rna-glow); }
.module-tile-metagenomics:hover { box-shadow: var(--app-shadow), 0 10px 24px -8px var(--engine-metagenomics-glow); }
.module-tile-epigenomics:hover { box-shadow: var(--app-shadow), 0 10px 24px -8px var(--engine-epigenomics-glow); }

.module-tile .bi {
  width: 2.6rem;
  height: 2.6rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.3rem;
  color: var(--accent-soft-ink);
  background-color: var(--accent-soft);
  border-radius: var(--bs-border-radius);
  margin-bottom: 0.9rem;
}

/* Glossy/3D icon chips: a diagonal two-stop gradient in the engine's own
   hue, a bright inset highlight along the top edge (the "glass" look),
   and an outer glow shadow tinted to match -- distinct from the flat,
   shadowless "Fluent" look the rest of this app deliberately uses (see
   the file-header comment), used sparingly here as each engine's one
   signature brand moment. */
.module-tile-folding .bi {
  color: #fff;
  background: linear-gradient(135deg, var(--engine-folding-a), var(--engine-folding-b));
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 4px 10px var(--engine-folding-glow);
}
.module-tile-ngs .bi {
  color: #fff;
  background: linear-gradient(135deg, var(--engine-ngs-a), var(--engine-ngs-b));
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 4px 10px var(--engine-ngs-glow);
}
.module-tile-variants .bi {
  color: #fff;
  background: linear-gradient(135deg, var(--engine-variants-a), var(--engine-variants-b));
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 4px 10px var(--engine-variants-glow);
}
.module-tile-rna .bi {
  color: #fff;
  background: linear-gradient(135deg, var(--engine-rna-a), var(--engine-rna-b));
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 4px 10px var(--engine-rna-glow);
}
.module-tile-metagenomics .bi {
  color: #fff;
  background: linear-gradient(135deg, var(--engine-metagenomics-a), var(--engine-metagenomics-b));
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 4px 10px var(--engine-metagenomics-glow);
}
.module-tile-epigenomics .bi {
  color: #fff;
  background: linear-gradient(135deg, var(--engine-epigenomics-a), var(--engine-epigenomics-b));
  box-shadow: inset 0 1px 1px rgba(255, 255, 255, 0.4), 0 4px 10px var(--engine-epigenomics-glow);
}

.module-name {
  font-size: 1.125rem;
  font-weight: 700;
  margin-bottom: 0.2rem;
}

.module-desc {
  font-size: 0.9rem;
  color: var(--bs-secondary);
  margin-bottom: 1rem;
  line-height: 1.45;
}

.module-stat {
  font-family: var(--font-mono);
  font-size: 1.6rem;
  font-weight: 700;
  line-height: 1;
}

.module-stat-label {
  font-size: 0.8125rem;
  color: var(--bs-secondary);
  font-weight: 600;
}

/* activity log -- macOS "grouped inset list" (Mail's message list, System
   Settings rows): one rounded panel, rows separated by a faint hairline
   rather than each row being its own bordered block. */
.log-panel {
  border: 1px solid var(--vibrancy-border);
  border-radius: var(--bs-border-radius-lg);
  background-color: var(--app-surface);
  box-shadow: var(--app-shadow-sm);
  overflow: hidden;
}

.log-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 1.25rem;
  border-bottom: 1px solid var(--vibrancy-border);
  font-size: 0.9375rem;
  text-decoration: none;
  color: var(--bs-body-color);
}

.log-row:last-child { border-bottom: none; }
.log-row:hover { background-color: var(--bs-body-bg); }

.log-time {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--bs-secondary);
  flex-shrink: 0;
  width: 4.75rem;
}

@media (max-width: 575.98px) {
  /* Narrowest screens: keep the tag, the label, and the LED (the parts
     that actually say what happened) -- drop the exact timestamp and the
     relative "ago" column rather than let the label get truncated to a
     couple of characters. */
  .log-time, .log-row .text-body-secondary.small { display: none; }
}

.log-tag {
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  color: var(--accent-soft-ink);
  background-color: var(--accent-soft);
  border-radius: 4px;
  padding: 0.2rem 0.5rem;
  flex-shrink: 0;
}

.log-tag-folding { color: var(--engine-folding-ink); background-color: var(--engine-folding-soft); }
.log-tag-ngs { color: var(--engine-ngs-ink); background-color: var(--engine-ngs-soft); }
.log-tag-variants { color: var(--engine-variants-ink); background-color: var(--engine-variants-soft); }
.log-tag-rna { color: var(--engine-rna-ink); background-color: var(--engine-rna-soft); }
.log-tag-metagenomics { color: var(--engine-metagenomics-ink); background-color: var(--engine-metagenomics-soft); }
.log-tag-epigenomics { color: var(--engine-epigenomics-ink); background-color: var(--engine-epigenomics-soft); }

.log-label {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Signed-out screens (login) render with no top strip, so centering is
   self-contained here. */
.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.5rem;
  background-color: var(--bs-body-bg);
}

.login-card {
  width: 100%;
  max-width: 52rem;
  background-color: var(--app-surface);
  border-radius: var(--bs-border-radius-lg);
  box-shadow: var(--app-shadow), 0 12px 32px rgba(30, 27, 41, 0.06);
  position: relative;
  z-index: 1;
  display: flex;
  overflow: hidden;
}

.login-brand {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--brand-dark);
  letter-spacing: -0.02em;
}

.login-brand-panel {
  flex: 0 0 40%;
  background-color: var(--brand-dark);
  color: #fff;
  padding: 2.5rem 2rem;
  flex-direction: column;
  justify-content: center;
}

.login-brand-panel .login-brand {
  color: #fff;
}

.login-tagline {
  color: rgba(255, 255, 255, 0.75);
  font-size: 1rem;
  line-height: 1.55;
  margin-bottom: 1.75rem;
}

.login-engine-list li {
  display: flex;
  align-items: baseline;
  gap: 0.65rem;
  padding: 0.6rem 0;
  font-size: 0.9375rem;
  color: rgba(255, 255, 255, 0.85);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.login-engine-list li:first-child {
  border-top: none;
  padding-top: 0;
}

.login-engine-list i {
  color: var(--bs-primary);
  font-size: 1.05rem;
  flex: none;
}

.login-form-panel {
  flex: 1 1 auto;
  min-width: 0;
  padding: 2.5rem 2.25rem;
}

/* Each provider's official button colors, per their own brand guidelines
   -- deliberately not themed off --app-surface/--bs-body-bg like the rest
   of the app, since the whole point is instant brand recognition and
   these are the same fixed colors every "Sign in with X" button uses
   everywhere else on the web, light or dark page alike. */
.btn-oauth {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.65rem;
  font-weight: 500;
}

.btn-oauth-logo {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
}

.btn-oauth-google {
  background-color: #fff;
  border: 1px solid #747775;
  color: #1f1f1f;
}

.btn-oauth-google:hover {
  background-color: #f7f8f8;
  border-color: #747775;
  color: #1f1f1f;
}

.btn-oauth-microsoft {
  background-color: #fff;
  border: 1px solid #8c8c8c;
  color: #5e5e5e;
}

.btn-oauth-microsoft:hover {
  background-color: #f5f5f5;
  border-color: #8c8c8c;
  color: #5e5e5e;
}

.btn-oauth-yahoo {
  background-color: #6001d2;
  border: 1px solid #6001d2;
  color: #fff;
}

.btn-oauth-yahoo:hover {
  background-color: #4e01ac;
  border-color: #4e01ac;
  color: #fff;
}

/* Reserves real space at the bottom of the page for the fixed footer
   below, so it never covers the last bit of page content. */
.has-fixed-footer {
  padding-bottom: 2.75rem;
}

/* ---------- footer (live host CPU/memory) ---------- */
/* position: fixed (not sticky) -- sticky would only pin it once its own
   normal-flow position scrolls into view, which on a short page (most of
   them) never happens; fixed keeps it visibly anchored to the viewport
   bottom regardless of page length. app-body-padding above reserves real
   space so it never covers the last bit of page content. */
.app-footer {
  position: fixed;
  bottom: 0;
  left: var(--nav-pane-width);
  right: 0;
  z-index: 1030;
  border-top: 1px solid var(--vibrancy-border);
  background-color: var(--vibrancy-bg);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  color: var(--bs-secondary);
  font-size: 0.8125rem;
  padding: 0.55rem 0;
}

.app-footer [data-system-stats-target] {
  font-variant-numeric: tabular-nums;
}

/* ---------- chart hover tooltip (see chart_tooltip_controller.js) ---------- */
.chart-tooltip-root {
  position: relative;
}

.chart-tooltip {
  position: absolute;
  pointer-events: none;
  z-index: 5;
  background-color: var(--brand-dark);
  color: #fff;
  font-size: 0.8125rem;
  line-height: 1.35;
  padding: 0.35rem 0.6rem;
  border-radius: var(--bs-border-radius-sm);
  max-width: 20rem;
  white-space: normal;
  box-shadow: var(--app-shadow-sm);
}

/* ---------- interactive density chart (see density_chart_controller.js) ---------- */
/* grab = "you can drag this"; the controller swaps in -dragging (below)
   for the duration of an actual drag, matching the native map/canvas
   panning convention. */
[data-controller~="density-chart"] svg {
  cursor: grab;
}

.density-chart-dragging svg {
  cursor: grabbing;
}

/* ---------- pipeline stepper (shared across every engine) ---------- */
/* Folding/NgsOrchestrator/RnaSeq/VariantLens each render their own copy of
   this same partial shape (e.g. engines/variant_lens/app/views/
   variant_lens/vcf_imports/_pipeline_stepper.html.erb) -- no view code is
   shared between engines by design, but the CSS driving their identical
   markup is pure shared visual language, so it's centralized here once
   instead of duplicated per engine.

   .pipeline-stepper stretches to the full width of its container -- stages
   are flexible, not fixed-width, and a connector line grows to fill
   whatever space is left between them, so the stepper always spans edge to
   edge instead of clumping on the left with empty space to the right. */
.pipeline-stepper {
  display: flex;
  align-items: flex-start;
  width: 100%;
}

.pipeline-stepper-stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  flex: 0 1 10rem;
  min-width: 6.5rem;
}

/* A continuous track between stage circles reads as one progress line
   rather than a repeated arrow glyph, and turns solid once the stage
   behind it is actually done -- so at a glance the line itself shows how
   far the pipeline has gotten, not just each stage's own badge. */
.pipeline-stepper-connector {
  position: relative;
  flex: 1 1 auto;
  min-width: 1.5rem;
  height: 2px;
  margin-top: 1.6rem;
  background-color: var(--bs-border-color);
}

.pipeline-stepper-connector-done {
  background-color: var(--bs-success);
}

.pipeline-stepper-connector-label {
  position: absolute;
  top: 0.5rem;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-size: 0.75rem;
  color: var(--bs-secondary-color);
}

/* Each stage's glyph (see ApplicationHelper#pipeline_step_icon) carries
   its own vivid, step-specific color baked into its SVG markup -- no
   circular badge/background/status-ring around it, deliberately: that
   framing fought with the glyph's own color for attention instead of
   just letting the glyph read as itself. Status is conveyed by the
   badge text already rendered below each icon (Done/In progress/
   Failed/Not started), not by recoloring or ringing the icon itself. */
.pipeline-map-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  margin-bottom: 0.4rem;
  transition: filter 0.15s ease, opacity 0.15s ease;
}

.step-glyph {
  width: 2rem;
  height: 2rem;
}

/* Not started yet -- muted/desaturated so a step's colorful glyph doesn't
   read as "already happened" before its turn. */
.pipeline-map-stage-not_started .pipeline-map-icon,
.pipeline-map-stage-cancelled .pipeline-map-icon {
  filter: grayscale(85%);
  opacity: 0.5;
}

/* A gentle opacity pulse on the in-progress stage's badge, not a hard
   on/off blink -- true blinking is a WCAG 2.2.2 concern (and just
   unpleasant to sit next to on a page that auto-refreshes);
   prefers-reduced-motion turns it off entirely for anyone who's asked
   their OS for that. */
@keyframes pipeline-stage-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

.pipeline-map-stage-in_progress .badge {
  animation: pipeline-stage-pulse 1.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .pipeline-map-stage-in_progress .badge {
    animation: none;
  }
}

/* Elapsed-time readout next to an in-progress stage's badge (see
   elapsed_timer_controller.js) -- one shared host-level controller used
   from every engine's pipeline stepper partial. */
.stage-elapsed {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--bs-secondary);
  margin-top: 0.25rem;
  font-variant-numeric: tabular-nums;
}

/* Real tool/software provenance for a stage -- e.g. "BWA-MEM v0.7.17",
   "ESMFold", "ClinVar" -- deliberately in the mono font (same distinct-
   font convention as .sequence-mono) and the signal accent color, so a
   workflow's actual tool provenance reads as a distinct, technical fact
   next to the plain-English step label, not just more label text.
   .stage-tool is the chip itself, used two ways: (a) bare, wherever a step
   only ever has one real tool (workflow definitions, run/job rows -- no
   click-to-reveal needed, there's nothing to hide), and (b) stacked inside
   the .stage-tools-badge popover below, for pipeline steppers where several
   steps' tool lists used to sit permanently visible under every icon and
   pushed the stepper into a wall of text. */
.stage-tool {
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--accent-soft-ink);
  background-color: var(--accent-soft);
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

/* Pipeline-stepper-only: the always-visible chip list collapses into a
   single click-to-reveal "Tools" badge (stage_tools_controller.js opens a
   Bootstrap Popover on click, populated from .stage-tools-popover-list). */
.stage-tools {
  margin-top: 0.3rem;
}

.stage-tools-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--accent-soft-ink);
  background-color: var(--accent-soft);
  border: none;
  border-radius: 999px;
  padding: 0.15rem 0.6rem;
  cursor: pointer;
}

.stage-tools-badge:hover,
.stage-tools-badge:focus-visible {
  filter: brightness(0.94);
}

.stage-tools-popover-list {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}

.stage-tools-popover-list .stage-tool {
  white-space: normal;
}

/* ---------- cross-engine link (Fluent InfoBar-style) ---------- */
/* One consistent look for every place one engine's page references real
   data in another engine (NGS<->VariantLens, VariantLens<->Folding) --
   previously each of the 4 link points improvised its own treatment (a
   button pair, a plain alert, a buried plain-text line, one card among
   many identical-looking ones), which read as 4 different features rather
   than one real, recurring fact about this app: engines share real data.
   Each engine implements its own markup instance (no shared ERB between
   engines, same standing convention as .pipeline-stepper). */
.cross-engine-link {
  display: flex;
  gap: 0.85rem;
  align-items: flex-start;
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--bs-border-color);
  border-left: 3px solid var(--bs-primary);
  border-radius: var(--bs-border-radius-sm);
  background-color: var(--accent-soft);
}

.cross-engine-link .bi {
  font-size: 1.15rem;
  color: var(--bs-primary);
  flex-shrink: 0;
  margin-top: 0.1rem;
}

/* This callout always names the *other* engine it points to or came from
   ("Auto-triggered from VariantLens", "Ready for VariantLens", "Derived
   from NGS Orchestrator"...) -- so its accent should be that named
   engine's brand color, not whichever engine's page happens to be
   rendering it (which the plain --bs-primary/--accent-soft above would
   give it, now that those tokens are scoped per-engine). Add
   .cross-engine-link--{target} in the view alongside the base class. */
.cross-engine-link--folding { border-left-color: var(--engine-folding-a); background-color: var(--engine-folding-soft); }
.cross-engine-link--folding .bi { color: var(--engine-folding-a); }
.cross-engine-link--ngs { border-left-color: var(--engine-ngs-a); background-color: var(--engine-ngs-soft); }
.cross-engine-link--ngs .bi { color: var(--engine-ngs-a); }
.cross-engine-link--variants { border-left-color: var(--engine-variants-a); background-color: var(--engine-variants-soft); }
.cross-engine-link--variants .bi { color: var(--engine-variants-a); }
.cross-engine-link--rna { border-left-color: var(--engine-rna-a); background-color: var(--engine-rna-soft); }
.cross-engine-link--rna .bi { color: var(--engine-rna-a); }
.cross-engine-link--metagenomics { border-left-color: var(--engine-metagenomics-a); background-color: var(--engine-metagenomics-soft); }
.cross-engine-link--metagenomics .bi { color: var(--engine-metagenomics-a); }
.cross-engine-link--epigenomics { border-left-color: var(--engine-epigenomics-a); background-color: var(--engine-epigenomics-soft); }
.cross-engine-link--epigenomics .bi { color: var(--engine-epigenomics-a); }

.cross-engine-link-body {
  flex: 1 1 auto;
  min-width: 0;
}

.cross-engine-link-title {
  font-weight: 700;
  font-size: 0.9375rem;
  margin-bottom: 0.15rem;
}

.cross-engine-link-desc {
  font-size: 0.875rem;
  color: var(--bs-secondary);
}

/* ---------- form controls: macOS text fields/checkboxes ---------- */
/* A native macOS text field is a flat, softly-bordered box that gains a
   pale blue glow (not a thicker border) when focused -- the same "halo"
   :focus-visible uses globally below, so a focused field and any other
   focused control read as one consistent language. */
.form-control,
.form-select {
  border-color: var(--bs-border-color);
  border-radius: var(--bs-border-radius);
}

.form-control:focus,
.form-select:focus {
  border-color: var(--bs-primary);
  box-shadow: 0 0 0 3.5px rgba(var(--bs-primary-rgb), 0.25);
}

/* accent-color is real, native browser checkbox/radio rendering -- an
   authentic system-blue fill with zero custom widget markup. */
.form-check-input {
  accent-color: var(--bs-primary);
  border-color: var(--bs-border-color);
}

/* ---------- alerts: same Windows InfoBar look as .cross-engine-link ---------- */
/* A flash/validation-error banner is the same "one-line callout" concept
   as .cross-engine-link above -- both get the identical InfoBar treatment
   (thin border + accent-color left bar + soft tint background) instead of
   two different visual languages for what's the same kind of message. */
.alert {
  border: 1px solid var(--bs-border-color);
  border-left: 3px solid var(--bs-primary);
  border-radius: var(--bs-border-radius-sm);
  background-color: var(--accent-soft);
  color: var(--bs-body-color);
}

.alert-danger {
  border-left-color: var(--bs-danger);
}

.alert-success {
  border-left-color: var(--bs-success);
}

.alert-warning {
  border-left-color: var(--bs-warning);
}

/* ---------- macOS focus ring: a soft blue halo, not a hard outline ---------- */
/* Every native macOS control gets the same pale blue glow around it when
   focused (text fields, buttons, checkboxes) -- a soft box-shadow, not a
   crisp offset rectangle. Keeping a (transparent) outline in the rule too
   means Windows High Contrast Mode still gets a real visible outline,
   since forced-colors mode ignores box-shadow entirely. */
:focus-visible {
  outline: 2px solid transparent;
  outline-offset: 1px;
  box-shadow: 0 0 0 4px rgba(var(--bs-primary-rgb), 0.3);
}

/* ---------- Windows/Fluent Pivot-style tabs (see .win-tabs users) ---------- */
/* Bootstrap's nav-tabs restyled toward a WinUI Pivot look -- an underline
   on the selected tab, no boxy tab chrome, larger touch/click targets to
   match this pass's "nothing tiny" rule. */
.win-tabs {
  border-bottom: 1px solid var(--bs-border-color);
  gap: 0.25rem;
  margin-bottom: 1.25rem;
}

.win-tabs .nav-link {
  border: none;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  color: var(--bs-secondary);
  font-weight: 600;
  font-size: 0.9375rem;
  padding: 0.65rem 0.25rem;
  margin-right: 1.5rem;
}

.win-tabs .nav-link:hover {
  color: var(--bs-body-color);
  border-color: var(--bs-border-color);
}

.win-tabs .nav-link.active {
  color: var(--bs-primary);
  background: none;
  border-color: var(--bs-primary);
}

/* ---------- notification/flash toasts ---------- */
/* Pinned to the top-right corner, stacking downward as more arrive. */
.app-toast-container {
  top: auto;
  bottom: 1rem;
  right: 1rem;
  left: auto;
  align-items: flex-end;
}

.app-toast-container .toast {
  min-width: 22rem;
  max-width: min(90vw, 28rem);
  border-radius: var(--bs-border-radius-lg);
  box-shadow: var(--app-shadow);
  overflow: hidden;
  font-size: 0.9375rem;
}

/* Outline style instead of a filled contextual background -- own classes
   rather than Bootstrap's .text-bg-* utilities, since those set
   background-color/color with !important and can't be overridden by a
   more specific selector. Surface-colored header, bordered in a darker
   tint of the variant color, so success/danger read as an accent outline
   rather than a solid color block. */
.app-toast-container .toast-header {
  font-weight: 700;
  background-color: var(--app-surface);
}

.app-toast-container .toast-header-success {
  color: color-mix(in srgb, var(--bs-success) 80%, black);
  border: 1px solid var(--bs-success);
}

.app-toast-container .toast-header-danger {
  color: color-mix(in srgb, var(--bs-danger) 80%, black);
  border: 1px solid var(--bs-danger);
}

.app-toast-container .toast-header-dark {
  color: var(--bs-body-color);
  border: 1px solid var(--bs-border-color);
}

.app-toast-container .toast-body {
  background-color: var(--app-surface);
  color: var(--bs-body-color);
  font-size: 1.0625rem;
  padding: 1rem 1.25rem;
}

/* ---------- notification bell dropdown ---------- */
.notification-dropdown-menu {
  width: 22rem;
  max-width: 90vw;
  border-radius: var(--bs-border-radius-lg);
  box-shadow: var(--app-shadow);
  overflow: hidden;
}

/* Only the message list itself scrolls -- the header and "View all"
   footer stay put instead of scrolling away with it. overflow-x: hidden
   is the actual fix for the horizontal scrollbar long messages used to
   cause; it only ever showed up because .dropdown-item's Bootstrap
   default (white-space: nowrap) fought with .notification-message's own
   wrapping below. */
.notification-list {
  max-height: 22rem;
  overflow-y: auto;
  overflow-x: hidden;
}

.notification-item {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.65rem 1rem;
  white-space: normal;
}

.notification-item:hover {
  background-color: var(--accent-soft);
}

.notification-dot {
  flex-shrink: 0;
  width: 0.5rem;
  height: 0.5rem;
  margin-top: 0.35rem;
  border-radius: 50%;
  background-color: transparent;
}

.notification-item.is-unread .notification-dot {
  background-color: var(--bs-primary);
}

.notification-item.is-unread .notification-message {
  font-weight: 600;
}

/* min-width: 0 is what actually lets a flex child wrap instead of forcing
   the row (and the whole dropdown) wider to fit one unbroken line. */
.notification-body {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
  flex: 1;
}

.notification-message {
  font-size: 0.875rem;
  line-height: 1.35;
  white-space: normal;
  word-break: break-word;
  color: var(--bs-body-color);
}

.notification-time {
  font-size: 0.7rem;
}

/* Folding's phylogenetic tree SVG is a fixed width -- scrolls its own
   container on a narrow viewport instead of overflowing the page. */
.phylo-tree-svg {
  overflow-x: auto;
}
