/* =============================================================================
   StatusPulse — design system (brand v1.1)
   Inter Tight for display + body, plain Inter for the SVG wordmark only,
   JetBrains Mono for numbers.
   Pulse green (primary, buttons, status) + coral/amber/danger (semantic).
   ============================================================================= */

:root {
    /* Text inks — primary + muted come straight from the brand manual; the
       intermediate scale points (ink-2, ink-4) are derived to keep the
       4-tier visual hierarchy the dashboard already relies on. */
    --ink:   #0E1A16;   /* color.text.primary (light)              */
    --ink-2: #2c3935;   /* derived — secondary text                */
    --ink-3: #5A6660;   /* color.text.muted   (light)              */
    --ink-4: #8FA09A;   /* derived — super-muted (footers, hints) */

    /* Surfaces — page-bg straight from brand; secondary surfaces are
       neutral off-white shades that stay readable next to the brand
       greens without competing with them. */
    --paper:   #FFFFFF;  /* color.page.bg (light) */
    --paper-2: #F5F5F2;  /* off-white card surface               */
    --paper-3: #E8E8E2;  /* deeper surface                       */
    --line:   rgba(14, 26, 22, 0.08);
    --line-2: rgba(14, 26, 22, 0.16);

    /* The pulse — primary brand green. Cells, buttons, CTAs, "up" status,
       brand mark. Identical hex in both light and dark per brand manual. */
    --pulse:      #18D883;  /* color.accent           */
    --pulse-soft: #DFF5EB;  /* color.card.bg (light) — green tint behind logo */
    --pulse-ink:  #0F9658;  /* derived — hover/focus, ~30% darker */

    /* Brand incident red — the red cell in the logo. Distinct from the
       semantic --danger below; this is brand chrome, --danger is status. */
    --incident:      #E24B4A;  /* color.incident (light) */
    --incident-soft: #F8DADA;  /* derived */

    /* Brand card surface — the green-tinted box behind the logo mark. Used
       when the platform draws the logo on a non-white background and needs
       to honour the manual's container colour. */
    --brand-card-bg:     #DFF5EB;  /* color.card.bg     (light) */
    --brand-card-border: #AFE8CF;  /* color.card.border (light) */
    --brand-wordmark:    #0E1A16;  /* color.wordmark    (light) */

    /* Coral — warm complement / featured-plan accent. SEMANTIC PLATFORM
       CONSTANT (kept across the v1.1 rebrand): warning orange carries
       status meaning that should not change between platform-default and
       customer-tinted views. */
    --coral:      #ff7a1a;
    --coral-soft: #ffe4d0;
    --coral-ink:  #b44010;

    /* Amber — used sparingly. Same semantic-constant rationale as coral. */
    --amber:      #ba7517;
    --amber-soft: #faeeda;

    /* Danger — outage red. SEMANTIC PLATFORM CONSTANT (same rationale as
       coral above): the brand --incident red is for the logo cell only,
       this red is for "probe is down". */
    --danger:      #a32d2d;
    --danger-soft: #fceaea;

    /* Admin accent — deliberate contrast vs customer UI */
    --admin-ink:  #4a1b0c;
    --admin-soft: #fbe8e1;

    /* Typography — Inter Tight is the platform body/display font (already
       self-hosted via fonts.css). Plain Inter is loaded ALONGSIDE solely
       for fidelity of the SVG wordmark, which the brand manual specifies
       as Inter Medium 500 with letter-spacing -0.5 (decision A in the
       v1.1 migration). --font-brand is referenced by the inline logo
       partial so the wordmark inherits the right family. */
    --font-display: "Inter Tight", -apple-system, BlinkMacSystemFont, sans-serif;
    --font-body:    "Inter Tight", -apple-system, BlinkMacSystemFont, sans-serif;
    --font-brand:   "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
    --font-mono:    "JetBrains Mono", ui-monospace, "SF Mono", monospace;

    /* Rhythm */
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 16px;

    /* Input control sizing tiers — every <input>/<select> must use one of
       these padding pairs so the form-control grid stays on four heights
       (assumes box-sizing: border-box, font-size 13-14px, line-height 1.6):
         lg  →  44px  default form/modal inputs, primary buttons
         md  →  36px  page selectors, workspace-header-action buttons
         sm  →  32px  compact inline pickers (latency-window-select)
         xs  →  28px  inline admin-table edit fields                        */
    --input-pad-y-lg: 11px; --input-pad-x-lg: 14px;
    --input-pad-y-md: 8px;  --input-pad-x-md: 12px;
    --input-pad-y-sm: 6px;  --input-pad-x-sm: 10px;
    --input-pad-y-xs: 4px;  --input-pad-x-xs: 8px;

    --container: 1280px;
}

/* Reset + base
   ============================================================================= */

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }

body {
    background: var(--paper);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 { margin: 0; font-weight: 500; letter-spacing: -0.015em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; border: none; background: none; color: inherit; }
ul { margin: 0; padding: 0; list-style: none; }
code { font-family: var(--font-mono); font-size: 0.9em; }
dl { margin: 0; }
dt { font-weight: 500; color: var(--ink-3); margin-top: 12px; font-size: 13px; }
dd { margin: 2px 0 0; font-size: 13px; }

::selection { background: var(--pulse); color: var(--paper); }

.container { max-width: var(--container); margin: 0 auto; padding: 0 24px; }

/* Authenticated app gets more breathing room — the dashboard has wide heatmaps,
   monitor cards, and side-by-side workspace panels that benefit from 1440 px. */
body.app-body .container { max-width: 1440px; }

/* Header (public)
   ============================================================================= */

.site-header {
    border-bottom: 1px solid var(--line);
    background: var(--paper);
    position: sticky;
    top: 0;
    z-index: 10;
}

.header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 24px;
    max-width: var(--container);
    margin: 0 auto;
}

.brand { display: flex; align-items: center; gap: 10px; }

.brand-mark {
    width: 26px; height: 26px;
    border-radius: 7px;
    background: var(--pulse-soft);
    display: inline-flex; align-items: center; justify-content: center;
}

.brand-mark.admin-mark { background: var(--admin-soft); }

.brand-dot {
    width: 9px; height: 9px; border-radius: 50%;
    background: var(--pulse);
    animation: sp-pulse 2s ease-in-out infinite;
}

.admin-mark .brand-dot { background: var(--admin-ink); }

.brand-name {
    font-family: var(--font-display);
    font-size: 19px;
    font-weight: 500;
    letter-spacing: -0.02em;
}

.admin-badge {
    font-family: var(--font-mono);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: #fff;
    background: rgba(255, 255, 255, 0.18);
    padding: 2px 6px;
    border-radius: 4px;
    margin-left: 6px;
    vertical-align: middle;
}

.site-nav {
    display: flex; align-items: center; gap: 28px;
    font-size: 14px; color: var(--ink-3);
}

.site-nav a { transition: color 0.15s; }
.site-nav a:hover { color: var(--ink); }

.nav-cta {
    padding: 7px 14px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    color: var(--ink);
}

.nav-cta:hover { background: var(--pulse); color: #fff; border-color: var(--pulse); }

/* Product dropdown — CSS-only hover/focus menu. The trigger itself is a
   real link to /features so a no-JS / no-hover (touch) visitor still
   has a working destination. Submenu opens on :hover OR :focus-within
   so keyboard tabbing into the trigger reveals the children. */
.nav-dropdown { position: relative; display: inline-flex; align-items: center; }
.nav-dropdown-trigger {
    display: inline-flex; align-items: center; gap: 4px;
}
.nav-dropdown-chevron {
    font-size: 11px; line-height: 1;
    transition: transform 0.15s ease;
}
.nav-dropdown:hover .nav-dropdown-chevron,
.nav-dropdown:focus-within .nav-dropdown-chevron { transform: rotate(180deg); }

/* Invisible hover-bridge between the trigger and the menu. Without
   it, the 8px visual gap below the trigger is a "dead zone" where
   the cursor leaves the trigger before reaching the menu — :hover
   on .nav-dropdown flips off and the menu hides. The ::after stays
   inside .nav-dropdown's hoverable rect across the whole gap, so
   the cursor can travel down at any speed and the menu stays open.
   Only active while hovering so it doesn't block clicks below the
   nav under normal browsing. */
.nav-dropdown::after {
    content: "";
    position: absolute;
    top: 100%; left: 0; right: 0;
    height: 14px;
    pointer-events: none;
}
.nav-dropdown:hover::after,
.nav-dropdown:focus-within::after { pointer-events: auto; }

.nav-dropdown-menu {
    position: absolute; top: calc(100% + 8px); left: 0;
    min-width: 320px;
    background: var(--paper); border: 1px solid var(--line);
    border-radius: var(--radius-md);
    box-shadow: 0 8px 24px rgba(0,0,0,0.08);
    padding: 8px;
    display: none;
    z-index: 20;
}
.nav-dropdown:hover .nav-dropdown-menu,
.nav-dropdown:focus-within .nav-dropdown-menu { display: block; }

.nav-dropdown-menu a {
    display: block;
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    color: var(--ink-2);
}
.nav-dropdown-menu a:hover { background: var(--paper-2); color: var(--ink); }
.nav-dropdown-menu a strong {
    display: block; color: var(--ink);
    font-weight: 500; font-size: 14px;
}
.nav-dropdown-meta {
    display: block; font-size: 12.5px; color: var(--ink-4);
    margin-top: 2px;
}

/* Hero
   ============================================================================= */

.hero {
    padding: 28px 24px 28px;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 56px;
    align-items: center;
}

/* Single-column variant — the hero copy + CTAs centered on the page,
   no right-side card. Used after the waitlist form was removed.
   2026-05 — landing reverted to 2-col with a hero illustration on the
   right (see .hero-visual below). This .hero-centered class is kept for
   any other page that might still want the centered variant. */
.hero-centered {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    text-align: center;
    padding-bottom: 64px;
}
.hero-centered .hero-copy { max-width: 720px; text-align: center; }
.hero-centered .hero-actions { justify-content: center; flex-wrap: wrap; }

/* Right-side hero illustration — standalone SVG asset at
   wwwroot/img/hero-illustration.svg, referenced via <img>. The viewBox
   is 680×830 (portrait-ish), so max-width is sized so the natural
   height (~720px) doesn't dominate the hero copy column. Sits in the
   second column of the 2-col .hero grid; on narrow screens the grid
   collapses to 1 column and the illustration stacks below the copy. */
.hero-visual {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
.hero-illustration {
    width: 100%;
    height: auto;
    max-width: 540px;
    display: block;
}

/* Hero headline carousel — viewport + track that slides horizontally.
   The .hero-slides viewport clips overflow and reveals one slide width
   at a time. The .hero-slides-track holds all slides flex-row; JS sets
   transform: translateX(-N * 100%) to advance. Slide width is fixed at
   100% of the viewport via flex: 0 0 100%. Container's height equals the
   tallest slide (flex stretches); no layout shift between slides. */
.hero-slides {
    width: 100%;
    overflow: hidden;
    margin-bottom: 14px;
}
.hero-slides-track {
    display: flex;
    align-items: stretch;
    transition: transform 0.55s cubic-bezier(0.4, 0, 0.2, 1);
    will-change: transform;
}
/* When the JS performs an instant repositioning (the infinite-carousel
   snap-back at the end of the wrap), it adds .no-anim for one frame so
   the snap doesn't visibly animate. */
.hero-slides-track.no-anim {
    transition: none !important;
}
.hero-slide {
    flex: 0 0 100%;
    min-width: 0;
}
.hero-slide .hero-title { margin-bottom: 16px; }
.hero-slide .hero-lede { margin-bottom: 0; }
/* Inactive slides are still in the DOM but should be ignored by the tab
   order + screen readers. The `inert` attribute does both; the CSS here
   is just defence-in-depth for browsers that haven't shipped inert yet. */
.hero-slide[aria-hidden="true"] { pointer-events: none; }

/* Dot indicators — 3 small clickable circles below the headlines. */
.hero-dots {
    display: flex;
    gap: 10px;
    justify-content: center;
    margin: 6px 0 22px;
}
.hero-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    border: 1px solid var(--ink-3, #999);
    background: transparent;
    cursor: pointer;
    padding: 0;
    transition: background 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
    appearance: none;
    -webkit-appearance: none;
}
.hero-dot:hover { border-color: var(--ink-2, #555); }
.hero-dot.active {
    background: var(--ink-2, #333);
    border-color: var(--ink-2, #333);
    transform: scale(1.25);
}
.hero-dot:focus-visible {
    outline: 2px solid var(--pulse, #6366f1);
    outline-offset: 3px;
}

/* Honour reduced motion: drop the slide transition; the JS already skips
   the auto-rotation, but a dot click should still snap instantly. */
@media (prefers-reduced-motion: reduce) {
    .hero-slides-track { transition: none !important; }
}

.hero-copy { max-width: 520px; }

.eyebrow {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 5px 12px;
    background: var(--paper-2);
    border-radius: 999px;
    font-size: 12.5px;
    color: var(--ink-3);
    margin-bottom: 28px;
}

.eyebrow-dot {
    width: 6px; height: 6px; border-radius: 50%;
    background: var(--pulse);
    animation: sp-pulse 2s ease-in-out infinite;
}

.hero-title {
    font-family: var(--font-display);
    font-size: clamp(32px, 4.4vw, 48px);
    line-height: 1.05;
    letter-spacing: -0.025em;
    font-weight: 500;
    margin-bottom: 24px;
    font-variation-settings: "opsz" 120;
}

.hero-title em {
    font-style: italic;
    color: var(--coral);
    font-variation-settings: "opsz" 120, "SOFT" 100;
}

.hero-lede {
    font-size: 15.5px; line-height: 1.55;
    color: var(--ink-3);
    margin-bottom: 24px;
}

.hero-actions { display: flex; gap: 10px; align-items: center; margin-bottom: 12px; }

/* Modifier for the "See it in action" section on the landing — same flex
   layout as .hero-actions but with extra top breathing room (the lede
   above is a tight paragraph, not a hero h1) so the buttons read as a
   deliberate next step rather than a continuation of the sentence. */
.hero-actions-product { margin: 18px 0 28px; }
.hero-note { font-size: 13px; color: var(--ink-4); margin-bottom: 16px; }

/* Recognition badges (Product Hunt + SaaSHub) sit inline with the
   hero copy, just under the hero-note. Sized down vs. the old
   .badge-strip section so both fit comfortably within the hero-copy
   column (~480px). Height 43px keeps both badges on the same
   baseline regardless of their authored aspect ratios. */
.hero-badges {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
}
.hero-badges a { display: inline-flex; align-items: center; }
.hero-badges img { display: block; height: 43px; width: auto; }

/* Buttons
   ============================================================================= */

.btn {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 11px 18px;
    border-radius: var(--radius-md);
    font-size: 14.5px; font-weight: 500;
    transition: all 0.15s ease;
    cursor: pointer;
    border: 1px solid transparent;
    white-space: nowrap;
}

.btn-primary { background: var(--pulse); color: #fff; }
.btn-primary:hover { background: var(--pulse-ink); transform: translateY(-1px); }
.btn-primary:disabled { opacity: 0.6; cursor: not-allowed; transform: none; }

.btn-ghost { border-color: var(--line-2); color: var(--ink); }
.btn-ghost:hover { background: var(--paper-2); }
.btn-ghost:disabled,
.btn-ghost[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
    pointer-events: none;
}

.btn-full { width: 100%; justify-content: center; padding: 13px 18px; }

/* Inline "back" text link used at the top of detail pages (left of the H1).
   Small, muted, with a hover that reveals it's interactive. No border, no pill. */
.back-link {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 13.5px; color: var(--ink-3);
    text-decoration: none;
    transition: color 0.12s;
}
.back-link:hover { color: var(--pulse-ink); }
.back-sep {
    color: var(--ink-4);
    font-weight: 300;
    font-size: 18px;
    line-height: 1;
    user-select: none;
}

/* Status widget (hero showpiece)
   ============================================================================= */

/* Example "status page" sample shown under the Three-products feature grid.
   Mirrors the real public status page at /status/{slug} — left-bordered rows
   tinted by current status, 48 h × 6-row heatmap, SLA + latency + uptime metrics.
   All class names are `sample-*` scoped so they don't collide with real app styles.
   ============================================================================= */

.status-widget-sample {
    padding: 22px 24px 18px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: 0 1px 2px rgba(15, 18, 17, 0.04),
                0 20px 40px -20px rgba(15, 18, 17, 0.08);
}

/* Landing-only cap — keeps the sample from dominating the feature grid.
   The All-monitors page omits this scope so the card flows at full width. */
.features .status-widget-sample {
    max-width: 720px;
    margin: 56px auto 0;
}

/* Two-column composition on the landing: the full monitor widget on the left
   and two stacked mini-chart previews (latency history + SLA band) on the
   right. The widget's own max-width rule above is neutralised when it lives
   inside the grid so both columns share the row's full width. Collapses to a
   single column at narrower viewports. */
.features .sample-row-grid {
    display: grid;
    grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
    gap: 24px;
    margin-top: 56px;
    align-items: start;
}
.features .sample-row-grid > .status-widget-sample {
    max-width: none;
    margin: 0;
}
@media (max-width: 960px) {
    .features .sample-row-grid {
        grid-template-columns: 1fr;
    }
}

.mini-sample-stack {
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.mini-sample {
    padding: 16px 18px 14px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: 0 1px 2px rgba(15, 18, 17, 0.04),
                0 20px 40px -20px rgba(15, 18, 17, 0.08);
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.mini-sample-header {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 10px;
}
.mini-sample-header strong {
    display: block;
    font-size: 14px;
}
.mini-sample-meta {
    display: block;
    margin-top: 2px;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px;
    color: var(--ink-4);
}
.mini-sample-chip {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11.5px;
    color: var(--ink-3);
    background: var(--paper-2);
    padding: 3px 8px;
    border-radius: 4px;
    flex-shrink: 0;
}
.mini-sample-chip-ok {
    color: #0f7a3e;
    background: var(--pulse-soft);
}

.mini-sample-svg {
    width: 100%;
    height: auto;
    display: block;
}
.mini-sla-svg {
    /* SLA band stretches full width via preserveAspectRatio="none". */
    height: 110px;
}

.mini-chart-axis {
    stroke: var(--ink-4);
    stroke-width: 1;
}
.mini-chart-grid {
    stroke: var(--line);
    stroke-width: 1;
    stroke-dasharray: 2 4;
}
.mini-chart-label {
    fill: var(--ink-4);
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 9px;
}
.mini-chart-line {
    fill: none;
    stroke: var(--pulse);
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}
.mini-chart-trend {
    stroke: #d97706;
    stroke-width: 1.5;
    stroke-dasharray: 5 4;
    opacity: 0.9;
}

.mini-sample-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 14px;
    font-size: 11px;
    color: var(--ink-3);
}
.mini-legend-swatch {
    display: inline-block;
    width: 16px; height: 0;
    vertical-align: middle;
    margin-right: 5px;
}
.mini-legend-line { border-top: 3px solid var(--pulse); }
.mini-legend-trend { border-top: 2px dashed #d97706; }
.mini-legend-sla-good {
    width: 22px; height: 10px; border: 0;
    border-radius: 2px;
    background: linear-gradient(to right, hsl(145, 45%, 72%), hsl(145, 60%, 38%));
}
.mini-legend-sla-bad {
    width: 22px; height: 10px; border: 0;
    border-radius: 2px;
    background: linear-gradient(to right, hsl(2, 60%, 78%), hsl(2, 70%, 42%));
}

.sample-header {
    display: flex; align-items: flex-start; justify-content: space-between;
    flex-wrap: wrap; gap: 12px;
    padding-bottom: 18px; margin-bottom: 18px;
    border-bottom: 1px solid var(--line);
}
.sample-brand {
    margin: 0;
    font-family: var(--font-display);
    font-size: 20px; font-weight: 500;
    letter-spacing: -0.01em;
    color: var(--ink);
}
.sample-domain {
    margin: 4px 0 0;
    font-family: var(--font-mono);
    font-size: 11.5px; color: var(--ink-4);
}

.sample-overall {
    display: inline-flex; align-items: center; gap: 9px;
    padding: 6px 14px;
    border-radius: 999px;
    font-size: 13px; font-weight: 500;
}
.sample-overall-ok      { background: var(--pulse-soft);  color: var(--pulse); }
.sample-overall-warn    { background: var(--coral-soft);  color: var(--coral); }
.sample-overall-down    { background: var(--danger-soft); color: var(--danger); }
.sample-overall-unknown { background: var(--paper-2);     color: var(--ink-3); }
.sample-overall-warn    .sample-pulse { background: var(--coral); }
.sample-overall-down    .sample-pulse { background: var(--danger); }
.sample-overall-unknown .sample-pulse { background: var(--ink-4); }
.sample-pulse {
    width: 7px; height: 7px; border-radius: 50%;
    background: var(--pulse);
    animation: sp-pulse 2s ease-in-out infinite;
}

.sample-services { list-style: none; margin: 0; padding: 0; }

.sample-row {
    display: flex; flex-direction: column; gap: 10px;
    padding: 14px 16px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-left-width: 4px;
    border-left-color: var(--ink-4);
    border-radius: var(--radius-md);
    margin-bottom: 8px;
}
.sample-row-ok      { background: var(--pulse-soft);  border-left-color: var(--pulse); }
.sample-row-warn    { background: var(--coral-soft);  border-left-color: var(--coral); }
.sample-row-down    { background: var(--danger-soft); border-left-color: var(--danger); }
.sample-row-paused  { border-left-color: var(--ink-4); }
.sample-row-unknown { border-left-color: var(--ink-4); }

.sample-row-top {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 12px;
}
.sample-info { min-width: 0; }
.sample-info strong { display: block; font-size: 14.5px; color: var(--ink); }
.sample-meta {
    display: block; margin-top: 2px;
    font-family: var(--font-mono); font-size: 11px;
    color: var(--ink-4);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

.sample-badges {
    display: flex; align-items: center; gap: 8px; flex-shrink: 0;
}
.sample-status {
    padding: 3px 10px; border-radius: 6px;
    font-size: 12.5px; font-weight: 500;
    flex-shrink: 0;
}
.sample-status-ok      { background: var(--pulse-soft);  color: var(--pulse); }
.sample-status-warn    { background: var(--coral-soft);  color: var(--coral); }
.sample-status-down    { background: var(--danger-soft); color: var(--danger); }
.sample-status-paused  { background: var(--paper-2);     color: var(--ink-4); }
.sample-status-unknown { background: var(--paper-2);     color: var(--ink-3); }

.sample-sla {
    display: inline-flex; align-items: center; gap: 5px;
    padding: 3px 8px;
    border-radius: 6px;
    font-family: var(--font-mono);
    font-size: 11px; font-weight: 500;
    flex-shrink: 0;
}
.sample-sla-ok      { background: var(--pulse-soft);  color: var(--pulse); }
.sample-sla-breach  { background: var(--danger-soft); color: var(--danger); }
.sample-sla-unknown { background: var(--paper-2);     color: var(--ink-4); }

/* Heatmap — 48 columns × 6 rows of 10-min cells. Matches the real status page. */
.sample-row-chart {
    padding-top: 8px;
    border-top: 1px dashed var(--line);
}
.sample-chart {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    column-gap: 6px;
    row-gap: 3px;
}
.sample-chart-y {
    grid-column: 1; grid-row: 1;
    display: flex; flex-direction: column; justify-content: space-between;
    font-family: var(--font-mono);
    font-size: 9px; line-height: 1;
    color: var(--ink-4);
}
.sample-chart-grid {
    grid-column: 2; grid-row: 1;
    display: grid;
    grid-template-columns: repeat(48, 1fr);
    grid-template-rows: repeat(6, 10px);
    grid-auto-flow: column;
    gap: 2px;
}
.sample-chart-x {
    grid-column: 2; grid-row: 2;
    display: flex; justify-content: space-between;
    font-family: var(--font-mono);
    font-size: 9px; color: var(--ink-4);
    padding-top: 2px;
}
.sample-cell {
    border-radius: 1px;
    background: var(--ink-4);
    min-width: 0; min-height: 0;
}
.sample-cell-ok      { background: var(--pulse); }
.sample-cell-warn    { background: var(--coral); }
.sample-cell-down    { background: var(--danger); }
.sample-cell-empty   { background: var(--paper-2); }
.sample-cell-unknown { background: var(--ink-4); }

.sample-row-metrics {
    display: flex; flex-wrap: wrap; align-items: center; gap: 16px;
    padding-top: 8px;
    border-top: 1px dashed var(--line);
    font-size: 12px; color: var(--ink-3);
}
.sample-metric { display: inline-flex; gap: 6px; align-items: baseline; }
.sample-metric strong {
    font-family: var(--font-mono);
    font-weight: 500; font-size: 12.5px;
    color: var(--ink);
}
.sample-metric-uptime { margin-left: auto; }

.sample-updated {
    text-align: center;
    margin: 16px 0 0;
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--ink-4);
}
.sample-updated strong { color: var(--ink-3); font-weight: 500; }

/* Section kickers
   ============================================================================= */

.section-kicker {
    font-size: 12px; color: var(--ink-4);
    letter-spacing: 0.12em;
    text-transform: uppercase;
    margin-bottom: 20px;
    font-weight: 500;
}

/* Features / compare / pricing / waitlist (public sections)
   ============================================================================= */

.features { padding: 40px 24px 56px; border-top: 1px solid var(--line); margin-top: 0; }
.feature-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px 40px; }
/* Feature card — compact left-border-only treatment (no box padding).
   The card is a block-level anchor; "Learn more →" sits inline with
   the h3 in the .feature-head flex row so it lives in the top-right
   corner of the card without consuming a separate row. Only the CTA
   shows movement on hover — the rest of the card stays put. */
.feature {
    padding-left: 18px;
    border-left: 3px solid var(--pulse);
    display: block;
    color: inherit;
    text-decoration: none;
}
.feature-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
}
.feature h3 {
    font-family: var(--font-display); font-size: 20px;
    margin: 0 0 8px;
    font-variation-settings: "opsz" 48;
    color: var(--ink-1);
}
.feature p { font-size: 14px; line-height: 1.55; color: var(--ink-3); margin: 0; }
.feature-cta {
    font-size: 12px;
    font-weight: 500;
    color: var(--pulse);
    opacity: 0;
    flex-shrink: 0;
    transition: opacity 120ms ease;
    white-space: nowrap;
}
.feature:hover .feature-cta,
.feature:focus-visible .feature-cta {
    opacity: 1;
}
.feature:focus-visible { outline: 2px solid var(--pulse); outline-offset: 2px; border-radius: 2px; }

/* Monitor types catalogue — the second landing-page block, sitting between
   the feature/example showcase and pricing. Same chrome conventions as
   .features (border-top + section padding). Each card is a paper-2 surface
   with a coloured left border that signals "available" (pulse-green) or
   "coming soon" (amber); the icon block + meta line ride above the body. */
.monitor-types { padding: 56px 24px; border-top: 1px solid var(--line); }
.monitor-types-title {
    font-family: var(--font-display);
    font-size: 32px;
    font-weight: 500;
    letter-spacing: -0.02em;
    margin: 8px 0 12px;
}
.monitor-types-lede {
    font-size: 16px;
    line-height: 1.6;
    color: var(--ink-3);
    max-width: 720px;
    margin: 0 0 32px;
}
.monitor-type-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
}
/* Monitor-type card — also an <a> for the click-to-detail-page flow.
   Reset anchor styling (color: inherit, no underline) and add a hover
   lift so the click affordance is visible. */
.monitor-type {
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-left-width: 4px;
    border-left-color: var(--pulse);
    border-radius: var(--radius-md);
    padding: 20px 22px;
    display: flex;
    flex-direction: column;
    gap: 12px;
    color: inherit;
    text-decoration: none;
    transition: transform 120ms ease, border-color 120ms ease, box-shadow 120ms ease;
}
.monitor-type:hover,
.monitor-type:focus-visible {
    transform: translateY(-2px);
    border-color: var(--line-2);
    box-shadow: 0 4px 14px rgba(0, 0, 0, 0.04);
    outline: none;
}
.monitor-type-head {
    display: grid;
    /* Third column collapses to 0 when no pill is rendered (auto on an empty
       cell), so cards without a "Coming soon" badge stay visually identical
       to the 2-column layout. */
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 12px;
}
.monitor-type-pill {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 10.5px;
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 4px 9px;
    border-radius: 999px;
    border: 1px solid transparent;
    white-space: nowrap;
}
.monitor-type-pill-soon {
    background: var(--coral-soft);
    color: var(--coral-ink);
    border-color: var(--coral);
}
.monitor-type-icon {
    width: 36px; height: 36px;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 8px;
    color: var(--ink-2);
}
.monitor-type-icon svg { width: 20px; height: 20px; }
.monitor-type h3 {
    font-family: var(--font-display);
    font-size: 18px;
    font-weight: 500;
    margin: 0;
    letter-spacing: -0.01em;
}
.monitor-type-meta {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11.5px;
    color: var(--ink-3);
    margin: 2px 0 0;
}
.monitor-type > p {
    font-size: 14px;
    line-height: 1.6;
    color: var(--ink-2);
    margin: 0;
}
.monitor-type code {
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 12.5px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: 1px 5px;
}
.monitor-type-points {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.monitor-type-points li {
    font-size: 13.5px;
    line-height: 1.55;
    color: var(--ink-3);
    padding-left: 14px;
    position: relative;
}
.monitor-type-points li::before {
    content: "";
    position: absolute;
    left: 0; top: 0.6em;
    width: 4px; height: 4px;
    border-radius: 999px;
    background: var(--ink-4);
}
.monitor-type-points strong { color: var(--ink); font-weight: 500; }

@media (max-width: 720px) {
    .monitor-type-grid { grid-template-columns: 1fr; }
}

.compare { padding: 56px 24px; border-top: 1px solid var(--line); }
.compare-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.compare-card { padding: 20px 18px; background: var(--paper-2); border-radius: var(--radius-md); }
.compare-card-us { background: var(--pulse-soft); border: 1px solid var(--pulse); }
.compare-name { font-size: 12.5px; color: var(--ink-3); margin-bottom: 10px; }
.compare-card-us .compare-name { color: var(--pulse-ink); font-weight: 500; }
.compare-price {
    font-family: var(--font-display); font-size: 28px; font-weight: 500;
    color: var(--ink); letter-spacing: -0.02em; margin-bottom: 6px;
}
.compare-card-us .compare-price { color: var(--pulse-ink); }
.compare-price span {
    font-family: var(--font-body); font-size: 13px;
    color: var(--ink-4); font-weight: 400; margin-left: 2px;
}
.compare-card-us .compare-price span { color: var(--pulse-ink); opacity: 0.7; }
.compare-caveat { font-size: 11.5px; color: var(--ink-4); line-height: 1.4; }
.compare-card-us .compare-caveat { color: var(--pulse-ink); opacity: 0.8; }

.pricing { padding: 72px 24px; border-top: 1px solid var(--line); }
.pricing-title {
    font-family: var(--font-display); font-size: 36px; font-weight: 500;
    margin-bottom: 36px; letter-spacing: -0.02em;
}
.pricing-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 14px; }
.plan {
    padding: 26px 22px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    position: relative;
    transition: transform 0.2s ease, border-color 0.2s ease;
}
.plan:hover { transform: translateY(-3px); border-color: var(--line-2); }
.plan-featured { border-color: var(--coral); border-width: 1.5px; }
.plan-badge {
    position: absolute; top: -10px; left: 20px;
    background: var(--coral); color: var(--paper);
    font-size: 11px; font-weight: 500;
    padding: 3px 10px; border-radius: 999px;
    letter-spacing: 0.02em;
}
.plan-name {
    font-size: 13px; color: var(--ink-3);
    margin-bottom: 8px;
    letter-spacing: 0.02em; text-transform: uppercase; font-weight: 500;
}
.plan-price {
    font-family: var(--font-display); font-size: 40px; font-weight: 500;
    letter-spacing: -0.025em; margin-bottom: 20px; color: var(--ink);
}
.plan-price span {
    font-family: var(--font-body); font-size: 14px;
    color: var(--ink-4); font-weight: 400;
}
.plan ul { display: flex; flex-direction: column; gap: 9px; }
.plan li {
    font-size: 13.5px; color: var(--ink-2);
    padding-left: 20px; position: relative;
}
.plan li::before {
    content: ""; position: absolute;
    left: 2px; top: 8px;
    width: 10px; height: 6px;
    border-left: 1.5px solid var(--pulse);
    border-bottom: 1.5px solid var(--pulse);
    transform: rotate(-45deg);
}
/* Inheritance row — "All <previous> features, plus:". Sits between
   the quantity bullets and the per-tier feature increment, with no
   checkmark and a hairline separator so the visual rhythm reads:
   quantities → "rest is on top of X" → new features. */
.plan li.plan-inherits {
    padding-left: 0;
    margin-top: 4px; padding-top: 9px;
    border-top: 1px dashed var(--line);
    color: var(--ink-3);
}
.plan li.plan-inherits::before { content: none; }
.plan li.plan-inherits strong { color: var(--ink-1); font-weight: 600; }
.pricing-note { margin-top: 28px; font-size: 13px; color: var(--ink-4); text-align: center; }

/* Comparison-page links below the pricing grid. Discreet — the goal is
   to give validation-seeking visitors an exit ramp, not to distract from
   the primary "Subscribe" CTA on each plan card. */
.pricing-vs {
    margin: 18px auto 0;
    text-align: center;
}
.pricing-vs-label {
    font-size: 12.5px;
    color: var(--ink-4);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    font-weight: 600;
    margin: 0 0 10px;
}
.pricing-vs-links {
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px 24px;
}
.pricing-vs-links a {
    font-size: 14px;
    color: var(--pulse-ink);
    text-decoration: none;
    border-bottom: 1px solid transparent;
    padding-bottom: 1px;
    transition: border-color 0.15s;
}
.pricing-vs-links a:hover {
    border-bottom-color: var(--pulse-ink);
}

/* Pricing — Monthly / Annual segmented toggle. Sits between the title
   and the cards. Two button group; the active one carries `.active`
   set by the nonce'd script in Index.cshtml. */
.pricing-toggle {
    display: inline-flex;
    align-self: center;
    margin: 4px auto 28px;
    padding: 4px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--paper-2);
    gap: 4px;
}
.pricing-toggle-btn {
    border: 0;
    background: transparent;
    font-family: var(--font-body);
    font-size: 13.5px;
    color: var(--ink-3);
    padding: 7px 16px;
    border-radius: 999px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.pricing-toggle-btn.active {
    background: var(--ink);
    color: var(--paper);
    font-weight: 500;
}
.pricing-toggle-discount {
    font-size: 11px;
    background: var(--pulse);
    color: #fff;
    padding: 1px 6px;
    border-radius: 999px;
    font-weight: 500;
}
.pricing-toggle-btn.active .pricing-toggle-discount {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
}
/* Cycle visibility — pricing section flips data-billing-cycle, cards
   reveal the matching block and hide the off-cycle one. */
#pricing[data-billing-cycle="monthly"] .plan-price[data-cycle="annual"],
#pricing[data-billing-cycle="annual"]  .plan-price[data-cycle="monthly"] { display: none; }
.plan .plan-cta {
    margin-top: 18px;
    width: 100%;
    text-align: center;
    justify-content: center;
    transition: background 0.15s ease, border-color 0.15s ease, transform 0.15s ease;
}
/* Mirror the Pro card's btn-primary hover energy on the ghost-styled
   CTAs (Starter, Business, Free → Go to dashboard / Sign up free).
   Without this they fall back to .btn-ghost:hover which paints
   --paper-2 on top of the card's white background — visually
   identical, so the buttons looked dead on hover. Darker fill +
   stronger border + 1px lift gives the same affordance as the
   primary CTA without breaking the visual hierarchy. */
.plan .plan-cta.btn-ghost:hover {
    background: var(--paper-3);
    border-color: var(--ink-4);
    transform: translateY(-1px);
}
/* Center the pricing-toggle inside the section flow (it's inline-flex
   on a block container; adding text-align centres it on the row). */
.pricing { display: flex; flex-direction: column; }

/* ── Billing card on /Dashboard/Account ───────────────────────────── */
.billing-card { /* dashboard-debug wrapper supplies the box; we layer on top */ }
.billing-plan-row {
    display: flex; justify-content: space-between; align-items: flex-start;
    gap: 20px;
    flex-wrap: wrap;
}
.billing-plan-text { flex: 1 1 auto; min-width: 220px; }
.billing-plan-name {
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 500;
    margin: 0 0 8px;
    color: var(--ink);
}
.billing-meta {
    margin: 8px 0 0;
    font-size: 13.5px;
    color: var(--ink-3);
}
.billing-plan-actions { flex: 0 0 auto; }

.billing-pill {
    display: inline-block;
    font-size: 11.5px;
    font-weight: 500;
    letter-spacing: 0.04em;
    padding: 3px 10px;
    border-radius: 999px;
    margin-left: 4px;
    vertical-align: middle;
    text-transform: uppercase;
}
.billing-pill-ok    { background: var(--pulse-soft); color: var(--pulse-ink); }
.billing-pill-info  { background: #e0f0ff; color: #1a5fa8; }
.billing-pill-warn  { background: #ffe9d6; color: #a85c00; }
.billing-pill-muted { background: var(--paper-2); color: var(--ink-3); }

.billing-invoices { margin-top: 24px; }
.billing-invoices-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.billing-invoices-table th {
    text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line);
    font-weight: 500; color: var(--ink-3); font-size: 12px; text-transform: uppercase;
    letter-spacing: 0.05em;
}
.billing-invoices-table td {
    padding: 8px; border-bottom: 1px solid var(--line); color: var(--ink-2);
}
.billing-invoices-table tr:last-child td { border-bottom: none; }

/* ── Subscription status banner (top of every authenticated page) ── */
.billing-banner {
    margin-bottom: 16px;
    padding: 10px 16px;
    border-radius: 8px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 16px;
    font-size: 13.5px;
    border: 1px solid transparent;
}
.billing-banner-error {
    background: #fde7e7; color: #8c1d1d; border-color: #f3c7c7;
}
.billing-banner-warn {
    background: #fff4d6; color: #6b4400; border-color: #f0d990;
}
.billing-banner-info {
    background: var(--pulse-soft); color: var(--pulse-ink); border-color: #b6e8d0;
}
.billing-banner-cta {
    color: inherit;
    text-decoration: underline;
    font-weight: 500;
    flex: 0 0 auto;
}
.billing-banner-cta:hover { text-decoration: none; }

/* Contact section — two-column layout: copy on the left, feedback form on the right. */
.contact {
    padding: 72px 24px 80px;
    border-top: 1px solid var(--line);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    gap: 56px;
    align-items: start;
}
.contact-copy { max-width: 480px; }
.contact-title {
    font-family: var(--font-display); font-size: 32px; font-weight: 500;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
}
.contact-lede {
    font-size: 15.5px; line-height: 1.6;
    color: var(--ink-3);
    margin: 0;
}
.contact-lede a { color: var(--pulse); }
.contact-lede a:hover { text-decoration: underline; }

.contact-form-card {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 28px;
}
.contact-form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
.contact-form-card .field select,
.contact-form-card .field textarea {
    width: 100%;
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font: inherit; font-size: 14px;
    background: var(--paper);
    color: var(--ink);
    resize: vertical;
}
.contact-form-card .field textarea { min-height: 110px; }
.contact-form-card .field select:focus,
.contact-form-card .field textarea:focus {
    outline: none;
    border-color: var(--pulse);
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
.field-hint-inline { color: var(--ink-4); font-weight: 400; }

/* Contact mobile stack. */
@media (max-width: 900px) {
    .contact { grid-template-columns: 1fr; gap: 32px; }
    .contact-form-grid { grid-template-columns: 1fr; }
}

/* Dark surface overrides for the contact form. */
body.theme-dark .contact-form-card { background: var(--paper-2); }
body.theme-dark .contact-form-card .field select,
body.theme-dark .contact-form-card .field textarea {
    background: var(--paper-3);
    color: var(--ink);
    border-color: var(--line-2);
}

.waitlist {
    padding: 72px 24px 80px;
    border-top: 1px solid var(--line);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    gap: 56px;
    align-items: start;
}
.waitlist-copy h2 {
    font-family: var(--font-display); font-size: 34px; font-weight: 500;
    margin-bottom: 16px; line-height: 1.15; letter-spacing: -0.02em;
}
.waitlist-copy p { font-size: 15.5px; line-height: 1.6; color: var(--ink-3); }
.waitlist-count { margin-top: 20px; font-size: 14px; color: var(--ink-3); }
.waitlist-count strong { color: var(--pulse); font-weight: 500; font-family: var(--font-mono); }

/* Form
   ============================================================================= */

.waitlist-form {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 28px;
}

/* Heading + sub copy for the waitlist form when it lives inside the hero. */
.hero-waitlist .waitlist-heading {
    font-family: var(--font-display);
    font-size: 22px; font-weight: 500;
    margin: 4px 0 10px;
    letter-spacing: -0.01em;
    color: var(--ink);
}
.hero-waitlist .waitlist-sub {
    font-size: 14px; line-height: 1.55; color: var(--ink-3);
    margin-bottom: 22px;
}
.hero-waitlist .waitlist-sub .waitlist-count {
    display: inline; margin: 0 0 0 4px;
}

.field { margin-bottom: 18px; }
.field label {
    display: block; font-size: 13px;
    color: var(--ink-3); margin-bottom: 6px; font-weight: 500;
}
.field input,
.field select,
.field textarea {
    width: 100%;
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font: inherit; font-size: 14px;
    background: var(--paper); color: var(--ink);
    transition: border-color 0.15s, background 0.15s;
}
.field input::placeholder,
.field textarea::placeholder { color: var(--ink-4); }
.field input:focus,
.field select:focus,
.field textarea:focus {
    outline: none;
    border-color: var(--pulse);
    background: #fff;
    box-shadow: 0 0 0 3px var(--pulse-soft);
}

/* Standalone .input — used outside .field for inline search boxes and
   filters in page headers. Mirrors the .field input visuals (border,
   radius, focus ring, font) but omits width:100% so the caller controls
   the inline width via class or attribute. Inside .workspace-header-actions
   the lg-tier (44px) drops to md-tier (36px) so the textbox lines up with
   the 36px-forced .btn next to it. */
.input {
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font: inherit; font-size: 14px;
    background: var(--paper); color: var(--ink);
    transition: border-color 0.15s, background 0.15s;
}
.input::placeholder { color: var(--ink-4); }
.input:focus {
    outline: none;
    border-color: var(--pulse);
    background: #fff;
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
.workspace-header-actions .input {
    padding: var(--input-pad-y-md) var(--input-pad-x-md);
}

/* Color swatch input — used in branding settings (six swatches per
   light/dark theme). Documented exception to the --input-pad-y/x tokens:
   <input type="color"> renders as a swatch, not a text box, so the 2px
   padding is the inner gap between swatch and border (not text padding).
   Locked at the 36px (md) height so the swatch row aligns with sibling
   selects. See docs/INPUT_CONTROL_TOKENS.md. */
.input-color {
    width: 100%;
    height: 36px;
    padding: 2px;
}

/* Two-column grid for side-by-side fields. Collapses to a single column on
   narrow viewports so the form stays usable without horizontal scroll. */
.field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 540px) {
    .field-row { grid-template-columns: 1fr; gap: 0; }
}

/* Three-column field row for "Host + Port + Security"-style triplets where
   the middle column is intentionally narrow. Used on the SMTP / IMAP / POP3
   blocks of the Email round-trip probe modal so the connection setup fits
   one line instead of three. Below 540px the row collapses to one column
   stacked vertically — same behavior as `.field-row`. */
.field-row-3 {
    display: grid;
    grid-template-columns: 1fr 110px 220px;
    gap: 16px;
}
@media (max-width: 720px) {
    .field-row-3 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 540px) {
    .field-row-3 { grid-template-columns: 1fr; gap: 0; }
}

/* Three equal columns. Used for trios of similar-shape inputs (numerics,
   selects, etc.) — Interval/Timeout/SLA on the New Probe modal,
   per-type triplets like Method+Status+Body, Connect+TLS+Banner, etc.
   Collapses 3→2 at tablet, 2→1 at phone. */
.field-row-eq3 {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 16px;
}
@media (max-width: 720px) {
    .field-row-eq3 { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 540px) {
    .field-row-eq3 { grid-template-columns: 1fr; gap: 0; }
}

/* Tabs inside the New-Probe / Edit Email block. Subtle underline-active
   pattern (same vibe as the dashboard tabs but lighter). Pane visibility
   driven by the .active class — JS toggles. Hidden tabs (per probe mode)
   use the standard `hidden` attribute so screen readers skip them. */
.modal-tabs { display: block; }
.modal-tab-nav {
    display: flex;
    gap: 2px;
    border-bottom: 1px solid var(--line);
    margin-bottom: 16px;
}
.modal-tab-btn {
    background: transparent;
    border: none;
    padding: 10px 14px;
    font-size: 13px;
    color: var(--ink-3);
    cursor: pointer;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    font-weight: 500;
    font-family: inherit;
    transition: color 0.15s, border-color 0.15s;
}
.modal-tab-btn:hover { color: var(--ink); }
.modal-tab-btn.active {
    color: var(--pulse-ink);
    border-bottom-color: var(--pulse);
}
body.app-body.theme-dark .modal-tab-btn.active { color: var(--pulse); }
.modal-tab-pane { display: none; }
.modal-tab-pane.active { display: block; }

/* Span helper — used for "Target spans cols 2-3" in 3-col header layouts. */
.field-span-2 { grid-column: span 2; }
@media (max-width: 540px) { .field-span-2 { grid-column: auto; } }

/* Email round-trip probe — side-by-side SMTP submission + Mail retrieval.
   The wrapper defaults to 1-col (Mode A: only SMTP visible). When the JS
   adds .has-retrieval (Modes B/C with Mail retrieval visible) it switches
   to 2-col so the two blocks render in parallel — that's what saves the
   most vertical real-estate inside the New Probe / Edit modals. Below
   720px stacks to 1-col regardless so the form stays readable on tablet/
   phone. The internal .email-field-row pairs Port+Security, Username+
   Password, etc. inside each block at 2-col. */
.email-side-blocks {
    display: grid;
    grid-template-columns: 1fr;
    gap: 24px;
}
.email-side-blocks.has-retrieval {
    grid-template-columns: 1fr 1fr;
}
@media (max-width: 720px) {
    .email-side-blocks.has-retrieval { grid-template-columns: 1fr; }
}
.email-block > h4 {
    margin: 0 0 12px;
    font-size: 13px;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
}
.email-field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
}
@media (max-width: 540px) {
    .email-field-row { grid-template-columns: 1fr; gap: 0; }
}

/* Half-width field for a single control that shouldn't stretch full-width
   (e.g., the SLA dropdown on the monitor Settings tab). */
.field-half { max-width: calc(50% - 8px); }
@media (max-width: 540px) {
    .field-half { max-width: none; }
}

.segmented { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.seg {
    padding: 9px 8px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font-size: 13px; color: var(--ink-2);
    background: var(--paper);
    transition: all 0.15s;
    font-family: var(--font-mono);
}
.seg:hover { border-color: var(--ink-3); }
.seg-selected { background: var(--pulse); color: #fff; border-color: var(--pulse); }

.honeypot { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }

.form-error {
    margin: 12px 0; padding: 10px 14px;
    background: var(--danger-soft); color: var(--danger);
    border-radius: var(--radius-sm); font-size: 13px;
}

.form-legal { margin-top: 14px; font-size: 11.5px; color: var(--ink-4); line-height: 1.5; }

.validation-message {
    display: block; margin-top: 6px;
    font-size: 12.5px; color: var(--danger);
}

.form-success { text-align: center; padding: 20px 10px; }
.form-success-icon {
    width: 48px; height: 48px;
    margin: 0 auto 16px;
    color: var(--pulse);
    background: var(--pulse-soft);
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    padding: 12px;
}
.form-success-icon svg { width: 100%; height: 100%; }
.form-success h3 {
    font-family: var(--font-display); font-size: 24px;
    margin-bottom: 8px; color: var(--ink);
}
.form-success p { font-size: 14.5px; color: var(--ink-3); }
.form-success-position { margin-top: 14px; font-size: 13px; }
.form-success-position strong { font-family: var(--font-mono); color: var(--pulse); font-weight: 500; }

/* Footer
   ============================================================================= */

.site-footer { border-top: 1px solid var(--line); padding: 40px 0 28px; }
.footer-row { display: flex; align-items: center; justify-content: space-between; padding: 0 24px; }
.footer-brand {
    font-family: var(--font-display);
    font-size: 16px; font-weight: 500; margin-bottom: 2px;
}
.footer-tagline { font-size: 12.5px; color: var(--ink-4); max-width: 240px; }
.footer-meta {
    display: flex; align-items: center; gap: 10px;
    font-size: 12.5px; color: var(--ink-4);
}
.footer-meta a:hover { color: var(--ink-2); }

/* Footer link sections — distribute internal link equity to /vs/*,
   /features/*, /guides/* (the 42 SEO-load-bearing pages) so they're
   reachable from every marketing page, not just from the landing. */
.footer-columns {
    display: grid;
    grid-template-columns: 1.4fr 1fr 1fr 1fr;
    gap: 32px;
    padding: 0 24px 28px;
    border-bottom: 1px solid var(--line);
    margin-bottom: 20px;
}
.footer-col-title {
    font-size: 12px; font-weight: 500;
    text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--ink-3);
    margin: 0 0 12px;
}
.footer-col-list {
    list-style: none; margin: 0; padding: 0;
    display: flex; flex-direction: column; gap: 6px;
    font-size: 13px;
}
.footer-col-list a {
    color: var(--ink-2);
    transition: color 0.15s ease;
}
.footer-col-list a:hover { color: var(--ink); }
.footer-row-meta { font-size: 12.5px; color: var(--ink-4); }

/* Authenticated app (Dashboard + Admin)
   ============================================================================= */

.app-body { background: var(--paper); }

.app-header {
    border-bottom: 1px solid var(--line);
    background: #fff;
}

.admin-header {
    background: var(--admin-soft);
    border-bottom-color: var(--admin-ink);
}

.app-nav {
    display: flex; align-items: center; gap: 22px;
    font-size: 14px; color: var(--ink-3);
}

.app-nav a { transition: color 0.15s; }
.app-nav a:hover { color: var(--ink); }

/* Nav submenu — <details>/<summary> dropdown used inside .app-nav.
   Matches the visual weight of a regular nav link; the dropdown panel shares
   the visual language of the user-menu dropdown for consistency. */
.nav-submenu { position: relative; display: inline-block; }
.nav-submenu summary { list-style: none; cursor: pointer; }
.nav-submenu summary::-webkit-details-marker { display: none; }
.nav-submenu summary::marker { display: none; }

.nav-submenu-trigger {
    display: inline-flex; align-items: center; gap: 4px;
    font-size: 14px; color: var(--ink-3);
    transition: color 0.15s;
}
.nav-submenu-trigger:hover { color: var(--ink); }
.nav-submenu[open] .nav-submenu-trigger { color: var(--ink); }

.nav-submenu-caret { font-size: 10px; line-height: 1; opacity: 0.7; }
.nav-submenu[open] .nav-submenu-caret { transform: rotate(180deg); opacity: 1; }

.nav-submenu-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    min-width: 160px;
    padding: 6px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    box-shadow: 0 10px 30px -10px rgba(15, 18, 17, 0.15);
    z-index: 100;
}

.nav-submenu-item {
    display: block;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    font-size: 14px;
    color: var(--ink-2);
    text-decoration: none;
}
.nav-submenu-item:hover { background: var(--pulse-soft); color: var(--pulse-ink); }

/* Pending-approvals counter on the Watchers nav trigger + on the dropdown
   item itself, plus the per-page badge on the workspace-subtab Watchers
   link. Brand coral — a "you have work" signal, not a destructive marker. */
.nav-pending-badge {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 18px; height: 18px;
    padding: 0 6px;
    margin-left: 6px;
    background: var(--coral);
    color: #fff;
    border-radius: 999px;
    font-size: 11px; font-weight: 600;
    font-family: var(--font-mono);
    line-height: 1;
}
.nav-pending-badge-inline { margin-left: auto; }
.nav-submenu-item { display: flex; align-items: center; }

/* Admin shell — always dark, independent of the user's theme cookie.
   Uses a cooler sage-green as the accent (`--admin-accent`) so the chrome is
   tonally distinct from the customer app's vivid pulse-green while staying in
   the same colour family.
   ============================================================================= */
.admin-body {
    /* Force dark tokens. No theme-dark class needed — admin is dark, period. */
    --ink: #F5F5F2;
    --ink-2: #d4d0c3;
    --ink-3: #a0a79f;
    --ink-4: #6b7470;
    --paper: #0C120F;
    --paper-2: #1a2220;
    --paper-3: #252d2a;
    --line: rgba(255, 255, 255, 0.08);
    --line-2: rgba(255, 255, 255, 0.18);
    --pulse-soft: #13332a;
    --coral-soft: #3d2418;
    --amber-soft: #2e2414;
    --danger-soft: #2e1818;

    /* Admin accent — sage green. Distinct from the vivid `--pulse` the app uses
       for "service up" so admin chrome doesn't read as a status signal. */
    --admin-accent: #3cb88b;
    --admin-accent-soft: #142e25;
    --admin-accent-ink: #7fdcae;

    background: var(--paper);
    color: var(--ink);
    color-scheme: dark;
}

.admin-topbar {
    display: flex; align-items: center; justify-content: space-between;
    padding: 12px 24px;
    background: var(--paper-3);
    color: var(--ink);
    border-bottom: 2px solid var(--admin-accent);
    position: sticky; top: 0; z-index: 20;
}
.admin-topbar .brand,
.admin-topbar .brand-name,
.admin-topbar a { color: var(--ink); }
.admin-topbar .user-chip {
    color: var(--ink-2);
    background: rgba(255, 255, 255, 0.06);
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 13px;
    font-family: var(--font-mono);
}
.admin-topbar-action {
    padding: 6px 14px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font-size: 13px;
    color: var(--ink-2);
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.admin-topbar-action:hover {
    background: rgba(255, 255, 255, 0.04);
    border-color: var(--admin-accent);
    color: var(--admin-accent);
}

.admin-topbar-right { display: flex; align-items: center; gap: 14px; font-size: 14px; }

/* Admin badge next to the brand name — little amber pill that signals
   "you're in admin". Visually anchors the accent color. */
.admin-badge {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 8px;
    background: var(--admin-accent);
    color: #0C120F;
    font-size: 10.5px; font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-radius: 3px;
    vertical-align: middle;
}

.admin-shell {
    display: grid;
    grid-template-columns: 220px 1fr;
    min-height: calc(100vh - 56px);
}

.admin-sidebar {
    background: var(--paper-2);
    border-right: 1px solid var(--line);
    display: flex; flex-direction: column; justify-content: space-between;
    padding: 20px 0;
    /* Stick the nav at the bottom of the (already sticky) topbar so it
       stays put while only .admin-main scrolls. `align-self: start`
       stops the grid row from stretching the sidebar to full content
       height — sticky needs the item to be shorter than its
       containing block to have room to slide. Internal `overflow-y`
       handles the edge case where the nav list is taller than the
       viewport on a short screen. The 56px offset mirrors the
       --admin-shell min-height calc — keep the two in sync. */
    position: sticky;
    top: 56px;
    align-self: start;
    height: calc(100vh - 56px);
    overflow-y: auto;
}

.admin-sidebar nav { display: flex; flex-direction: column; gap: 2px; }

.admin-nav-link {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 20px;
    color: var(--ink-3);
    font-size: 14px;
    border-left: 3px solid transparent;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.admin-nav-link:hover { background: rgba(255, 255, 255, 0.04); color: var(--ink); }
.admin-nav-link-active {
    background: var(--admin-accent-soft);
    color: var(--admin-accent-ink);
    border-left-color: var(--admin-accent);
    font-weight: 500;
}

.admin-nav-icon {
    display: inline-block; width: 16px; text-align: center;
    font-size: 14px; color: inherit;
}

/* Collapsible nav group — used for the "Plan settings" section that holds
   Features / Limits / Probes. Native <details>/<summary>; the summary mimics
   .admin-nav-link styling so the group header sits flush with the flat links
   above and below. Chevron rotates 180° on open. */
.admin-nav-group { padding: 0; }
.admin-nav-group > summary {
    list-style: none;
    cursor: pointer;
}
.admin-nav-group > summary::-webkit-details-marker { display: none; }
.admin-nav-group > summary::marker { content: ""; }

.admin-nav-summary .admin-nav-label { flex: 1; }
.admin-nav-chevron {
    margin-left: auto;
    font-size: 11px;
    color: var(--ink-4);
    transition: transform 0.15s ease;
}
.admin-nav-group[open] > summary .admin-nav-chevron {
    transform: rotate(180deg);
}

/* Children of the Plan settings group. Indented past the icon column so the
   visual hierarchy reads "this lives under the parent". No icon — the indent
   alone signals "submenu item". Active state mirrors the flat-link active
   pattern so the operator sees "you are here" with the same colour cue. */
.admin-nav-sub { display: flex; flex-direction: column; gap: 2px; padding-top: 2px; }
.admin-nav-sublink {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 20px 8px 50px;
    color: var(--ink-3);
    font-size: 13.5px;
    border-left: 3px solid transparent;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.admin-nav-sublink:hover { background: rgba(255, 255, 255, 0.04); color: var(--ink); }
.admin-nav-sublink-active {
    background: var(--admin-accent-soft);
    color: var(--admin-accent-ink);
    border-left-color: var(--admin-accent);
    font-weight: 500;
}

.admin-sidebar-footer { padding: 0 20px; }
.admin-back-link {
    display: inline-block; padding: 8px 0;
    font-size: 13px; color: var(--ink-4);
}
.admin-back-link:hover { color: var(--ink); }

.admin-main {
    padding: 32px 40px;
    max-width: 1440px;
}

.admin-page-title {
    display: flex; align-items: baseline; justify-content: space-between;
    margin-bottom: 24px;
}
.admin-page-title h1 {
    font-family: var(--font-display); font-size: 28px; margin: 0;
    color: var(--ink);
}
.admin-page-title .section-kicker { margin-bottom: 6px; }

/* Admin-wide table style */
/* Occurrence-count badge shown next to a deduplicated error row — renders
   like "×7" in a small amber pill to communicate "this happened 7 times"
   without hiding the underlying message. */
.error-count-badge {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 8px;
    border-radius: 10px;
    background: var(--amber-soft, #fff1d6);
    color: #b8832b;
    font-size: 11.5px;
    font-weight: 600;
    vertical-align: 2px;
    font-variant-numeric: tabular-nums;
}

.admin-table {
    width: 100%;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    border-collapse: separate; border-spacing: 0;
    overflow: hidden;
    font-size: 14px;
    color: var(--ink-2);
}
.admin-table thead { background: var(--paper-3); }
.admin-table th {
    text-align: left; font-weight: 500;
    padding: 11px 16px;
    color: var(--ink-3);
    border-bottom: 1px solid var(--line);
    font-size: 12.5px;
    letter-spacing: 0.02em;
}
.admin-table td {
    padding: 12px 16px;
    border-top: 1px solid var(--line);
    color: var(--ink-2);
}
.admin-table tbody tr:first-child td { border-top: none; }
.admin-table tbody tr:hover { background: rgba(255, 255, 255, 0.03); }

.admin-table select,
.admin-table input[type="text"] {
    font: inherit;
    padding: var(--input-pad-y-xs) var(--input-pad-x-xs);
    background: var(--paper-3);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    color: var(--ink);
}

.admin-empty {
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 40px;
    text-align: center;
    color: var(--ink-3);
}

/* Reusable pager rendered by _AdminPager.cshtml beneath admin tables.
   Centred row of Prev / page-of-pages / Next. Disabled state mutes
   the buttons so the chrome stays consistent at the table edges. */
.admin-pager {
    display: flex; gap: 10px; justify-content: center; align-items: center;
    margin-top: 20px; font-size: 13px;
}
.admin-pager-btn { padding: 6px 14px; }
.admin-pager-btn-disabled { opacity: 0.4; pointer-events: none; }
.admin-pager-status { color: var(--ink-3); }

/* Shared components rendered inside admin pages that hardcode light-mode
   surfaces. Force dark equivalents so admin stays consistent. */
.admin-body .metric { background: var(--paper-2); color: var(--ink); }
.admin-body .metric-value { color: var(--ink); }
.admin-body .metric-label { color: var(--ink-4); }
.admin-body .plan-limit-form { background: var(--paper-2); border-color: var(--line-2); }
.admin-body .plan-limit-input { color: var(--ink); }
.admin-body .plan-limit-btn { background: var(--paper-3); color: var(--ink-3); }
.admin-body .plan-limit-btn:hover { background: var(--admin-accent-soft); color: var(--admin-accent); }
.admin-body .toggle-slider { background: var(--ink-4); }
.admin-body .toggle-switch input:checked + .toggle-slider { background: var(--admin-accent); }

/* Contrast fix — on the admin dark theme, the app-wide `--pulse` green is
   bright (#18D883). White text on it fails AA; force dark ink on every
   green-filled button inside .admin-body. */
.admin-body .btn-primary,
.admin-body .btn-entra-refresh { color: #0C120F; }
.admin-body .btn-primary:hover,
.admin-body .btn-entra-refresh:hover { color: #0C120F; }

/* Reusable form card for full-page forms (monitor create/edit, etc.).
   Mirrors the modal surface styling so the inputs track the theme cookie. */
.form-card {
    max-width: 640px;
    padding: 32px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
}
.form-card .field-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
.form-card input,
.form-card select,
.form-card textarea {
    width: 100%;
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font: inherit; font-size: 14px;
    background: var(--paper);
    color: var(--ink);
}
.form-card input:focus,
.form-card select:focus,
.form-card textarea:focus {
    outline: none;
    border-color: var(--pulse);
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
.form-card input:disabled,
.form-card input[readonly] {
    background: var(--paper-2);
    color: var(--ink-4);
    cursor: not-allowed;
}
.form-card .field label { display: block; margin-bottom: 6px; font-weight: 500; font-size: 13px; color: var(--ink-3); }
.form-card details summary { cursor: pointer; color: var(--ink-3); }
.form-card .field-error { color: var(--danger); font-size: 13px; }

/* Dark variant — matches modal-content dark overrides. */
body.app-body.theme-dark .form-card { background: var(--paper-2); }
body.app-body.theme-dark .form-card input,
body.app-body.theme-dark .form-card select,
body.app-body.theme-dark .form-card textarea {
    background: var(--paper-3);
    color: var(--ink);
    border-color: var(--line-2);
}
body.app-body.theme-dark .form-card input:focus,
body.app-body.theme-dark .form-card select:focus,
body.app-body.theme-dark .form-card textarea:focus { background: var(--paper-2); }
body.app-body.theme-dark .form-card input:disabled,
body.app-body.theme-dark .form-card input[readonly] {
    background: rgba(255, 255, 255, 0.04);
    color: var(--ink-4);
}
body.app-body.theme-dark .form-card .field label { color: var(--ink-2); }

/* Inline count badge next to a section heading ("Pending feedback 7"). */
.admin-pending-count {
    display: inline-block;
    margin-left: 8px;
    padding: 2px 10px;
    background: var(--coral-soft);
    color: var(--coral-ink);
    font-family: var(--font-mono);
    font-size: 12.5px; font-weight: 500;
    border-radius: 999px;
    vertical-align: middle;
}

/* Soft category chip used in admin tables. */
.admin-badge-soft {
    display: inline-block;
    padding: 3px 10px;
    background: var(--paper-2);
    color: var(--ink-3);
    border-radius: 999px;
    font-size: 12px; font-weight: 500;
}

.admin-toolbar {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 14px;
    gap: 12px;
}
.admin-toolbar .refresh-note {
    font-size: 12.5px; color: var(--ink-4);
    font-family: var(--font-mono);
}

/* Toggle switch — pill slider. This is the project-wide standard for every
   boolean toggle (app + admin). Use it instead of native checkboxes. Pattern:
     <label class="toggle-switch">
         <input type="checkbox" ... />
         <span class="toggle-slider"></span>
     </label>
   Colours follow the theme — `--pulse` in the app, `--admin-accent` under .admin-body. */
.toggle-switch {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 22px;
    vertical-align: middle;
}
.toggle-switch input {
    opacity: 0; width: 0; height: 0; margin: 0;
}
.toggle-slider {
    position: absolute; inset: 0;
    cursor: pointer;
    background: var(--ink-4);
    border-radius: 22px;
    transition: background 0.18s;
}
.toggle-slider::before {
    content: "";
    position: absolute;
    height: 16px; width: 16px;
    left: 3px; bottom: 3px;
    background: #fff;
    border-radius: 50%;
    transition: transform 0.18s;
    box-shadow: 0 1px 2px rgba(0,0,0,0.2);
}
.toggle-switch input:checked + .toggle-slider { background: var(--pulse); }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(18px); }
.toggle-switch input:focus-visible + .toggle-slider {
    box-shadow: 0 0 0 3px rgba(16, 192, 116, 0.25);
}

/* ============================================================================
   SSL monitor card — shared visual for MonitorType.Ssl everywhere it's
   rendered (authenticated dashboard, public status page, landing example).
   Two-column layout: left column carries the full cert property list, right
   column is a colour-coded "days until expiry" hero block.
   ============================================================================ */
.ssl-card {
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-left-width: 4px;
    border-left-color: var(--ink-4);
    border-radius: var(--radius-md);
    padding: 20px 24px;
    /* Mirror .service-row's vertical rhythm — when SSL/Domain cards
       and HTTP service-rows are stacked together inside .services
       (Dashboard tab), every card needs the same gap to its sibling. */
    margin-bottom: 8px;
}

/* Status tiers — same palette the HTTP sample-row uses so the two monitor
   types read visually consistent on the same page. Outer bg = soft tint,
   left border = the solid colour. Paused / Unknown fall back to neutral. */
.ssl-card-ok      { background: var(--pulse-soft);  border-left-color: var(--pulse); }
.ssl-card-warn    { background: var(--coral-soft);  border-left-color: var(--coral); }
.ssl-card-down    { background: var(--danger-soft); border-left-color: var(--danger); }
.ssl-card-paused  { border-left-color: var(--ink-4); }
.ssl-card-unknown { border-left-color: var(--ink-4); }
.ssl-card-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}
.ssl-card-info strong { display: block; font-size: 16px; color: var(--ink); }
.ssl-card-info .sample-meta {
    display: block;
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: var(--ink-4);
    margin-top: 4px;
}

.ssl-card-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(180px, 200px);
    gap: 20px;
    align-items: stretch;
}
@media (max-width: 620px) {
    /* Stack on narrow viewports so the details column doesn't crowd. */
    .ssl-card-grid { grid-template-columns: 1fr; }
}

/* Inner two-column layout for the property lists. Keeps the card short
   when there's lots of metadata — 9 rows stacked linearly would make the
   card dominate the page. */
.ssl-card-details {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 12px 24px;
}
@media (max-width: 820px) {
    /* Under 820 the two inner columns collapse into one so the labels
       don't get squeezed next to the narrow remaining space. */
    .ssl-card-details { grid-template-columns: 1fr; }
}

/* Narrow-container override: when the SSL card lives inside the landing
   right-column stack (mini-sample-stack), the *container* is much narrower
   than the viewport, so the viewport-keyed breakpoints above never fire.
   Force a single-column layout and shrink the days hero so the card stays
   readable next to the latency / SLA mini-charts. */
.mini-sample-stack .ssl-card { padding: 16px 18px; }
.mini-sample-stack .ssl-card-grid { grid-template-columns: 1fr; gap: 14px; }
.mini-sample-stack .ssl-card-details { grid-template-columns: 1fr; gap: 10px; }
.mini-sample-stack .ssl-card-props { grid-template-columns: 110px minmax(0, 1fr); gap: 4px 10px; }
.mini-sample-stack .ssl-card-days { padding: 12px; }
.mini-sample-stack .ssl-card-days-number { font-size: 36px; margin-bottom: 2px; }
.mini-sample-stack .ssl-card-days-unit { font-size: 12px; }

.ssl-card-props {
    display: grid;
    grid-template-columns: 120px minmax(0, 1fr);
    gap: 6px 12px;
    margin: 0;
    padding: 0;
    font-size: 13.5px;
    align-content: start;
}
.ssl-card-props dt { color: var(--ink-4); margin: 0; }
.ssl-card-props dd {
    color: var(--ink-2);
    margin: 0;
    font-family: var(--font-mono);
    font-size: 12.5px;
    word-break: break-word;
    overflow-wrap: anywhere;
}
.ssl-card-serial {
    /* Serial numbers are long hex strings; give them their own break rule so
       they wrap gracefully in the narrow left column. */
    word-break: break-all;
}

.ssl-card-days {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 16px;
    border-radius: var(--radius-md);
    border: 1px solid var(--line);
    min-height: 140px;
}
.ssl-card-days-number {
    font-family: var(--font-display);
    font-size: 56px;
    font-weight: 500;
    letter-spacing: -0.02em;
    line-height: 1;
    margin-bottom: 6px;
}
.ssl-card-days-unit {
    color: var(--ink-2);
    font-size: 13px;
    line-height: 1.4;
}

/* Colour tiers — mirror the status pill semantics so the eye can pattern-
   match red/amber/green across a page of monitors without reading the label. */
.ssl-expiry-ok {
    background: color-mix(in srgb, var(--pulse) 8%, transparent);
    border-color: color-mix(in srgb, var(--pulse) 30%, transparent);
}
.ssl-expiry-ok .ssl-card-days-number { color: var(--pulse-ink); }
.ssl-expiry-warn {
    background: color-mix(in srgb, #d9a14a 10%, transparent);
    border-color: color-mix(in srgb, #d9a14a 30%, transparent);
}
.ssl-expiry-warn .ssl-card-days-number { color: #b8832b; }
.ssl-expiry-down {
    background: color-mix(in srgb, #d94a4a 10%, transparent);
    border-color: color-mix(in srgb, #d94a4a 30%, transparent);
}
.ssl-expiry-down .ssl-card-days-number { color: #c23a3a; }
.ssl-expiry-unknown { background: var(--paper-2); }
.ssl-expiry-unknown .ssl-card-days-unit { color: var(--ink-4); }

.ssl-card-error {
    background: color-mix(in srgb, #d94a4a 8%, transparent);
    border-left: 3px solid #d94a4a;
    padding: 10px 14px;
    margin: 16px 0 0;
    font-size: 13.5px;
    color: var(--ink-2);
    font-family: var(--font-mono);
    border-radius: 4px;
    word-break: break-word;
}

/* ============================================================================
   Domain-expiration monitor card — same shape as .ssl-card. Two-column layout:
   left column carries the registration property list (registrar, name servers,
   status codes, DNSSEC, expires/registered dates), right column is a
   colour-coded "days until expiry" hero block. Drift incidents land on the
   .domain-card-down tier with an explanatory error footer.
   ============================================================================ */
.domain-card {
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-left-width: 4px;
    border-left-color: var(--ink-4);
    border-radius: var(--radius-md);
    padding: 20px 24px;
    /* Same rationale as .ssl-card above — keeps stacked card siblings
       evenly spaced on the Dashboard tab. */
    margin-bottom: 8px;
}

.domain-card-ok      { background: var(--pulse-soft);  border-left-color: var(--pulse); }
.domain-card-warn    { background: var(--coral-soft);  border-left-color: var(--coral); }
.domain-card-down    { background: var(--danger-soft); border-left-color: var(--danger); }
.domain-card-paused  { border-left-color: var(--ink-4); }
.domain-card-unknown { border-left-color: var(--ink-4); }

.domain-card-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 16px;
}
.domain-card-info strong { display: block; font-size: 16px; color: var(--ink); }
.domain-card-info .sample-meta {
    display: block;
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: var(--ink-4);
    margin-top: 4px;
}

.domain-card-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(180px, 200px);
    gap: 20px;
    align-items: stretch;
}
@media (max-width: 620px) {
    .domain-card-grid { grid-template-columns: 1fr; }
}

.domain-card-details {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 12px 24px;
}
@media (max-width: 820px) {
    .domain-card-details { grid-template-columns: 1fr; }
}

/* Narrow-container override mirroring the SSL card's mini-sample-stack
   handling — for consistency if the domain card ever lands in the landing
   right-column. */
.mini-sample-stack .domain-card { padding: 16px 18px; }
.mini-sample-stack .domain-card-grid { grid-template-columns: 1fr; gap: 14px; }
.mini-sample-stack .domain-card-details { grid-template-columns: 1fr; gap: 10px; }
.mini-sample-stack .domain-card-props { grid-template-columns: 110px minmax(0, 1fr); gap: 4px 10px; }
.mini-sample-stack .domain-card-days { padding: 12px; }
.mini-sample-stack .domain-card-days-number { font-size: 36px; margin-bottom: 2px; }
.mini-sample-stack .domain-card-days-unit { font-size: 12px; }

.domain-card-props {
    display: grid;
    grid-template-columns: 120px minmax(0, 1fr);
    gap: 6px 12px;
    margin: 0;
    padding: 0;
    font-size: 13.5px;
    align-content: start;
}
.domain-card-props dt { color: var(--ink-4); margin: 0; }
.domain-card-props dd {
    color: var(--ink-2);
    margin: 0;
    font-family: var(--font-mono);
    font-size: 12.5px;
    word-break: break-word;
    overflow-wrap: anywhere;
}
.domain-card-status-codes {
    /* Status codes can be long camelCase strings (clientTransferProhibited);
       break aggressively so they don't push the right hero off-screen. */
    word-break: break-all;
}

.domain-card-days {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 16px;
    border-radius: var(--radius-md);
    border: 1px solid var(--line);
    min-height: 140px;
}
.domain-card-days-number {
    font-family: var(--font-display);
    font-size: 56px;
    font-weight: 500;
    letter-spacing: -0.02em;
    line-height: 1;
    margin-bottom: 6px;
}
.domain-card-days-unit {
    color: var(--ink-2);
    font-size: 13px;
    line-height: 1.4;
}

.domain-expiry-ok {
    background: color-mix(in srgb, var(--pulse) 8%, transparent);
    border-color: color-mix(in srgb, var(--pulse) 30%, transparent);
}
.domain-expiry-ok .domain-card-days-number { color: var(--pulse-ink); }
.domain-expiry-warn {
    background: color-mix(in srgb, #d9a14a 10%, transparent);
    border-color: color-mix(in srgb, #d9a14a 30%, transparent);
}
.domain-expiry-warn .domain-card-days-number { color: #b8832b; }
.domain-expiry-down {
    background: color-mix(in srgb, #d94a4a 10%, transparent);
    border-color: color-mix(in srgb, #d94a4a 30%, transparent);
}
.domain-expiry-down .domain-card-days-number { color: #c23a3a; }
.domain-expiry-unknown { background: var(--paper-2); }
.domain-expiry-unknown .domain-card-days-unit { color: var(--ink-4); }

.domain-card-error {
    background: color-mix(in srgb, #d94a4a 8%, transparent);
    border-left: 3px solid #d94a4a;
    padding: 10px 14px;
    margin: 16px 0 0;
    font-size: 13.5px;
    color: var(--ink-2);
    font-family: var(--font-mono);
    border-radius: 4px;
    word-break: break-word;
}

/* Disabled-but-rendered state. Applied when a feature/flag is gated so the
   cell keeps the same footprint as an active toggle — operator sees *why*
   it's grey and read-only (via the hint message elsewhere on the page). */
.toggle-switch-disabled .toggle-slider { cursor: not-allowed; opacity: 0.45; }
.toggle-switch-disabled .toggle-slider::before { box-shadow: none; }

/* Small inline action button for admin table rows (ghost-style). */
.btn-admin-row {
    display: inline-block;
    padding: 4px 12px;
    font-size: 12.5px;
    color: var(--pulse-ink);
    background: #fff;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    transition: background 0.12s, border-color 0.12s;
}
.btn-admin-row:hover {
    background: var(--pulse-soft);
    border-color: var(--pulse);
}

/* "Refresh from Entra" — pulse-green filled button, darker green hover.
   Reads as an active primary action inside the admin chrome. */
.btn-entra-refresh {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 8px 16px;
    font-size: 13px; font-weight: 500;
    color: #fff;
    background: var(--pulse);
    border: 1px solid var(--pulse);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s, transform 0.12s;
}
.btn-entra-refresh:hover {
    background: var(--pulse-ink);
    border-color: var(--pulse-ink);
    transform: translateY(-1px);
}
.btn-entra-refresh:disabled {
    opacity: 0.6; cursor: not-allowed; transform: none;
}

.user-chip {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink-3);
    padding: 3px 10px;
    background: var(--paper-2);
    border-radius: 999px;
}

.sign-out {
    padding: 6px 12px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font-size: 13px;
}

.sign-out:hover { background: var(--pulse); color: #fff; border-color: var(--pulse); }

.app-main { padding: 48px 24px 80px; }

.dashboard-placeholder h1 {
    font-family: var(--font-display);
    font-size: 36px;
    font-weight: 500;
    margin-bottom: 12px;
    letter-spacing: -0.02em;
}

.dashboard-lede {
    font-size: 16px;
    color: var(--ink-3);
    line-height: 1.6;
    max-width: 640px;
    margin-bottom: 32px;
}

.dashboard-debug {
    margin-top: 32px;
    padding: 24px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
}

.dashboard-debug code {
    background: var(--paper-2);
    padding: 1px 6px;
    border-radius: 4px;
}

/* Admin
   ============================================================================= */

.admin-overview h1 {
    font-family: var(--font-display);
    font-size: 36px;
    font-weight: 500;
    margin-bottom: 12px;
    letter-spacing: -0.02em;
}

.metric-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 14px;
    margin-top: 24px;
}

.metric {
    padding: 20px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
}

.metric-label {
    font-size: 12px;
    color: var(--ink-4);
    letter-spacing: 0.08em;
    text-transform: uppercase;
    margin-bottom: 8px;
}

.metric-value {
    font-family: var(--font-display);
    font-size: 32px;
    font-weight: 500;
    color: var(--ink);
    letter-spacing: -0.02em;
}

/* Comparison pages (/vs/{competitor})
   =============================================================================
   Structured comparison layout: TL;DR header → at-a-glance stat cards →
   pricing table → feature matrix → honest "pick which" lateral cards →
   migration steps → CTA. Section spacing is loose so the page reads as
   long-form, not as a cramped grid. */

.vs-page {
    max-width: 1120px;
    padding: 32px 24px 80px;
    margin: 0 auto;
    color: var(--ink);
}
.vs-header {
    margin-bottom: 56px;
}
.vs-header h1 {
    font-family: var(--font-display);
    font-size: clamp(28px, 4vw, 44px);
    line-height: 1.1;
    margin: 16px 0 14px;
}
.vs-vs {
    color: var(--ink-3);
    font-weight: 500;
    font-style: italic;
    font-size: 0.7em;
    margin: 0 4px;
}
.vs-lede {
    font-size: 18px;
    line-height: 1.55;
    color: var(--ink-2);
    max-width: 760px;
}
.vs-stamp {
    margin-top: 18px;
    font-size: 13px;
    color: var(--ink-4);
}

.vs-page section {
    margin-bottom: 56px;
}
.vs-page section h2 {
    font-family: var(--font-display);
    font-size: 24px;
    margin: 0 0 18px;
}
.vs-section-lede {
    color: var(--ink-3);
    margin-bottom: 20px;
    font-size: 15px;
    line-height: 1.6;
}

/* At-a-glance — 3 stat cards */
.vs-glance-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 18px;
}
.vs-glance-card {
    padding: 22px 22px 24px;
    background: var(--pulse-soft);
    border-radius: 12px;
    border-left: 3px solid var(--pulse);
}
.vs-glance-stat {
    font-family: var(--font-display);
    font-size: 36px;
    font-weight: 700;
    color: var(--pulse-ink);
    line-height: 1;
    margin: 0 0 4px;
}
.vs-glance-stat em {
    font-style: italic;
    font-size: 0.85em;
    color: var(--ink-3);
}
.vs-glance-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink-2);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin: 0 0 10px;
}
.vs-glance-body {
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-2);
    margin: 0;
}
@media (max-width: 760px) {
    .vs-glance-grid { grid-template-columns: 1fr; }
}

/* Tables — pricing + feature matrix */
.vs-table-wrap {
    overflow-x: auto;
}
.vs-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14.5px;
}
.vs-table th, .vs-table td {
    padding: 11px 14px;
    text-align: left;
    border-bottom: 1px solid var(--line);
    vertical-align: top;
}
.vs-table th {
    font-weight: 600;
    color: var(--ink);
    background: var(--paper-2);
    border-bottom: 2px solid var(--line);
    text-align: center;
}
.vs-table th:first-child {
    text-align: left;
    background: transparent;
}
.vs-table td:nth-child(2),
.vs-table td:nth-child(3) {
    text-align: center;
}
.vs-table-pricing td:first-child {
    font-weight: 500;
}
.vs-good { color: var(--pulse-ink); }
.vs-good strong { color: var(--pulse-ink); }
.vs-yes { color: var(--pulse-ink); font-weight: 500; }
.vs-no { color: var(--ink-4); }
.vs-partial { color: #b87900; font-weight: 500; }
.vs-row-section td {
    background: var(--paper-2);
    font-size: 12px;
    font-weight: 700;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    padding: 8px 14px;
    text-align: left !important;
}
.vs-table-note {
    margin-top: 14px;
    font-size: 13.5px;
    color: var(--ink-3);
    line-height: 1.6;
    padding: 12px 16px;
    background: var(--paper-2);
    border-left: 3px solid var(--ink-4);
    border-radius: 0 6px 6px 0;
}

/* Honest "pick which" lateral cards */
.vs-honest-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
}
.vs-honest {
    padding: 24px 26px;
    border-radius: 12px;
    border: 1px solid var(--line);
    background: var(--paper);
}
.vs-honest-us {
    background: var(--pulse-soft);
    border-color: var(--pulse);
    border-width: 1px;
}
.vs-honest h3 {
    font-family: var(--font-display);
    font-size: 20px;
    margin: 0 0 14px;
}
.vs-honest-us h3 { color: var(--pulse-ink); }
.vs-honest ul {
    margin: 0;
    padding-left: 18px;
}
.vs-honest li {
    margin-bottom: 12px;
    line-height: 1.6;
    color: var(--ink-2);
    font-size: 14.5px;
}
.vs-honest li strong {
    color: var(--ink);
}
@media (max-width: 760px) {
    .vs-honest-grid { grid-template-columns: 1fr; }
}

/* Migration steps */
.vs-migration ol {
    padding-left: 20px;
    margin: 0;
}
.vs-migration li {
    margin-bottom: 14px;
    line-height: 1.6;
    color: var(--ink-2);
}
.vs-migration code {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 0.92em;
    font-family: var(--font-mono);
}

/* Final CTA */
.vs-cta {
    padding: 32px 28px;
    background: var(--pulse-soft);
    border-radius: 14px;
    text-align: center;
    margin-bottom: 0;
}
.vs-cta h2 {
    margin: 0 0 8px;
    color: var(--pulse-ink);
}
.vs-cta p {
    color: var(--ink-2);
    margin: 0 0 18px;
    font-size: 15px;
}
.vs-cta-buttons {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
}

/* Feature detail pages (/features/{slug})
   =============================================================================
   One page per feature card on the landing. Same visual grammar as the
   /vs/* pages — max-width 960, display-font H1, lede in --ink-2, section
   gap 56px — but with a parameter table specific to the per-feature
   config surface. The CTA at the bottom mirrors .vs-cta exactly. */
.feature-detail {
    max-width: 1120px;
    padding: 32px 24px 80px;
    margin: 0 auto;
    color: var(--ink);
}
.feature-detail-header {
    margin-bottom: 56px;
}
.feature-detail-eyebrow {
    font-size: 13px;
    font-weight: 600;
    color: var(--pulse-ink);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin: 16px 0 12px;
}
.feature-detail-header h1 {
    font-family: var(--font-display);
    font-size: clamp(28px, 4vw, 44px);
    line-height: 1.1;
    margin: 0 0 14px;
}
.feature-detail-lede {
    font-size: 18px;
    line-height: 1.55;
    color: var(--ink-2);
    max-width: 760px;
    margin: 0;
}
.feature-detail-body .feature-detail-section {
    margin-bottom: 56px;
}
.feature-detail-body h2 {
    font-family: var(--font-display);
    font-size: 24px;
    margin: 0 0 18px;
}
.feature-detail-body p,
.feature-detail-body li {
    font-size: 15px;
    line-height: 1.65;
    color: var(--ink-2);
}
.feature-detail-body p { margin: 0 0 14px; }
.feature-detail-body ul,
.feature-detail-body ol {
    padding-left: 20px;
    margin: 0 0 14px;
}
.feature-detail-body li { margin-bottom: 8px; }
.feature-detail-body li strong { color: var(--ink); }
.feature-detail-body code {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 0.92em;
    font-family: var(--font-mono);
}

/* Parameters table — same chrome as .vs-table but left-aligned across
   all columns (the matrix's centred Yes/No cells don't apply to
   prose-heavy parameter descriptions). */
.feature-params-wrap {
    overflow-x: auto;
}
.feature-params {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    /* Fixed layout so cell content doesn't push the Description column
       narrower than the explicit %-widths below. The 5 columns are:
       Field, Type, Required, Default, Description. Description gets the
       lion's share of width because it carries the prose. */
    table-layout: fixed;
}
.feature-params col:nth-child(1) { width: 18%; }
.feature-params col:nth-child(2) { width: 17%; }
.feature-params col:nth-child(3) { width: 11%; }
.feature-params col:nth-child(4) { width: 12%; }
.feature-params col:nth-child(5) { width: 42%; }
.feature-params th,
.feature-params td {
    padding: 11px 14px;
    text-align: left;
    border-bottom: 1px solid var(--line);
    vertical-align: top;
}
.feature-params th {
    font-weight: 600;
    color: var(--ink);
    background: var(--paper-2);
    border-bottom: 2px solid var(--line);
}
.feature-params td code {
    background: var(--paper-2);
    color: var(--ink-2);
    padding: 1px 6px;
    border-radius: 4px;
    font-size: 0.92em;
    font-family: var(--font-mono);
    /* Long Type values like "en-US, en-GB, pt-PT, …" or enum lists
       must wrap inside their fixed-width column instead of bulldozing
       the Description into a 1-word ribbon. break-word handles the
       worst case (a single hyperlong identifier with no spaces). */
    white-space: normal;
    word-break: break-word;
}

/* Pricing tier callout — a discreet single-line block sitting between
   the technical section and the related links. Tells the prospect
   which plan unlocks the feature and offers the help link as an exit
   ramp for the technically-curious. Same paper-2 background as the
   tables so it doesn't fight for attention. */
.feature-detail-tier {
    background: var(--paper-2);
    border-left: 3px solid var(--pulse);
    border-radius: 0 6px 6px 0;
    padding: 14px 18px;
    margin-bottom: 32px;
}
.feature-detail-tier-line {
    margin: 0;
    font-size: 14.5px;
    color: var(--ink-2);
    line-height: 1.55;
}
.feature-detail-tier-line strong { color: var(--ink); }
.feature-detail-tier-line a {
    color: var(--pulse-ink);
    text-decoration: none;
    border-bottom: 1px dotted var(--pulse);
}
.feature-detail-tier-line a:hover { border-bottom-style: solid; }

/* Related links — small pill cards instead of a bulleted list, so the
   cross-link section reads as navigation rather than narrative. */
.feature-related-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}
.feature-related-list li { margin: 0; }
.feature-related-list a {
    display: inline-block;
    padding: 8px 14px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--ink);
    text-decoration: none;
    font-size: 13.5px;
    transition: background-color 120ms ease, border-color 120ms ease;
}
.feature-related-list a:hover,
.feature-related-list a:focus-visible {
    background: var(--pulse-soft);
    border-color: var(--pulse);
    color: var(--pulse-ink);
    outline: none;
}

/* CTA — verbatim layout from .vs-cta so every page in the marketing
   spine closes with the same affordance. */
.feature-detail-cta {
    padding: 32px 28px;
    background: var(--pulse-soft);
    border-radius: 14px;
    text-align: center;
    margin-bottom: 0;
}
.feature-detail-cta h2 {
    font-family: var(--font-display);
    margin: 0 0 8px;
    color: var(--pulse-ink);
}
.feature-detail-cta p {
    color: var(--ink-2);
    margin: 0 0 18px;
    font-size: 15px;
}
.feature-detail-cta-buttons {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
}

/* Guides hub + individual guide pages (/guides/, /guides/{slug})
   =============================================================================
   Cornerstone long-form SEO content. The hub page lists every guide as a
   row card; each guide is typography-rich, narrow column for reading, with
   a sticky TOC on the right (collapses below the article on narrow screens).
   The bottom CTA is the same on every page. */

/* Hub */
.guides-index {
    max-width: 1040px;
    padding: 32px 24px 80px;
    margin: 0 auto;
    color: var(--ink);
}

/* Features index (/features) — six grouped sections, each a heading +
   lede + grid of .feature cards (the same class used everywhere else).
   Same overall shell as .guides-index but a touch wider so a 3-up
   feature grid breathes. */
.features-page,
.probes-page {
    max-width: 1200px;
    padding: 32px 24px 80px;
    margin: 0 auto;
    color: var(--ink);
}
.features-page-header,
.probes-page-header {
    margin-bottom: 36px;
}
.features-page-header h1,
.probes-page-header h1 {
    font-family: var(--font-display);
    font-size: clamp(32px, 4.4vw, 48px);
    line-height: 1.1;
    margin: 16px 0 12px;
}
.features-page-lede {
    font-size: 17px;
    line-height: 1.55;
    color: var(--ink-2);
    max-width: 720px;
}
.features-page-lede a { color: var(--pulse); }
.features-page-lede a:hover { text-decoration: underline; }

.features-group {
    margin: 56px 0 0;
}
.features-group:first-of-type { margin-top: 32px; }
.features-group-head {
    margin-bottom: 18px;
    max-width: 760px;
}
.features-group-head h2 {
    font-family: var(--font-display);
    font-size: 24px;
    font-weight: 500;
    letter-spacing: -0.015em;
    margin: 0 0 8px;
}
.features-group-head p {
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--ink-3);
}

/* Bottom "Ready to start?" CTA card on both /features and /probes —
   tight box with two buttons. Echoes the contact-form card visuals. */
.features-page-cta {
    margin: 64px auto 0;
    max-width: 720px;
    text-align: center;
    padding: 32px 24px;
    background: var(--paper-2);
    border-radius: var(--radius-lg);
}
.features-page-cta h2 {
    font-family: var(--font-display);
    font-size: 22px;
    font-weight: 500;
    margin: 0 0 8px;
}
.features-page-cta p {
    font-size: 14.5px;
    color: var(--ink-3);
    margin: 0 0 16px;
    line-height: 1.55;
}
.features-page-cta-actions {
    display: inline-flex; gap: 10px; flex-wrap: wrap;
    justify-content: center;
}
.guides-index-header {
    margin-bottom: 40px;
}
.guides-index-header h1 {
    font-family: var(--font-display);
    font-size: clamp(32px, 4.4vw, 48px);
    line-height: 1.1;
    margin: 16px 0 12px;
}
.guides-index-lede {
    font-size: 18px;
    line-height: 1.55;
    color: var(--ink-2);
    max-width: 680px;
}
/* Section header inside the hub — splits "Compare & choose" from
   "Probe deep dives" so 13 cards don't feel like a wall. */
.guides-section-title {
    font-family: var(--font-display);
    font-size: 14px;
    font-weight: 700;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.12em;
    margin: 32px 0 16px;
}
.guides-section-title:first-of-type { margin-top: 8px; }

/* 3-column grid of roughly-square cards. Collapses to 2 cols on
   tablet, 1 col on mobile. Each card is a flex column so the
   "Read guide →" CTA stays anchored at the bottom regardless of
   description length. */
.guides-list {
    list-style: none;
    padding: 0;
    margin: 0 0 24px;
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 16px;
}
@media (max-width: 900px) {
    .guides-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
    .guides-list { grid-template-columns: 1fr; }
}
.guides-list-item {
    display: flex;
}
.guides-list-link {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-height: 240px;
    padding: 20px 22px 18px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 12px;
    text-decoration: none;
    color: var(--ink);
    transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.guides-list-link:hover {
    border-color: var(--pulse);
    transform: translateY(-2px);
    box-shadow: 0 8px 24px -12px rgba(15, 18, 17, 0.12);
}
.guides-list-eyebrow {
    font-size: 10.5px;
    font-weight: 700;
    color: var(--pulse-ink);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin: 0 0 12px;
}
.guides-list-link h2 {
    font-family: var(--font-display);
    font-size: 17px;
    margin: 0 0 10px;
    line-height: 1.25;
    color: var(--ink);
}
.guides-list-link p {
    color: var(--ink-2);
    margin: 0 0 14px;
    font-size: 14px;
    line-height: 1.5;
    /* clamp to ~4 lines so cards stay roughly the same height */
    display: -webkit-box;
    -webkit-line-clamp: 4;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.guides-list-link code {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    padding: 1px 5px;
    border-radius: 3px;
    font-size: 0.9em;
    font-family: var(--font-mono);
}
.guides-list-cta {
    color: var(--pulse-ink);
    font-weight: 600;
    font-size: 13.5px;
    margin-top: auto;
}

/* Individual guide page */
.guide-page {
    max-width: 820px;
    padding: 32px 24px 80px;
    margin: 0 auto;
    color: var(--ink);
}
.guide-header {
    margin-bottom: 32px;
    padding-bottom: 28px;
    border-bottom: 1px solid var(--line);
}
.guide-eyebrow {
    font-size: 12px;
    font-weight: 600;
    color: var(--pulse-ink);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin: 16px 0 12px;
}
.guide-header h1 {
    font-family: var(--font-display);
    font-size: clamp(30px, 4.2vw, 42px);
    line-height: 1.15;
    margin: 0 0 14px;
    letter-spacing: -0.5px;
}
.guide-lede {
    font-size: 19px;
    line-height: 1.55;
    color: var(--ink-2);
    margin: 0 0 18px;
}
.guide-meta {
    font-size: 13.5px;
    color: var(--ink-4);
}

.guide-toc {
    background: var(--pulse-soft);
    border-left: 3px solid var(--pulse);
    border-radius: 0 8px 8px 0;
    padding: 16px 20px;
    margin: 0 0 32px;
}
.guide-toc-title {
    font-size: 12px;
    font-weight: 700;
    color: var(--pulse-ink);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin: 0 0 8px;
}
.guide-toc ol {
    list-style: decimal;
    padding-left: 24px;
    margin: 0;
}
.guide-toc li {
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--ink-2);
    margin-bottom: 4px;
}
.guide-toc a {
    color: var(--pulse-ink);
    text-decoration: none;
}
.guide-toc a:hover { text-decoration: underline; }

.guide-body {
    font-size: 17px;
    line-height: 1.7;
    color: var(--ink);
}
.guide-body h2 {
    font-family: var(--font-display);
    font-size: 26px;
    line-height: 1.2;
    margin: 48px 0 16px;
    padding-top: 20px;
    border-top: 1px solid var(--line);
    scroll-margin-top: 80px;
    letter-spacing: -0.3px;
}
.guide-body h2:first-of-type {
    border-top: 0;
    padding-top: 0;
    margin-top: 0;
}
.guide-body h3 {
    font-family: var(--font-display);
    font-size: 19px;
    line-height: 1.25;
    margin: 32px 0 12px;
    scroll-margin-top: 80px;
}
.guide-body p {
    margin: 0 0 16px;
    color: var(--ink-2);
}
.guide-body ul, .guide-body ol {
    margin: 0 0 18px;
    padding-left: 24px;
    color: var(--ink-2);
}
.guide-body li {
    margin-bottom: 8px;
    line-height: 1.65;
}
.guide-body strong { color: var(--ink); }
.guide-body code {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    padding: 1.5px 6px;
    border-radius: 4px;
    font-size: 0.92em;
    font-family: var(--font-mono);
}
.guide-body pre {
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 14px 18px;
    font-size: 14px;
    line-height: 1.55;
    font-family: var(--font-mono);
    overflow-x: auto;
    margin: 0 0 20px;
}
.guide-body pre code {
    background: transparent;
    color: var(--ink);
    padding: 0;
    font-size: inherit;
}
.guide-body blockquote {
    border-left: 3px solid var(--pulse);
    background: var(--pulse-soft);
    padding: 14px 18px;
    margin: 0 0 20px;
    border-radius: 0 6px 6px 0;
    color: var(--pulse-ink);
    font-style: italic;
}
.guide-body blockquote p:last-child { margin-bottom: 0; }
.guide-body table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 20px;
    font-size: 15px;
}
.guide-body th, .guide-body td {
    text-align: left;
    padding: 10px 14px;
    border-bottom: 1px solid var(--line);
    vertical-align: top;
}
.guide-body th {
    background: var(--paper-2);
    font-weight: 600;
}
.guide-body a {
    color: var(--pulse-ink);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 2px;
}
.guide-body a:hover { text-decoration-thickness: 2px; }

/* Bottom CTA — shared between guides hub and individual guides */
.guides-cta, .guide-cta {
    margin-top: 56px;
    padding: 32px 28px;
    background: var(--pulse-soft);
    border-radius: 14px;
    text-align: center;
}
.guides-cta h2, .guide-cta h2 {
    font-family: var(--font-display);
    margin: 0 0 10px;
    color: var(--pulse-ink);
    font-size: 24px;
}
.guides-cta p, .guide-cta p {
    color: var(--ink-2);
    margin: 0 0 18px;
    font-size: 15.5px;
}
.guides-cta-buttons, .guide-cta-buttons {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
}

/* Legal pages
   ============================================================================= */

.legal-page {
    max-width: 960px;
    padding: 48px 24px 80px;
}

.legal-page h1 {
    font-family: var(--font-display);
    font-size: 40px;
    font-weight: 500;
    letter-spacing: -0.02em;
    margin-bottom: 8px;
}

.legal-page h2 {
    font-family: var(--font-display);
    font-size: 22px;
    margin-top: 32px;
    margin-bottom: 12px;
}

.legal-page h3 {
    font-family: var(--font-display);
    font-size: 17px;
    font-weight: 500;
    margin-top: 20px;
    margin-bottom: 8px;
    color: var(--ink);
}

.legal-page p, .legal-page ul { font-size: 15.5px; line-height: 1.7; color: var(--ink-2); margin-bottom: 12px; }
.legal-page ul { padding-left: 20px; list-style: disc; }
.legal-page li { margin-bottom: 6px; }

.legal-page code {
    font-family: var(--font-mono);
    font-size: 13.5px;
    background: var(--paper-2);
    padding: 1px 6px;
    border-radius: 4px;
    color: var(--ink);
}

/* Plain-language summary at the top of a policy page. Gives the TL;DR
   before the legalese — mirrors the pattern that Stripe / Vercel / Linear
   use, and keeps readers oriented. */
.legal-callout {
    background: var(--pulse-soft);
    border-left: 3px solid var(--pulse);
    padding: 16px 20px;
    border-radius: var(--radius-sm);
    font-size: 15px;
    line-height: 1.65;
    color: var(--ink-2);
    margin: 12px 0 28px;
}
.legal-callout strong { color: var(--pulse-ink); }
.legal-callout a { color: var(--pulse-ink); text-decoration: underline; }

.legal-kicker {
    font-size: 12.5px;
    color: var(--ink-4);
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin-bottom: 32px;
}

/* Animations
   ============================================================================= */

@keyframes sp-pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.5; transform: scale(1.25); }
}

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

/* Responsive
   ============================================================================= */

@media (max-width: 960px) {
    .hero { grid-template-columns: 1fr; gap: 40px; padding-top: 48px; }
    .feature-grid { grid-template-columns: 1fr; gap: 32px; }
    .compare-grid { grid-template-columns: repeat(2, 1fr); }
    .pricing-grid { grid-template-columns: repeat(2, 1fr); }
    .waitlist { grid-template-columns: 1fr; gap: 32px; }
    .metric-grid { grid-template-columns: 1fr; }
    .site-nav a:not(.nav-cta) { display: none; }
    .app-nav a:not(.sign-out) { display: none; }
}

@media (max-width: 520px) {
    .hero-title { font-size: 36px; }
    .pricing-grid { grid-template-columns: 1fr; }
    .hero-actions { flex-direction: column; align-items: stretch; }
    .btn { justify-content: center; }
    .footer-row { flex-direction: column; gap: 16px; align-items: flex-start; }
    .footer-columns { grid-template-columns: 1fr 1fr; gap: 24px; }
}

/* Sub-tablet collapse for the 4-column footer link grid — Brand column
   wraps full-width above the three link columns so the inline-block
   columns stay readable on iPad-portrait widths. */
@media (max-width: 820px) and (min-width: 521px) {
    .footer-columns { grid-template-columns: repeat(3, 1fr); }
    .footer-col-brand { grid-column: 1 / -1; }
}

/* Dark theme — applied via <body class="theme-dark"> on /Dark.
   Throwaway variant for A/B visual comparison; delete once the direction is chosen.
   ============================================================================= */

body.theme-dark {
    /* Neutrals inverted — primary + muted from brand manual, intermediate
       scale points derived to preserve the 4-tier hierarchy. */
    --ink:   #F5F5F2;   /* color.text.primary (dark)              */
    --ink-2: #d6d6d3;   /* derived — secondary text               */
    --ink-3: #9BA8A2;   /* color.text.muted   (dark)              */
    --ink-4: #6c7872;   /* derived — super-muted                  */

    --paper:   #0C120F;  /* color.page.bg (dark) */
    --paper-2: #122A20;  /* color.card.bg (dark) — green-tinted card from brand */
    --paper-3: #214435;  /* color.card.border (dark) — slightly lighter        */
    --line:   rgba(245, 245, 242, 0.08);
    --line-2: rgba(245, 245, 242, 0.18);

    /* Pulse green — same accent in both modes per brand manual. The
       soft/ink role swap survives: --pulse-soft becomes a dim brand-bg
       tint, --pulse-ink becomes a brightened tint for accent text. */
    --pulse:      #18D883;
    --pulse-soft: #122A20;   /* color.card.bg (dark) — same as --paper-2 */
    --pulse-ink:  #5fe5a7;   /* derived — brightened for dark contrast   */

    /* Brand incident red — softer pink for dark contrast, per manual. */
    --incident:      #F09595;  /* color.incident (dark) */
    --incident-soft: #3d1a1a;  /* derived dim tint      */

    /* Brand card surface (dark variant) */
    --brand-card-bg:     #122A20;
    --brand-card-border: #214435;
    --brand-wordmark:    #F5F5F2;

    /* Semantic warn/down — kept brightened for dark contrast (same values
       as the previous platform palette). These are NOT brand colours;
       they're status indicators. */
    --coral:      #ff8a3a;
    --coral-soft: #3d2418;
    --coral-ink:  #ffb27a;
    --amber-soft: #2e2414;
    --danger-soft: #2e1818;

    background: var(--paper);
    color: var(--ink);
}

/* Cards / widgets / form surfaces that were hardcoded to #fff need an explicit override. */
body.theme-dark .status-widget,
body.theme-dark .status-widget-sample,
body.theme-dark .mini-sample,
body.theme-dark .plan,
body.theme-dark .waitlist-form,
body.theme-dark .seg-selected,
body.theme-dark .form-success {
    background: var(--paper-2);
}
body.theme-dark .mini-sample-chip { background: var(--paper-3); color: var(--ink-3); }
body.theme-dark .mini-sample-chip-ok { background: var(--pulse-soft); color: var(--pulse); }
body.theme-dark .mini-chart-axis { stroke: rgba(255, 255, 255, 0.18); }
body.theme-dark .mini-chart-grid { stroke: rgba(255, 255, 255, 0.06); }
body.theme-dark .mini-chart-label { fill: var(--ink-4); }
body.theme-dark .mini-chart-trend { stroke: #fbbf24; }
body.theme-dark .mini-legend-trend { border-top-color: #fbbf24; }

/* Sample rows — pull the neutral row bg up from --paper-2 so tinted rows still
   stand apart when the widget card is already on --paper-2. */
body.theme-dark .sample-row { background: var(--paper-3); }
body.theme-dark .sample-row-ok   { background: var(--pulse-soft); }
body.theme-dark .sample-row-warn { background: var(--coral-soft); }
body.theme-dark .sample-row-down { background: var(--danger-soft); }

/* <li> wrapper class used when the partial renders inside a <ul.sample-services>
   list (e.g. /Dashboard/Probes). The .ssl-card inside is self-framed —
   the <li> just has to get out of the way. */
.sample-services > li.service-row-ssl {
    display: block;
    padding: 0;
    /* Match .sample-row's bottom margin so SSL rows don't collapse against
       the next monitor in the list. The wrapper itself has no chrome — only
       the spacing carries over from the standard row. */
    margin: 0 0 8px 0;
    background: transparent;
    border: 0;
}

/* SSL card follows the same bg re-tinting on dark theme — the --pulse-soft /
   --coral-soft / --danger-soft tokens already map to muted dark-theme values,
   but the default (.ssl-card without a status modifier) needs --paper-3 so
   it's lighter than the surrounding --paper background. */
body.theme-dark .ssl-card           { background: var(--paper-3); }
body.theme-dark .ssl-card-ok        { background: var(--pulse-soft); }
body.theme-dark .ssl-card-warn      { background: var(--coral-soft); }
body.theme-dark .ssl-card-down      { background: var(--danger-soft); }

/* Domain-expiration card mirrors the SSL dark-theme treatment 1:1. */
body.theme-dark .domain-card        { background: var(--paper-3); }
body.theme-dark .domain-card-ok     { background: var(--pulse-soft); }
body.theme-dark .domain-card-warn   { background: var(--coral-soft); }
body.theme-dark .domain-card-down   { background: var(--danger-soft); }

/* Same treatment for the compact monitor rows on /Dashboard. */
body.theme-dark .workspace-monitor           { background: var(--paper-3); }
body.theme-dark .workspace-monitor-ok        { background: var(--pulse-soft); }
body.theme-dark .workspace-monitor-warn      { background: var(--coral-soft); }
body.theme-dark .workspace-monitor-down      { background: var(--danger-soft); }

/* Compare card base (non-us variant uses --paper-2 already via class). */
body.theme-dark .compare-card { background: var(--paper-2); }
body.theme-dark .compare-card-us {
    background: var(--pulse-soft);
    border-color: var(--pulse);
}

/* Form fields — inputs have white bg by default in some browsers. */
body.theme-dark .field input,
body.theme-dark .field select,
body.theme-dark .field textarea,
body.theme-dark .input {
    background: var(--paper-3);
    color: var(--ink);
    border-color: var(--line-2);
}
body.theme-dark .field input::placeholder,
body.theme-dark .input::placeholder { color: var(--ink-4); }

/* Segmented control */
body.theme-dark .seg { background: var(--paper-3); color: var(--ink-3); }
body.theme-dark .seg:hover { background: var(--paper-2); color: var(--ink); }
body.theme-dark .seg-selected { background: var(--pulse); color: #0C120F; }

/* Status widget "sw-row" uses --paper as its inner background — on dark paper this
   makes rows invisible. Force rows to the raised card surface. */
body.theme-dark .sw-row { background: var(--paper-3); }

/* Ghost button in dark mode needs higher contrast border. */
body.theme-dark .btn-ghost { border-color: var(--line-2); color: var(--ink); }
body.theme-dark .btn-ghost:hover { background: var(--paper-2); }

/* Header sticky bg on dark */
body.theme-dark .site-header { background: var(--paper); }

/* Keep button-primary text bright against bright green */
body.theme-dark .btn-primary { color: #0C120F; }

/* User menu — dropdown in the app header. <details>/<summary> drives the open/close
   state natively (no JS). The summary looks like a clickable avatar chip; when
   open, the dropdown panel floats absolutely below.
   ============================================================================= */

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

.user-menu summary { list-style: none; cursor: pointer; }
.user-menu summary::-webkit-details-marker { display: none; }
.user-menu summary::marker { display: none; }

/* Avatar-only trigger — the 28px circle is the entire clickable target. */
.user-menu-trigger {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--line-2);
    background: transparent;
    transition: border-color 0.12s, box-shadow 0.12s;
}
.user-menu-trigger:hover { border-color: var(--pulse); box-shadow: 0 0 0 3px var(--pulse-soft); }
.user-menu[open] .user-menu-trigger { border-color: var(--pulse); box-shadow: 0 0 0 3px var(--pulse-soft); }

.user-avatar {
    width: 28px; height: 28px;
    border-radius: 50%;
    display: inline-block;
    object-fit: cover;
    background: var(--paper-2);
}
.user-avatar-fallback {
    display: none;
    width: 28px; height: 28px;
    border-radius: 50%;
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    font-family: var(--font-mono);
    font-size: 11px; font-weight: 500;
    align-items: center; justify-content: center;
}

/* Expanded identity header inside the dropdown. */
.user-menu-header {
    display: flex; align-items: center; gap: 12px;
    padding: 12px 12px 10px 12px;
}
.user-menu-header-avatar {
    width: 44px; height: 44px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--paper-2);
    flex-shrink: 0;
}
.user-menu-header-avatar-fallback {
    display: none;
    width: 44px; height: 44px;
    border-radius: 50%;
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    font-family: var(--font-mono);
    font-size: 15px; font-weight: 500;
    align-items: center; justify-content: center;
    flex-shrink: 0;
}
.user-menu-header-text { min-width: 0; }
.user-menu-header-name {
    font-size: 14px; font-weight: 500;
    color: var(--ink);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.user-menu-header-email {
    font-family: var(--font-mono); font-size: 12px;
    color: var(--ink-4); margin-top: 2px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    max-width: 220px;
}

.user-menu-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 240px;
    padding: 6px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    box-shadow: 0 10px 30px -10px rgba(15, 18, 17, 0.15);
    z-index: 100;
}

.user-menu-item {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 12px;
    border-radius: var(--radius-sm);
    font-size: 14px;
    color: var(--ink-2);
    text-decoration: none;
    width: 100%;
    text-align: left;
    background: none; border: none;
    font-family: inherit;
    cursor: pointer;
}
.user-menu-item:hover { background: var(--pulse-soft); color: var(--pulse-ink); }
.user-menu-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 18px; font-size: 14px; color: var(--ink-4);
}
.user-menu-item:hover .user-menu-icon { color: inherit; }
.user-menu-themeform { margin: 0; }
.user-menu-sep {
    height: 1px;
    margin: 6px 0;
    background: var(--line);
}

/* Support page — form card + success state
   ============================================================================= */

.support-form-card {
    max-width: 720px;
    padding: 28px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
}

.support-row-2 {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 640px) {
    .support-row-2 { grid-template-columns: 1fr; }
}

.support-form-card .field { margin-bottom: 16px; }
.support-form-card .field label {
    display: block; font-size: 13px;
    color: var(--ink-3); margin-bottom: 6px; font-weight: 500;
}
.support-form-card .field input,
.support-form-card .field select,
.support-form-card .field textarea {
    width: 100%;
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font: inherit;
    font-size: 14px;
    background: var(--paper);
    color: var(--ink);
    transition: border-color 0.15s, background 0.15s;
}
.support-form-card .field textarea { font-family: var(--font-mono); font-size: 13px; line-height: 1.5; resize: vertical; min-height: 160px; }
.support-form-card .field input:focus,
.support-form-card .field select:focus,
.support-form-card .field textarea:focus {
    outline: none;
    border-color: var(--pulse);
    background: #fff;
    box-shadow: 0 0 0 3px var(--pulse-soft);
}

.support-success {
    max-width: 560px;
    padding: 40px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    text-align: center;
}
.support-success-icon {
    width: 56px; height: 56px;
    margin: 0 auto 20px;
    padding: 14px;
    color: var(--pulse);
    background: var(--pulse-soft);
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
}
.support-success-icon svg { width: 100%; height: 100%; }
.support-success h2 {
    font-family: var(--font-display);
    font-size: 24px;
    margin-bottom: 8px;
}
.support-success p { margin-bottom: 20px; color: var(--ink-3); }

.admin-row-dim td { opacity: 0.55; }

/* Dark theme for the authenticated app.
   Only applied to _LayoutApp (dashboard pages). Admin deliberately stays on the
   light admin-soft palette — different persona, different visual language.
   ============================================================================= */

body.app-body.theme-dark {
    --ink: #F5F5F2;
    --ink-2: #d4d0c3;
    --ink-3: #a0a79f;
    --ink-4: #6b7470;
    --paper: #0C120F;
    --paper-2: #1a2220;
    --paper-3: #252d2a;
    --line: rgba(255, 255, 255, 0.08);
    --line-2: rgba(255, 255, 255, 0.18);

    --pulse: #18D883;
    --pulse-soft: #13332a;
    --pulse-ink: #5fe5a7;

    --coral: #ff8a3a;
    --coral-soft: #3d2418;
    --coral-ink: #ffb27a;

    --amber-soft: #2e2414;
    --danger: #ef6b6b;
    --danger-soft: #3d1a1a;

    background: var(--paper);
    color: var(--ink);
}

/* Surfaces hardcoded to #fff in light mode need explicit overrides in dark. */
body.app-body.theme-dark .app-header,
body.app-body.theme-dark .user-menu-dropdown,
body.app-body.theme-dark .nav-submenu-dropdown,
body.app-body.theme-dark .support-form-card,
body.app-body.theme-dark .support-success,
body.app-body.theme-dark .dashboard-debug,
body.app-body.theme-dark .metric { background: var(--paper-2); }

body.app-body.theme-dark .user-menu-trigger { background: transparent; border-color: var(--line-2); }
body.app-body.theme-dark .user-menu-item:hover { background: var(--pulse-soft); color: var(--pulse-ink); }
body.app-body.theme-dark .nav-submenu-item:hover { background: var(--pulse-soft); color: var(--pulse-ink); }

body.app-body.theme-dark .support-form-card .field input,
body.app-body.theme-dark .support-form-card .field select,
body.app-body.theme-dark .support-form-card .field textarea {
    background: var(--paper-3);
    color: var(--ink);
}

/* Dashboard workspace — sidebar (status pages) + main (monitors).
   ============================================================================= */

.workspace {
    display: grid;
    grid-template-columns: 240px 1fr;
    gap: 24px;
    align-items: start;
}

@media (max-width: 860px) {
    .workspace { grid-template-columns: 1fr; }
}

.workspace-sidebar {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 16px 12px;
    display: flex; flex-direction: column; gap: 10px;
    position: sticky; top: 24px;
}

.sidebar-kicker {
    font-size: 11px; font-weight: 500;
    color: var(--ink-4);
    letter-spacing: 0.08em; text-transform: uppercase;
    padding: 0 4px;
}

.sidebar-pages { display: flex; flex-direction: column; gap: 2px; }

.sidebar-empty {
    font-size: 13px; color: var(--ink-4);
    padding: 8px 10px;
}

.sidebar-page {
    display: flex; flex-direction: column; gap: 2px;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    font-size: 14px;
    color: var(--ink-2);
    text-decoration: none;
    transition: background 0.12s, color 0.12s;
}
.sidebar-page:hover { background: var(--paper-2); color: var(--ink); }
.sidebar-page.active {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    font-weight: 500;
}
.sidebar-page-name { font-size: 14px; }
.sidebar-page-slug {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--ink-4);
}
.sidebar-page.active .sidebar-page-slug { color: var(--pulse-ink); opacity: 0.8; }

.sidebar-new-btn {
    margin-top: 6px;
    padding: 9px 12px;
    border: 1px dashed var(--line-2);
    border-radius: var(--radius-sm);
    font-size: 13px; font-weight: 500;
    color: var(--ink-3);
    text-align: center;
    transition: all 0.12s;
}
.sidebar-new-btn:hover { color: var(--pulse-ink); border-color: var(--pulse); background: var(--pulse-soft); }

.workspace-main { min-width: 0; }

/* Horizontal tab bar — used as the entity picker on /Dashboard, /Dashboard/Watchers/Persons,
   /Dashboard/Watchers/Groups. One tab per entity plus a trailing "+ new" action.
   Each tab renders as a folder-style lift: rounded top corners, border on three
   sides when active, and the bottom edge visually erased so the active tab appears
   seamlessly connected to the content card below. Inactive tabs hover with a
   softer paper-2 fill to preview the same shape. */
.workspace-tabs {
    display: flex;
    align-items: flex-end;
    gap: 4px;
    border-bottom: 1px solid var(--line-2);
    margin-bottom: 24px;
    overflow-x: auto;
    scrollbar-width: thin;
    padding: 0 2px;
}

.workspace-tab {
    display: inline-flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 18px 11px;
    border: 1px solid transparent;
    border-top-left-radius: var(--radius-sm);
    border-top-right-radius: var(--radius-sm);
    color: var(--ink-3);
    text-decoration: none;
    font-weight: 500;
    white-space: nowrap;
    flex-shrink: 0;
    margin-bottom: -1px;
    background: transparent;
    transition: color 0.12s, background 0.12s, border-color 0.12s;
}
.workspace-tab:hover {
    color: var(--ink);
    background: var(--paper-2);
}
.workspace-tab.active {
    color: var(--pulse-ink);
    background: #fff;
    border-color: var(--line-2);
    border-bottom-color: #fff;
    font-weight: 600;
}
.workspace-tab-name { font-size: 14px; }
.workspace-tab-meta {
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--ink-4);
    font-weight: 400;
}
.workspace-tab.active .workspace-tab-meta { color: var(--pulse-ink); opacity: 0.75; }

.workspace-tab-new {
    display: inline-flex;
    align-items: center;
    padding: 10px 14px 11px;
    border: 1px dashed var(--line-2);
    border-top-left-radius: var(--radius-sm);
    border-top-right-radius: var(--radius-sm);
    border-bottom: none;
    color: var(--ink-4);
    text-decoration: none;
    font-size: 13px;
    font-weight: 500;
    white-space: nowrap;
    flex-shrink: 0;
    margin-bottom: -1px;
    background: transparent;
    transition: color 0.12s, background 0.12s, border-color 0.12s;
}
.workspace-tab-new:hover {
    color: var(--pulse-ink);
    border-color: var(--pulse);
    background: var(--pulse-soft);
}

.workspace-tabs-empty {
    font-size: 13px;
    color: var(--ink-4);
    padding: 10px 14px 11px;
}

/* Page picker — label + dropdown + "add page" action inside the workspace
   header's right side. Formerly stood on its own row; now baselines with the
   page name on the left. */
.workspace-page-picker-label {
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-4);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin-right: 4px;
}
.page-select {
    min-width: 220px;
    padding: var(--input-pad-y-md) var(--input-pad-x-md);
    font-size: 14px;
    font-weight: 500;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    background: #fff;
    color: var(--ink);
    cursor: pointer;
}
body.app-body.theme-dark .page-select {
    background: var(--paper-2);
    color: var(--ink);
    border-color: var(--line-2);
}

/* Sub-tabs — used inside workspace-main to split views of a single entity
   (e.g., Monitors vs Settings on a status page). Minimalist underline style
   to avoid competing visually with the heavier folder-style page tabs. */
.workspace-subtabs {
    display: flex;
    align-items: stretch;
    gap: 4px;
    margin-bottom: 20px;
    border-bottom: 1px solid var(--line);
}
/* Delete-page action, pushed to the right end of the sub-tab row so it sits on
   the same horizontal line as the Monitors / Watchers / Settings tabs. Not a
   "tab" itself — align-self: center keeps it vertically centered instead of
   inheriting the stretch that overlaps the bottom border. */
.workspace-subtabs-trash {
    margin-left: auto;
    align-self: center;
}
.workspace-subtab {
    padding: 8px 14px 10px;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    color: var(--ink-3);
    text-decoration: none;
    font-size: 13.5px;
    font-weight: 500;
    transition: color 0.12s, border-color 0.12s;
}
.workspace-subtab:hover { color: var(--ink); }
.workspace-subtab.active {
    color: var(--pulse-ink);
    border-bottom-color: var(--pulse);
}

/* Probe-type filter tabs on /Dashboard/Probes — anchor-based (URL-driven via
   ?type=), same shape as the Pages page's Probes/Watchers/Settings tabs.
   Inherits the underline + active-state colour from .workspace-subtab; this
   rule just adds the inline-flex layout so the count pill aligns with the
   label baseline. */
.probe-type-tab {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}

/* Probe-type left-side sidebar on the Pages page's Probes sub-tab. Mirrors
   the .settings-layout pattern: 220 px rail of buttons, monitor list in the
   right pane. Distinct class names from .settings-* so the two tabs (Probes
   / Settings) on the same page don't share JS or styling state. The pane
   keeps a single <ul> — non-active types' rows are hidden via the [hidden]
   attribute so drag-and-drop reordering stays trivially correct (the
   visible items are still a single sortable list). */
.probe-type-layout {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}
@media (max-width: 720px) {
    .probe-type-layout { grid-template-columns: 1fr; }
    .probe-type-sidebar { flex-direction: row; flex-wrap: wrap; }
    .probe-type-nav-link { border-left: 0; border-bottom: 3px solid transparent; }
    .probe-type-nav-link.active { border-left-color: transparent; border-bottom-color: var(--pulse); }
}
.probe-type-sidebar {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.probe-type-nav-link {
    padding: 10px 14px;
    background: transparent;
    border: 0;
    border-left: 3px solid transparent;
    text-align: left;
    font-size: 14px;
    color: var(--ink-3);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    font-family: inherit;
    transition: background 80ms ease, color 80ms ease, border-color 80ms ease;
}
.probe-type-nav-link:hover {
    background: var(--paper-2);
    color: var(--ink);
}
.probe-type-nav-link.active {
    background: var(--paper-2);
    color: var(--ink);
    border-left-color: var(--pulse);
    font-weight: 500;
}
.probe-type-pane { min-width: 0; }

body.theme-dark .probe-type-nav-link:hover,
body.theme-dark .probe-type-nav-link.active { background: var(--paper-3); }
.probe-type-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--paper-3);
    color: var(--ink-4);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
}
.probe-type-tab.active .probe-type-count {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
}
body.app-body.theme-dark .workspace-subtabs { border-bottom-color: var(--line-2); }
body.app-body.theme-dark .workspace-subtab.active { color: var(--pulse); border-bottom-color: var(--pulse); }
body.app-body.theme-dark .probe-type-count { background: var(--paper-3); color: var(--ink-3); }
body.app-body.theme-dark .probe-type-tab.active .probe-type-count { background: var(--pulse-soft); color: var(--pulse); }

/* Tab intro — short explainer on the left + primary action on the right.
   Used at the top of a sub-tab's content (e.g., the Monitors tab). Stacks
   below ~540px so the action stays reachable on narrow screens. */
.tab-intro {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 20px;
}
.tab-intro-text {
    margin: 0;
    flex: 1;
    font-size: 13px;
    color: var(--ink-4);
    line-height: 1.55;
}
@media (max-width: 540px) {
    .tab-intro { flex-direction: column; align-items: stretch; gap: 12px; }
    .tab-intro .btn { align-self: flex-start; }
}

/* Watcher card header — section kicker on the left, "Add X" on the right. */
.watcher-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}
.watcher-card-header .section-kicker { margin: 0; }

/* Compact secondary-button utility. Used for in-card actions (Add Person in a
   watcher card, Add Monitor inside the Monitors tab-intro) where a full-size
   btn-primary would overpower the layout. Pairs with .btn .btn-ghost. */
.btn-sm {
    padding: 6px 12px;
    font-size: 12.5px;
    height: auto;
}

/* Ghost-button modifier tinted red — for destructive inline actions that
   should still read as "button" rather than a floating trash icon. Pairs with
   .btn .btn-ghost. */
.btn-ghost-danger {
    color: var(--danger);
    border-color: var(--danger-soft);
}
.btn-ghost-danger:hover {
    background: var(--danger-soft);
    border-color: var(--danger);
    color: var(--danger);
}

/* Monitor custom-headers list — key/value pairs managed inside HTTP options.
   No edit path; the operator adds with the row below and removes via the
   per-row trash icon. Grid columns keep key + value + action aligned whether
   the value is a short token or a long bearer string. */
.http-headers-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 10px;
}
.http-header-row {
    display: grid;
    grid-template-columns: minmax(140px, 1fr) minmax(140px, 2fr) 32px;
    gap: 10px;
    align-items: center;
}
.http-header-add-row {
    display: grid;
    grid-template-columns: minmax(140px, 1fr) minmax(140px, 2fr);
    gap: 10px;
    align-items: center;
}
.http-header-row {
    padding: 6px 12px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}
.http-header-row code {
    font-family: var(--font-mono);
    font-size: 12.5px;
    color: var(--ink);
    background: transparent;
    padding: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.http-header-row .http-header-key { color: var(--pulse-ink); font-weight: 500; }
.http-header-add-row input {
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    font-size: 14px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    background: var(--paper);
    color: var(--ink);
}
.http-header-add-row input:focus {
    outline: none;
    border-color: var(--pulse);
    background: #fff;
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
body.app-body.theme-dark .http-header-row { background: var(--paper-3); border-color: var(--line-2); }
body.app-body.theme-dark .http-header-row .http-header-key { color: var(--pulse); }
body.app-body.theme-dark .http-header-add-row input { background: var(--paper-3); border-color: var(--line-2); color: var(--ink); }
@media (max-width: 540px) {
    .http-header-row,
    .http-header-add-row { grid-template-columns: 1fr; }
}

/* Watcher row — one per person or group in the Watchers tab. Shows name, meta
   (email or member count), event badges, and a trash icon. */
.watcher-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 14px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    margin-bottom: 8px;
    background: #fff;
}
.watcher-row:last-child { margin-bottom: 0; }
.watcher-row-info { min-width: 0; flex: 1; }
.watcher-row-name { font-size: 14px; font-weight: 500; color: var(--ink); display: block; }
.watcher-row-meta {
    font-size: 12px;
    color: var(--ink-4);
    font-family: var(--font-mono);
    display: block;
    margin-top: 2px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.watcher-row-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-shrink: 0;
}
body.app-body.theme-dark .watcher-row { background: var(--paper-3); }

/* Event badges — Start / Change / Resolution / Responder. Clickable when rendered
   as <button> (cascades the flag across every subscription this watcher owns on
   the current page) or read-only when rendered as <span> (e.g., Responder on a
   group row, where the field doesn't exist in the data model). */
.watcher-badges {
    display: inline-flex;
    gap: 6px;
    flex-wrap: wrap;
    margin: 0;
    padding: 0;
}
.watcher-badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.02em;
    border: 1px solid transparent;
    white-space: nowrap;
    font-family: inherit;
    line-height: 1.45;
}
/* Reset native button chrome when a badge is rendered as <button>. */
button.watcher-badge {
    cursor: pointer;
    transition: transform 0.08s, box-shadow 0.12s, filter 0.12s;
}
button.watcher-badge:hover { filter: brightness(1.05); }
button.watcher-badge:active { transform: translateY(1px); }

.watcher-badge-on {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    border-color: var(--pulse-soft);
}
.watcher-badge-off {
    background: transparent;
    color: var(--ink-4);
    border-color: var(--line-2);
}
/* Disabled variant — used for badges that don't map to a toggleable field
   (Responder on a group row). Opaque, no hover, default cursor. */
.watcher-badge-disabled {
    background: transparent;
    color: var(--ink-4);
    border-color: var(--line);
    opacity: 0.55;
    cursor: not-allowed;
}
body.app-body.theme-dark .watcher-badge-on {
    background: rgba(16, 192, 116, 0.15);
    color: var(--pulse);
    border-color: transparent;
}
body.app-body.theme-dark .watcher-badge-off { color: var(--ink-3); border-color: var(--line-2); }
body.app-body.theme-dark .watcher-badge-disabled { color: var(--ink-4); border-color: var(--line-2); }

.watcher-empty {
    font-size: 13px;
    color: var(--ink-4);
    padding: 14px 4px 4px;
    text-align: center;
}

/* Card containers used inside the workspace to group related fields
   (Profile, Members, Monitor subscriptions). `.workspace-cards-row` renders
   children side-by-side on wide viewports and stacks them on narrow ones. */
.workspace-card {
    padding: 22px 24px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    margin-bottom: 24px;
}
.workspace-card > .section-kicker:first-child { margin-top: 0; }
.workspace-card > *:last-child { margin-bottom: 0; }

.workspace-cards-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 24px;
    margin-bottom: 0;
    align-items: start;
}
.workspace-cards-row > .workspace-card { margin-bottom: 24px; }
@media (max-width: 860px) {
    .workspace-cards-row { grid-template-columns: 1fr; gap: 0; }
}

/* Card heading row — h2 on the left, optional meta on the right.
   Used by Reports History, Schedule cards, and any workspace-card
   that wants a heading + a small right-aligned metric. */
.workspace-card-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.workspace-card-header h2 {
    margin: 0;
    font-size: 16px;
    font-weight: 600;
    color: var(--ink);
}
.workspace-card-meta {
    font-size: 12.5px;
    color: var(--ink-3);
    font-family: var(--font-mono);
}

/* Reports → Schedule page — 4 cards (one per cadence) laid out in a
   responsive grid. Two columns at desktop width, one column on
   narrower viewports. */
.schedule-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}
@media (max-width: 900px) {
    .schedule-grid { grid-template-columns: 1fr; }
}

/* "Next delivery" / "Last delivered" footer block on each schedule card. */
.schedule-card-meta {
    display: flex;
    gap: 24px;
    flex-wrap: wrap;
    padding: 12px 0;
    border-top: 1px solid var(--line);
    margin-top: 14px;
    font-size: 12.5px;
    color: var(--ink-3);
}
.schedule-card-meta-label {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--ink-4);
    margin-bottom: 2px;
}

/* Global submit-spinner overlay. Shown by spinner.js on any POST form
   submission; auto-hides when the new page response replaces this DOM. */
.spinner-overlay {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 9999;
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}
.spinner-overlay-visible { display: flex; }
.spinner {
    width: 48px;
    height: 48px;
    border: 4px solid rgba(255, 255, 255, 0.3);
    border-top-color: #fff;
    border-radius: 50%;
    animation: spinner-rotate 0.8s linear infinite;
}
@keyframes spinner-rotate { to { transform: rotate(360deg); } }

/* Compact metric tiles — used on report Detail page where each tile
   carries a short label + value (not a big KPI number). Overrides the
   default .metric-value 32px display font down to a readable 14px so
   6 tiles fit comfortably on a 3-column grid. */
.metric-grid-compact .metric { padding: 16px; }
.metric-grid-compact .metric-value {
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    letter-spacing: 0;
    color: var(--ink);
    margin: 0;
}
.metric-grid-compact .metric-label {
    font-size: 11px;
    margin-bottom: 6px;
}

body.app-body.theme-dark .workspace-card { background: var(--paper-2); }

.workspace-header {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 16px; margin-bottom: 24px;
}
.workspace-header h1 {
    font-family: var(--font-display); font-size: 28px;
    margin: 4px 0 4px; letter-spacing: -0.02em;
}
.workspace-url {
    font-family: var(--font-mono); font-size: 12.5px;
    color: var(--ink-4);
}
.workspace-header-actions { display: flex; gap: 10px; align-items: center; flex-shrink: 0; }
/* Match the +Monitor button height to the 36px settings icon next to it. */
.workspace-header-actions .btn { height: 36px; padding-top: 0; padding-bottom: 0; }

/* Integration row trailing actions (Send test / Rotate secret / Delete)
   live inside a workspace-card body, not the workspace header — but the
   user wants them at the same 36px tier as "Add Page" so the row reads
   as a settings control surface, not a primary CTA strip. */
.integration-row-actions .btn { height: 36px; padding-top: 0; padding-bottom: 0; }
/* Vertical separator between header-action button groups. Used on the
   Reports page to divide recurring-flow buttons (Schedule Report +
   Manage Schedule) from the one-shot Generate Report button. */
.header-action-divider {
    display: inline-block;
    width: 1px;
    height: 24px;
    background: var(--line-2);
    margin: 0 4px;
}

.icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    color: var(--ink-3);
    background: #fff;
    transition: all 0.12s;
}
.icon-btn:hover { color: var(--pulse-ink); border-color: var(--pulse); background: var(--pulse-soft); }

/* Destructive variant — red hover. Same geometry as .icon-btn. */
.icon-btn-danger:hover {
    color: var(--danger);
    border-color: var(--danger);
    background: var(--danger-soft);
}

/* Compact variant for inline per-row actions (e.g., monitor delete). */
.icon-btn-sm {
    width: 28px; height: 28px;
    padding: 0;
    border: 1px solid transparent;
    background: transparent;
    color: var(--ink-4);
    cursor: pointer;
}
.icon-btn-sm:hover { color: var(--danger); background: var(--danger-soft); border-color: var(--danger); }

.workspace-empty {
    padding: 48px 32px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    text-align: center;
}
.workspace-empty h2 {
    font-family: var(--font-display);
    font-size: 22px;
    margin-bottom: 8px;
}
.workspace-empty p { color: var(--ink-3); margin-bottom: 20px; }

.workspace-monitors { list-style: none; margin: 0; padding: 0; }
.workspace-monitor {
    position: relative;
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px;
    padding: 14px 18px;
    background: var(--paper-2);
}

/* Override the base `display: flex` above when the row is hidden via the
   HTML [hidden] attribute. Without this, `<li hidden>` from the probe-type
   filter on the Pages page's Probes sub-tab still rendered because our
   class rule outranked the user-agent stylesheet's [hidden] = display:none.
   Specificity here matches the base rule (one class + one attribute) but
   wins on the cascade order. */
.workspace-monitor[hidden] {
    display: none;
    border: 1px solid var(--line);
    border-left-width: 4px;
    border-left-color: var(--ink-4);
    border-radius: var(--radius-md);
    margin-bottom: 8px;
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s, filter 0.12s;
}
/* Status tiers — same soft-tint + coloured-strip pattern the public status
   page (.service-row-*) and the SSL card use, so a row in the dashboard
   reads identically to its public counterpart and to the SSL card. */
.workspace-monitor-ok      { background: var(--pulse-soft);  border-left-color: var(--pulse); }
.workspace-monitor-warn    { background: var(--coral-soft);  border-left-color: var(--coral); }
.workspace-monitor-down    { background: var(--danger-soft); border-left-color: var(--danger); }
.workspace-monitor-paused  { border-left-color: var(--ink-4); }
.workspace-monitor-unknown { border-left-color: var(--ink-4); }

.workspace-monitor:hover {
    border-color: var(--line-2);
    filter: brightness(0.97);
}
.workspace-monitor-info {
    /* flex: 1 makes the info column grab all the space between the handle
       and the right-side metrics, so the name/target sit hard left next
       to the handle (with the row gap as the separator) instead of
       drifting toward the centre under justify-content: space-between. */
    flex: 1 1 auto;
    min-width: 0;
}
.workspace-monitor-name {
    display: block;
    font-size: 15px; font-weight: 500;
    color: var(--ink);
    text-decoration: none;
}
.workspace-monitor-name:hover { color: var(--pulse-ink); }
/* Stretched-link hitbox — an invisible overlay pseudo-element extends the
   monitor-name anchor's click target to the whole row. Clicks on the
   decorative children (meta text, status pill, metric span) fall through
   to the overlay via pointer-events: none; the trash button and the drag
   handle explicitly opt back in so they still capture their own clicks. */
.workspace-monitor-name::after {
    content: "";
    position: absolute;
    inset: 0;
}
.workspace-monitor-info,
.workspace-monitor-right {
    pointer-events: none;
}
.workspace-monitor-name,
.workspace-monitor .icon-btn,
.workspace-monitor-drag {
    pointer-events: auto;
}
/* Lift interactive controls above the stretched-link ::after. CSS painting
   order puts positioned descendants (the absolute overlay) on top of
   in-flow non-positioned ones (the trash button), so without an explicit
   stacking the click would hit the overlay and navigate to the detail
   instead of opening the delete modal. The drag handle already does this
   via its own rule (z-index: 2). */
.workspace-monitor .icon-btn {
    position: relative;
    z-index: 1;
}

/* Drag handle — the only draggable element on the row. Sits above the
   stretched-link overlay via explicit positioning; cursor communicates
   the grab affordance; dragging class dims the source row so the drop
   location is visually obvious. */
.workspace-monitor-drag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    color: var(--ink-4);
    cursor: grab;
    border-radius: 4px;
    position: relative;
    z-index: 2;
    user-select: none;
}
.workspace-monitor-drag:hover { color: var(--ink-2); background: rgba(0, 0, 0, 0.05); }
.workspace-monitor-drag:active { cursor: grabbing; }
.workspace-monitor.dragging { opacity: 0.4; }
.workspace-monitor-meta {
    display: block; margin-top: 2px;
    font-family: var(--font-mono); font-size: 11.5px;
    color: var(--ink-4);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.workspace-monitor-right {
    display: flex; align-items: center; gap: 14px;
    flex-shrink: 0;
}
.workspace-monitor-latency {
    font-family: var(--font-mono); font-size: 12.5px;
    color: var(--ink-3);
    min-width: 64px; text-align: right;
    white-space: nowrap;
}

.form-success-inline {
    padding: 10px 14px;
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    border-radius: var(--radius-sm);
    font-size: 13px;
}

/* Modal (CSS :target pattern — no JS).
   Hidden by default; the matching #id in the URL fragment makes it display.
   `#close` (non-existent id) is the universal dismiss anchor.
   ============================================================================= */

.modal {
    display: none;
    position: fixed; inset: 0;
    align-items: center; justify-content: center;
    padding: 20px;
    z-index: 1000;
}
.modal:target { display: flex; }

.modal-backdrop {
    position: absolute; inset: 0;
    background: rgba(15, 18, 17, 0.45);
    cursor: pointer;
}

.modal-content {
    position: relative;
    width: 100%;
    max-width: 520px;
    background: #fff;
    border-radius: var(--radius-lg);
    box-shadow: 0 20px 60px -20px rgba(15, 18, 17, 0.35);
    padding: 24px;
    animation: modal-in 0.15s ease-out;
}
@keyframes modal-in {
    from { transform: translateY(-8px); opacity: 0; }
    to   { transform: translateY(0);    opacity: 1; }
}

.modal-header {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 20px;
}
.modal-header h2 {
    font-family: var(--font-display); font-size: 20px;
    margin: 0; letter-spacing: -0.01em;
}
.modal-close {
    width: 28px; height: 28px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: var(--radius-sm);
    color: var(--ink-4);
    font-size: 22px; line-height: 1;
    text-decoration: none;
}
.modal-close:hover { background: var(--paper-2); color: var(--ink); }

.modal-content .field { margin-bottom: 16px; }
.modal-content .field label {
    display: block; font-size: 13px;
    color: var(--ink-3); margin-bottom: 6px; font-weight: 500;
}
.modal-content .field input,
.modal-content .field select,
.modal-content .field textarea {
    width: 100%;
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font: inherit; font-size: 14px;
    background: var(--paper);
}
.modal-content .field input:focus,
.modal-content .field select:focus,
.modal-content .field textarea:focus {
    outline: none;
    border-color: var(--pulse);
    background: #fff;
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
.modal-content .field input:disabled,
.modal-content .field input[readonly] { background: var(--paper-2); color: var(--ink-4); cursor: not-allowed; }

/* Dark-mode modal — applies to both the dashboard's body.theme-dark and to
   the admin body (which forces dark tokens without the theme-dark class).
   The base .modal-content has background: #fff hardcoded; these overrides
   pin the modal surface to --paper-2 and push the input surface a level
   deeper to --paper-3 for contrast against the modal body. Without this,
   the modal pops up bright white over a dark chrome and the inputs (which
   inherit --paper, dark) look inverted. */
body.theme-dark .modal-content,
.admin-body .modal-content {
    background: var(--paper-2);
    color: var(--ink);
    box-shadow: 0 20px 60px -20px rgba(0, 0, 0, 0.55);
}
body.theme-dark .modal-content .field input,
body.theme-dark .modal-content .field select,
body.theme-dark .modal-content .field textarea,
.admin-body .modal-content .field input,
.admin-body .modal-content .field select,
.admin-body .modal-content .field textarea {
    background: var(--paper-3);
    color: var(--ink);
    border-color: var(--line-2);
}
body.theme-dark .modal-content .field input::placeholder,
body.theme-dark .modal-content .field textarea::placeholder,
.admin-body .modal-content .field input::placeholder,
.admin-body .modal-content .field textarea::placeholder {
    color: var(--ink-4);
}
body.theme-dark .modal-content .field input:focus,
body.theme-dark .modal-content .field select:focus,
body.theme-dark .modal-content .field textarea:focus,
.admin-body .modal-content .field input:focus,
.admin-body .modal-content .field select:focus,
.admin-body .modal-content .field textarea:focus {
    background: var(--paper-3);
    border-color: var(--pulse);
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
body.theme-dark .modal-content .field input:disabled,
body.theme-dark .modal-content .field input[readonly],
.admin-body .modal-content .field input:disabled,
.admin-body .modal-content .field input[readonly] {
    background: var(--paper-2);
    color: var(--ink-4);
}
.field-hint {
    display: block; margin-top: 6px;
    font-size: 12px; color: var(--ink-4);
}
.field-hint code { font-family: var(--font-mono); background: var(--paper-2); padding: 1px 6px; border-radius: 4px; }

.modal-actions {
    display: flex; gap: 8px; justify-content: flex-end;
    margin-top: 20px;
}
.modal-actions-split { justify-content: space-between; align-items: center; }

.plan-gate-tag {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    background: var(--coral-soft);
    color: var(--coral-ink);
    font-size: 10px; font-weight: 500;
    border-radius: 999px;
    text-transform: uppercase; letter-spacing: 0.05em;
    vertical-align: middle;
}

/* Inline upgrade alert in the New-probe modal — shown when the user picks a
   probe type their plan doesn't include. The Create button is disabled at
   the same time so the only way forward is to pick another type or follow
   the "See plans" link. Coral palette matches the rest of the warn-tier UI
   (sample-row-warn, plan-gate-tag) so it reads as "blocked but recoverable",
   not destructive. */
/* Solid destructive button — used for the Confirm action in destructive modals. */
.btn-danger {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 11px 18px;
    font-size: 14.5px; font-weight: 500;
    color: #fff;
    background: var(--danger);
    border: 1px solid var(--danger);
    border-radius: var(--radius-md);
    cursor: pointer;
    transition: all 0.15s ease;
}
.btn-danger:hover { filter: brightness(1.08); transform: translateY(-1px); }

.btn-danger-ghost {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 9px 14px;
    font-size: 13px; font-weight: 500;
    color: var(--danger);
    background: transparent;
    border: 1px solid var(--danger-soft);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all 0.12s;
}
.btn-danger-ghost:hover { background: var(--danger-soft); }

/* Admin is force-dark — apply the same modal surface as theme-dark so
   any .modal in /Admin/* reads as dark instead of the default white
   card. Sits before the theme-dark block so the cascade order matches
   the rule it mirrors. */
body.admin-body .modal-content {
    background: var(--paper-2);
    color: var(--ink);
    border: 1px solid var(--line-2);
}
body.admin-body .modal-backdrop { background: rgba(0, 0, 0, 0.6); }

/* Dark-theme overrides for workspace + modal surfaces. */
body.app-body.theme-dark .workspace-sidebar,
body.app-body.theme-dark .workspace-empty,
body.app-body.theme-dark .workspace-monitor,
body.app-body.theme-dark .modal-content,
body.app-body.theme-dark .icon-btn { background: var(--paper-2); }
body.app-body.theme-dark .workspace-monitor:hover { background: var(--paper-3); }

body.app-body.theme-dark .workspace-tabs { border-bottom-color: var(--line-2); }
body.app-body.theme-dark .workspace-tab { color: var(--ink-3); }
body.app-body.theme-dark .workspace-tab:hover {
    color: var(--ink);
    background: var(--paper-3);
}
body.app-body.theme-dark .workspace-tab.active {
    color: var(--pulse);
    background: var(--paper-2);
    border-color: var(--line-2);
    border-bottom-color: var(--paper-2);
}
body.app-body.theme-dark .workspace-tab.active .workspace-tab-meta { color: var(--pulse); opacity: 0.8; }
body.app-body.theme-dark .workspace-tab-new { border-color: var(--line-2); }
body.app-body.theme-dark .workspace-tab-new:hover {
    color: var(--pulse);
    background: rgba(16, 192, 116, 0.12);
    border-color: var(--pulse);
}

body.app-body.theme-dark .modal-content .field input,
body.app-body.theme-dark .modal-content .field select,
body.app-body.theme-dark .modal-content .field textarea {
    background: var(--paper-3);
    color: var(--ink);
    border-color: var(--line-2);
}
body.app-body.theme-dark .modal-content .field input:focus,
body.app-body.theme-dark .modal-content .field select:focus,
body.app-body.theme-dark .modal-content .field textarea:focus { background: var(--paper-2); }
body.app-body.theme-dark .modal-content .field input:disabled,
body.app-body.theme-dark .modal-content .field input[readonly] {
    background: rgba(255, 255, 255, 0.04);
    color: var(--ink-4);
}
/* Dark-mode label / hint contrast — the base light tokens are too dim on paper-2.
   Bump labels to ink-2 and hints to ink-3 so the settings dialog reads solidly. */
body.app-body.theme-dark .modal-content .field label { color: var(--ink-2); }
body.app-body.theme-dark .field-hint { color: var(--ink-3); }
body.app-body.theme-dark .field-hint code { background: var(--paper-3); color: var(--ink-2); }
body.app-body.theme-dark .modal-header h2 { color: var(--ink); }
body.app-body.theme-dark .modal-close { color: var(--ink-3); }
body.app-body.theme-dark .modal-close:hover { background: var(--paper-3); color: var(--ink); }
body.app-body.theme-dark .modal-backdrop { background: rgba(0, 0, 0, 0.6); }

/* Domain input + inline Verify button. Input takes the remaining width, button
   is a compact auxiliary action. */
.domain-input-row {
    display: flex; gap: 8px; align-items: stretch;
}
.domain-input-row > input { flex: 1; min-width: 0; }
.btn-verify-domain {
    padding: 8px 14px;
    font-size: 13px;
    white-space: nowrap;
    flex-shrink: 0;
}
.btn-verify-domain:disabled { opacity: 0.45; cursor: not-allowed; }

.verify-result {
    margin-top: 8px;
    font-size: 12.5px; line-height: 1.4;
    color: var(--ink-4);
    min-height: 1em;
}
.verify-result-ok      { color: var(--pulse); font-weight: 500; }
.verify-result-warn    { color: var(--coral); }
.verify-result-pending { color: var(--ink-3); }

/* DNS records callout in the page settings modal — shown between the hostname
   input and the Activate toggle when the customer has a domain entered but not
   yet active. Copy-friendly monospace for the CNAME / TXT values.
   ============================================================================= */
.dns-help {
    margin: 0 0 18px;
    padding: 14px 16px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}
.dns-help-title {
    font-size: 12.5px; font-weight: 500;
    color: var(--ink-2);
    margin-bottom: 10px;
    letter-spacing: 0.02em;
}
.dns-record {
    display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    margin-bottom: 6px;
    font-family: var(--font-mono); font-size: 11.5px;
}
.dns-record-type {
    display: inline-block;
    min-width: 44px; text-align: center;
    padding: 2px 6px;
    background: var(--pulse-soft); color: var(--pulse);
    border-radius: 3px;
    font-weight: 500;
}
.dns-record-name, .dns-record-value {
    padding: 3px 8px;
    background: #fff;
    border: 1px solid var(--line);
    border-radius: 3px;
    color: var(--ink-2);
    word-break: break-all;
}
.dns-record-value { flex: 1; min-width: 0; }
.dns-record-arrow { color: var(--ink-4); }

/* Copy icon button — sits at the end of each .dns-record. Shows a check-mark
   briefly after a successful copy via JS. */
.dns-copy-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 26px; height: 26px;
    padding: 0;
    border: 1px solid var(--line-2);
    border-radius: 4px;
    background: transparent;
    color: var(--ink-4);
    cursor: pointer;
    flex-shrink: 0;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.dns-copy-btn:hover { color: var(--pulse); border-color: var(--pulse); background: var(--pulse-soft); }
.dns-copy-btn.copied { color: var(--pulse); border-color: var(--pulse); background: var(--pulse-soft); }

.empty-card {
    padding: 48px 32px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    text-align: center;
}
body.app-body.theme-dark .empty-card { background: var(--paper-2); }

/* Toast — centered, auto-dismissing notification overlay. Container is fixed
   at viewport middle with pointer-events: none so it never blocks interaction.
   Each toast re-enables pointer events for click-to-dismiss.
   ============================================================================= */
.toast-container {
    position: fixed;
    top: 50%; left: 50%;
    transform: translate(-50%, -50%);
    z-index: 3000;
    display: flex; flex-direction: column; gap: 10px; align-items: center;
    pointer-events: none;
}
.toast {
    pointer-events: auto;
    min-width: 260px; max-width: 480px;
    padding: 14px 22px;
    border-radius: var(--radius-md);
    font-size: 14px; font-weight: 500;
    text-align: center;
    box-shadow: 0 8px 28px -8px rgba(15, 18, 17, 0.35);
    background: var(--ink);
    color: var(--paper);
    opacity: 0;
    transform: translateY(-6px);
    transition: opacity 0.18s ease-out, transform 0.18s ease-out;
    cursor: pointer;
}
.toast.toast-show { opacity: 1; transform: translateY(0); }
.toast.toast-hide { opacity: 0; transform: translateY(-6px); }

.toast-success { background: var(--pulse); color: #0C120F; }
.toast-error   { background: var(--danger); color: #fff; }
.toast-warn    { background: var(--coral); color: #1a1007; }
.toast-info    { background: var(--ink); color: var(--paper); }

/* Verify-failed modal — JS-controlled (display:flex) so it overlays the settings
   modal without touching the URL hash. Higher z-index keeps it on top. */
.verify-failed-modal {
    z-index: 2000;
    display: none;
    align-items: center; justify-content: center;
    position: fixed; inset: 0;
    padding: 20px;
}
.verify-failed-modal .modal-close {
    border: none;
    background: transparent;
    cursor: pointer;
    font: inherit;
}
.verify-failed-list {
    list-style: none;
    margin: 0 0 16px;
    padding: 0;
}
.verify-failed-list li {
    display: flex; gap: 10px; align-items: flex-start;
    padding: 12px;
    background: var(--danger-soft);
    border-radius: var(--radius-sm);
    margin-bottom: 8px;
}
.verify-failed-type {
    display: inline-block;
    min-width: 48px; text-align: center;
    padding: 3px 8px;
    background: var(--danger);
    color: #fff;
    border-radius: 3px;
    font-family: var(--font-mono); font-size: 11.5px; font-weight: 500;
    flex-shrink: 0;
}
.verify-failed-body { font-size: 13px; color: var(--ink-2); line-height: 1.5; min-width: 0; word-break: break-all; }
.verify-failed-body code {
    font-family: var(--font-mono); font-size: 12px;
    padding: 1px 5px;
    background: #fff;
    border-radius: 3px;
}
body.app-body.theme-dark .verify-failed-list li { background: rgba(239, 107, 107, 0.12); }
body.app-body.theme-dark .verify-failed-body code { background: var(--paper-3); color: var(--ink); }

body.app-body.theme-dark .dns-help { background: rgba(255, 255, 255, 0.03); }
body.app-body.theme-dark .dns-record-name,
body.app-body.theme-dark .dns-record-value { background: var(--paper-3); color: var(--ink); border-color: var(--line-2); }

/* Custom-domain activation row inside the settings modal.
   The native checkbox is styled by `.toggle-switch`; the label wraps the toggle + text.
   ============================================================================= */
.toggle-row {
    display: inline-flex; align-items: center; gap: 28px;
    font-size: 14px; color: var(--ink-2);
    cursor: pointer;
    line-height: 1.5;
}

/* Input with an action icon embedded inside on the right (e.g. copy
   button on a read-only URL field). The button is absolutely positioned
   over the right edge; the input gets right padding so the text doesn't
   slide under the icon. Pair the button's click handler with the
   `.copied` class to swap a clipboard SVG for a check SVG as visual
   feedback (see the helper script in Probes/Edit.cshtml for the toggle). */
.input-with-icon-action {
    position: relative;
}
.input-with-icon-action > input {
    width: 100%;
    padding-right: 38px;
}
.input-icon-btn {
    position: absolute;
    top: 50%;
    right: 4px;
    transform: translateY(-50%);
    background: transparent;
    border: none;
    color: var(--ink-3);
    cursor: pointer;
    padding: 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-sm);
    transition: background 0.15s, color 0.15s;
}
.input-icon-btn:hover {
    color: var(--ink);
    background: var(--paper-2);
}
.input-icon-btn:active {
    background: var(--line);
}
.input-icon-btn .icon-check { display: none; }
.input-icon-btn.copied { color: var(--ok); }
.input-icon-btn.copied .icon-clipboard { display: none; }
.input-icon-btn.copied .icon-check { display: inline-block; }
body.theme-dark .input-icon-btn:hover { background: rgba(255, 255, 255, 0.08); }

/* Radio pill — CSS-only segmented control for paired/triple radio choices.
   Native radios stay in the DOM (form posts and screen readers see them),
   but are visually replaced by styled spans. The brand-coloured fill
   matches the .toggle-switch ON state, so radios and toggles read as a
   coherent system. Use anywhere a short multi-choice (interval/cron,
   IPv4/IPv6, exact/contains/any) needs the same polish as the boolean
   toggle. */
.radio-pill {
    display: inline-flex;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    padding: 3px;
    background: var(--paper);
    gap: 2px;
}
.radio-pill > label {
    margin: 0;
    cursor: pointer;
    user-select: none;
    position: relative;
}
.radio-pill > label > input[type="radio"] {
    position: absolute;
    opacity: 0;
    width: 0;
    height: 0;
    pointer-events: none;
}
.radio-pill > label > span {
    display: inline-block;
    padding: 7px 16px;
    border-radius: calc(var(--radius-md) - 4px);
    font-size: 13.5px;
    color: var(--ink-2);
    transition: background 0.15s, color 0.15s;
    line-height: 1.2;
}
.radio-pill > label:hover > span {
    color: var(--ink);
}
.radio-pill > label > input[type="radio"]:checked ~ span {
    background: var(--pulse);
    color: #fff;
}
.radio-pill > label > input[type="radio"]:focus-visible ~ span {
    outline: 2px solid var(--pulse);
    outline-offset: 2px;
}

/* Read-only "assigned to" row — used on the Monitor Settings tab to show the
   parent status page without allowing it to be re-selected from the form.
   Plain label value on the left, inline action icons (delete, copy) on the
   right. No box chrome — the value reads as a flat label. */
.assignment-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 2px 0;
}
.assignment-value {
    font-weight: 500;
    color: var(--ink);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.assignment-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}

/* Horizontal container pairing a toggle-row with a status badge to its right.
   Used on the Custom Domain Activate row so the provisioning state reads as
   a badge aligned with the checkbox label instead of a full line below it. */
.toggle-row-with-status {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 6px;
}
.toggle-row-with-status .toggle-row { flex-shrink: 0; }

/* DNS records rendered as a table so Type / Host / Value line up in columns.
   Copy buttons sit next to the code block in their cell for quick paste into
   a DNS manager. Horizontal scroll on very narrow screens so the monospace
   values don't wrap mid-token. */
.dns-record-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 13px;
    margin: 4px 0 0;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    overflow: hidden;
    table-layout: auto;
}
.dns-record-table th,
.dns-record-table td {
    padding: 8px 12px;
    text-align: left;
    vertical-align: middle;
    border-bottom: 1px solid var(--line);
}
.dns-record-table tr:last-child td { border-bottom: none; }
.dns-record-table th {
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-4);
    background: var(--paper-2);
    border-bottom-color: var(--line-2);
}
.dns-record-table .dns-record-type {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 600;
    color: var(--pulse-ink);
    letter-spacing: 0.04em;
}
.dns-record-table code {
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink);
    word-break: break-all;
    background: transparent;
    padding: 0;
}
.dns-record-cell {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
}
body.app-body.theme-dark .dns-record-table {
    border-color: var(--line-2);
}
body.app-body.theme-dark .dns-record-table th {
    background: var(--paper-3);
    color: var(--ink-3);
}
body.app-body.theme-dark .dns-record-table code { color: var(--ink); }
body.app-body.theme-dark .dns-record-table .dns-record-type { color: var(--pulse); }
.custom-domain-status {
    margin-top: 10px;
    display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
}

/* Status pill primitives — used by the workspace monitor list and the settings
   modal's custom-domain state. Variant class decides the tint. */
.service-status {
    display: inline-flex; align-items: center;
    padding: 3px 10px; border-radius: 6px;
    font-size: 12.5px; font-weight: 500;
    flex-shrink: 0;
}
.service-status.status-ok      { background: var(--pulse-soft);  color: var(--pulse); }
.service-status.status-warn    { background: var(--coral-soft);  color: var(--coral); }
.service-status.status-down    { background: var(--danger-soft); color: var(--danger); }
.service-status.status-paused  { background: var(--paper-2);     color: var(--ink-4); }
.service-status.status-unknown { background: var(--paper-2);     color: var(--ink-3); }
body.app-body.theme-dark .toggle-row { color: var(--ink); }
body.theme-dark .radio-pill {
    border-color: rgba(255, 255, 255, 0.12);
    background: var(--paper-2);
}

/* Monitor detail shell — sidebar (Status · Settings) + main content.
   Used by /Dashboard/Probes/Status and /Dashboard/Probes/Edit. */
.monitor-shell {
    display: grid;
    grid-template-columns: 220px 1fr;
    gap: 24px;
    align-items: start;
}

@media (max-width: 860px) {
    .monitor-shell { grid-template-columns: 1fr; }
}

.monitor-sidebar {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 18px 0;
    position: sticky; top: 24px;
}
.monitor-sidebar nav { display: flex; flex-direction: column; gap: 2px; }

.monitor-nav-link {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 20px;
    font-size: 14px;
    color: var(--ink-3);
    border-left: 3px solid transparent;
    text-decoration: none;
    transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.monitor-nav-link:hover { background: var(--paper-2); color: var(--ink); }
.monitor-nav-link-active {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
    border-left-color: var(--pulse);
    font-weight: 500;
}
.monitor-nav-icon { display: inline-block; width: 16px; text-align: center; font-size: 13px; }

.monitor-main { min-width: 0; }

/* Watcher detail — subscription matrix (monitor × 3 toggles). */
.watcher-matrix {
    width: 100%;
    border-collapse: separate; border-spacing: 0;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    overflow: hidden;
    font-size: 14px;
}
.watcher-matrix thead { background: var(--paper-2); }
.watcher-matrix th {
    text-align: left; font-weight: 500;
    padding: 11px 16px;
    color: var(--ink-3);
    font-size: 12.5px;
    border-bottom: 1px solid var(--line);
}
.watcher-matrix th.matrix-col-toggle { text-align: center; width: 100px; }
/* Grouping header that spans the Email / SMS column triplets. Visually
   separates the two channels so the repeated Start/Change/Resolution labels
   on the second row read as "Email Start" vs "SMS Start". */
.watcher-matrix th.matrix-group {
    text-align: center;
    border-left: 1px solid var(--line);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-size: 11px;
    color: var(--ink-4);
    padding: 7px 8px 5px;
}
.watcher-matrix td {
    padding: 12px 16px;
    border-bottom: 1px solid var(--line);
    color: var(--ink-2);
}
.watcher-matrix td.matrix-col-toggle { text-align: center; }
.watcher-matrix tr:last-child td { border-bottom: none; }
.watcher-matrix tr.matrix-apply-all {
    background: var(--pulse-soft);
    border-bottom: 2px solid var(--pulse);
}
.watcher-matrix tr.matrix-apply-all td {
    font-weight: 500;
    color: var(--pulse-ink);
    border-bottom: 2px solid var(--pulse);
}
.watcher-matrix .matrix-monitor-name { font-weight: 500; color: var(--ink); }
.watcher-matrix .matrix-monitor-target {
    font-family: var(--font-mono); font-size: 11.5px;
    color: var(--ink-4); margin-top: 2px;
}
/* Section header row that groups probes by status page in the
   Persons / Groups subscription matrices. Spans every column so the
   page name reads as a band across the matrix. */
.watcher-matrix tr.matrix-page-header td {
    background: var(--paper-2);
    color: var(--ink-3);
    font-size: 11px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    font-weight: 600;
    padding: 8px 12px;
    border-bottom: 1px solid var(--line);
    border-top: 1px solid var(--line);
}
.watcher-matrix tr.matrix-page-header td .matrix-page-count {
    color: var(--ink-4);
    font-weight: 400;
    text-transform: none;
    letter-spacing: 0;
    font-size: 11.5px;
    margin-left: 6px;
}

.watcher-list-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    overflow: hidden;
}
.watcher-list-card table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 14px; }
.watcher-list-card thead { background: var(--paper-2); }
.watcher-list-card th {
    text-align: left; font-weight: 500;
    padding: 11px 16px;
    color: var(--ink-3); font-size: 12.5px;
    border-bottom: 1px solid var(--line);
}
.watcher-list-card td { padding: 12px 16px; border-bottom: 1px solid var(--line); color: var(--ink-2); }
.watcher-list-card tr:last-child td { border-bottom: none; }

/* Status-page Settings tab — left sidebar + right pane. One form wraps every
   section so Save commits all three at once; swapping sections is purely
   display:none/block, non-active sections keep posting their values. */
.settings-layout {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 24px;
    align-items: start;
}
@media (max-width: 720px) {
    .settings-layout { grid-template-columns: 1fr; }
    .settings-sidebar { flex-direction: row; flex-wrap: wrap; }
    .settings-nav-link { border-left: 0; border-bottom: 3px solid transparent; }
    .settings-nav-link.active { border-left-color: transparent; border-bottom-color: var(--pulse); }
}
.settings-sidebar {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.settings-nav-link {
    padding: 10px 14px;
    background: transparent;
    border: 0;
    border-left: 3px solid transparent;
    text-align: left;
    font-size: 14px;
    color: var(--ink-3);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    transition: background 80ms ease, color 80ms ease, border-color 80ms ease;
}
.settings-nav-link:hover {
    background: var(--paper-2);
    color: var(--ink);
}
.settings-nav-link.active {
    background: var(--paper-2);
    color: var(--ink);
    border-left-color: var(--pulse);
    font-weight: 500;
}
.settings-pane { min-width: 0; }
.settings-section { display: none; }
.settings-section.active { display: block; }

body.theme-dark .settings-nav-link:hover,
body.theme-dark .settings-nav-link.active { background: var(--paper-3); }

/* Slack setup walkthrough — numbered steps in a tinted panel so the operator
   can follow them without losing the Settings card's context. */
.slack-setup-steps {
    margin: 0 0 18px;
    padding: 14px 18px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    font-size: 13px;
    color: var(--ink-2);
    line-height: 1.55;
}
.slack-setup-title {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-3);
}
.slack-setup-steps ol {
    margin: 0;
    padding-left: 22px;
}
.slack-setup-steps li { margin-bottom: 4px; }
.slack-setup-steps li:last-child { margin-bottom: 0; }
.slack-setup-steps code {
    font-family: var(--font-mono);
    font-size: 12px;
    padding: 1px 5px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 4px;
}
body.theme-dark .slack-setup-steps { background: var(--paper-3); }
body.theme-dark .slack-setup-steps code { background: var(--paper); }

/* =============================================================================
   Monitor history modals — latency line chart + SLA colour-band band.
   Mirror of the public status page's modals; JS lives in
   /js/monitor-history.js and the IDs below are the contract it reads. Var
   naming follows the app palette (--pulse ↔ "ok", --danger ↔ "down") rather
   than the StatusPages copy (--ok / --down) so the same classes blend with
   the dashboard's existing surfaces.
   ============================================================================= */

.latency-history-btn,
.sla-history-btn {
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0;
    background: transparent;
    border: 1px solid var(--line);
    border-radius: 6px;
    color: var(--ink-3);
    cursor: pointer;
    transition: color 80ms ease, border-color 80ms ease, background 80ms ease;
}
.latency-history-btn { width: 24px; height: 24px; margin-left: 6px; }
.sla-history-btn     { width: 22px; height: 22px; margin-left: 4px; }
.latency-history-btn:hover,
.sla-history-btn:hover {
    color: var(--pulse);
    border-color: var(--pulse);
    background: var(--pulse-soft);
}
.latency-history-btn:focus-visible,
.sla-history-btn:focus-visible {
    outline: 2px solid var(--pulse);
    outline-offset: 2px;
}

.latency-modal {
    position: fixed; inset: 0;
    display: none;
    align-items: center; justify-content: center;
    z-index: 1000;
}
.latency-modal.open { display: flex; }
.latency-modal-backdrop {
    position: absolute; inset: 0;
    background: rgba(15, 18, 17, 0.55);
    backdrop-filter: blur(2px);
}
.latency-modal-content {
    position: relative;
    width: min(920px, 94vw);
    max-height: 88vh;
    overflow-y: auto;
    background: var(--paper);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    box-shadow: 0 20px 60px rgba(15, 18, 17, 0.25);
    padding: 22px 24px 20px;
}
.latency-modal-header {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 16px;
    margin-bottom: 14px;
}
.latency-modal-header h2 {
    margin: 0;
    font-size: 18px;
    letter-spacing: -0.01em;
}
.latency-modal-sub {
    margin: 4px 0 0;
    font-size: 13px; color: var(--ink-3);
}
.latency-modal-close {
    background: transparent; border: 0;
    font-size: 24px; line-height: 1;
    color: var(--ink-3);
    cursor: pointer;
    padding: 2px 8px;
    border-radius: 6px;
}
.latency-modal-close:hover { color: var(--ink); background: var(--paper-2); }

.latency-modal-controls {
    display: flex; align-items: center; gap: 10px;
    margin-bottom: 14px;
    font-size: 13px; color: var(--ink-3);
}
.latency-window-select {
    padding: var(--input-pad-y-sm) var(--input-pad-x-sm);
    font-size: 13px;
    background: var(--paper);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.latency-modal-chart {
    width: 100%;
    aspect-ratio: 2 / 1;
    min-height: 240px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--paper-2);
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
}
.latency-modal-meta {
    margin: 10px 0 0;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 12px; color: var(--ink-4);
}

.latency-svg { width: 100%; height: 100%; display: block; }
.latency-line {
    fill: none;
    stroke: var(--pulse);
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}
.trend-line {
    stroke: #d97706;
    stroke-width: 1.5;
    stroke-dasharray: 6 5;
    fill: none;
    opacity: 0.9;
}

/* Min / Avg / Max reference lines on the latency chart. Thinner than the
   trend line so the data line stays the visual focus. Brand v1.1: the
   palette aligns with the platform tokens — min uses the deeper accent
   (a darker shade of pulse), max uses the semantic --danger, avg sits
   on a neutral muted ink so it doesn't fight either. */
.ref-line { fill: none; stroke-width: 1; stroke-dasharray: 4 3; opacity: 0.75; }
.ref-line-min { stroke: var(--pulse-ink); }
.ref-line-avg { stroke: var(--ink-3); }
.ref-line-max { stroke: var(--danger); }
.ref-line-label { font-size: 11px; font-weight: 500; opacity: 0.9; }
.ref-line-label-min { fill: var(--pulse-ink); }
.ref-line-label-avg { fill: var(--ink-3); }
.ref-line-label-max { fill: var(--danger); }

.latency-chart-legend {
    display: flex; flex-wrap: wrap; align-items: center; gap: 18px;
    margin-top: 12px;
    font-size: 12px; color: var(--ink-3);
}
.latency-chart-legend .legend-item {
    display: inline-flex; align-items: center; gap: 8px;
}
.latency-chart-legend .legend-swatch {
    display: inline-block;
    width: 18px; height: 0;
}
.latency-chart-legend .legend-swatch-line {
    border-top: 3px solid var(--pulse);
}
.latency-chart-legend .legend-swatch-trend {
    border-top: 2px dashed var(--coral);
}
.latency-chart-legend .legend-swatch-min { border-top: 2px dashed var(--pulse-ink); }
.latency-chart-legend .legend-swatch-avg { border-top: 2px dashed var(--ink-3); }
.latency-chart-legend .legend-swatch-max { border-top: 2px dashed var(--danger); }
.latency-chart-legend .legend-note {
    color: var(--ink-4);
    font-style: italic;
}

.sla-band-wrap {
    width: 100%;
    min-height: 120px;
    padding: 6px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--paper-2);
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
}
.sla-band-svg {
    width: 100%;
    height: 120px;
    display: block;
}

.latency-chart-legend .sla-swatch {
    display: inline-block;
    width: 26px; height: 12px;
    border-radius: 3px;
    vertical-align: middle;
    margin-right: 6px;
}
.latency-chart-legend .sla-swatch-good {
    background: linear-gradient(to right, hsl(145, 45%, 72%), hsl(145, 70%, 32%));
}
.latency-chart-legend .sla-swatch-bad {
    background: linear-gradient(to right, hsl(2, 60%, 78%), hsl(2, 75%, 32%));
}
.latency-chart-legend .sla-swatch-gap { background: #3a3e3b; }

.chart-grid-line {
    stroke: var(--line);
    stroke-width: 1;
    stroke-dasharray: 2 4;
}
.chart-axis {
    stroke: var(--ink-4);
    stroke-width: 1;
}
.chart-axis-label {
    fill: var(--ink-3);
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 14px;
}
.chart-axis-title {
    fill: var(--ink-3);
    font-family: "Inter Tight", sans-serif;
    font-size: 14px;
}

.latency-chart-loading,
.latency-chart-empty,
.latency-chart-error {
    font-size: 13px; color: var(--ink-3);
    padding: 16px;
    text-align: center;
}
.latency-chart-error { color: var(--danger); }

/* Dark theme overrides — mirror the status.css dark block. The app already
   defines most of the palette via body.theme-dark; only surfaces with hard-
   coded tints need an override here. */
body.theme-dark .latency-modal-content {
    background: var(--paper-2);
}
body.theme-dark .latency-modal-chart,
body.theme-dark .sla-band-wrap {
    background: rgba(255, 255, 255, 0.03);
    border-color: rgba(255, 255, 255, 0.08);
}
body.theme-dark .latency-line { stroke: #5fe5a7; }
body.theme-dark .trend-line { stroke: #fbbf24; }
body.theme-dark .ref-line-min { stroke: #38bdf8; }
body.theme-dark .ref-line-avg { stroke: #a78bfa; }
body.theme-dark .ref-line-max { stroke: #f87171; }
body.theme-dark .ref-line-label-min { fill: #38bdf8; }
body.theme-dark .ref-line-label-avg { fill: #a78bfa; }
body.theme-dark .ref-line-label-max { fill: #f87171; }
body.theme-dark .latency-chart-legend .legend-swatch-line { border-top-color: #5fe5a7; }
body.theme-dark .latency-chart-legend .legend-swatch-trend { border-top-color: #fbbf24; }
body.theme-dark .latency-chart-legend .legend-swatch-min { border-top-color: #38bdf8; }
body.theme-dark .latency-chart-legend .legend-swatch-avg { border-top-color: #a78bfa; }
body.theme-dark .latency-chart-legend .legend-swatch-max { border-top-color: #f87171; }
body.theme-dark .latency-chart-legend .sla-swatch-gap { background: #6a6e6b; }
body.theme-dark .chart-grid-line { stroke: rgba(255, 255, 255, 0.08); }
body.theme-dark .chart-axis { stroke: rgba(255, 255, 255, 0.2); }
body.theme-dark .latency-chart-error { color: #ff8a8a; }

/* ── Forecast tab (probe detail) ─────────────────────────────────────── */
.forecast-tab { display: flex; flex-direction: column; gap: 18px; }

.forecast-summary {
    background: #ffffff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 18px 22px;
}
.forecast-current h2 { margin: 0 0 4px 0; font-size: 18px; }
.forecast-current-sub { margin: 0 0 14px 0; color: var(--ink-3); font-size: 13px; }

.forecast-bars { display: flex; flex-direction: column; gap: 10px; }
.forecast-bar-row {
    display: grid;
    grid-template-columns: 110px 1fr 56px;
    align-items: center;
    gap: 12px;
}
.forecast-bar-label { font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.forecast-bar-track {
    position: relative;
    height: 14px;
    background: var(--paper-2);
    border-radius: 7px;
    overflow: hidden;
    border: 1px solid var(--line);
}
.forecast-bar-fill {
    position: absolute; top: 0; left: 0; bottom: 0;
    border-radius: 7px 0 0 7px;
    transition: width 200ms ease;
}
.forecast-bar-fill.forecast-band-ok      { background: var(--pulse); }
.forecast-bar-fill.forecast-band-warn    { background: var(--amber); }
.forecast-bar-fill.forecast-band-down    { background: var(--danger); }
.forecast-bar-fill.forecast-band-unknown { background: var(--ink-4); }
.forecast-bar-threshold {
    position: absolute; top: -2px; bottom: -2px; width: 2px;
    background: var(--ink-2); opacity: 0.55;
}
.forecast-bar-value {
    text-align: right;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 14px;
}

.forecast-config { margin: 14px 0 0 0; font-size: 13px; color: var(--ink-3); }
.forecast-config a { color: var(--ink-2); text-decoration: underline; }

.forecast-chart-card {
    background: #ffffff;
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 16px 20px;
}
.forecast-chart-header {
    display: flex; align-items: center; justify-content: space-between;
    gap: 16px; margin-bottom: 8px; flex-wrap: wrap;
}
.forecast-chart-header h2 { margin: 0; font-size: 16px; }
.forecast-chart-legend {
    display: flex; align-items: center; gap: 10px;
    font-size: 12px; color: var(--ink-3);
}
.forecast-chart-legend .legend-dot {
    width: 10px; height: 10px; border-radius: 50%; display: inline-block;
}
.forecast-chart-legend .legend-line {
    width: 14px; height: 2px; display: inline-block; background: var(--ink-3);
    border-top: 2px dashed var(--ink-3); background: transparent;
}
.forecast-chart-legend .legend-deg  { background: var(--amber); }
.forecast-chart-legend .legend-down { background: var(--danger); }

.forecast-chart {
    width: 100%; height: 220px;
    display: block;
}
.forecast-band-fill-warn { fill: var(--amber); fill-opacity: 0.07; }
.forecast-band-fill-down { fill: var(--danger); fill-opacity: 0.10; }
.forecast-grid-line { stroke: var(--line-2); stroke-width: 1; stroke-dasharray: 2 3; }
.forecast-axis-label { font-size: 10px; fill: var(--ink-3); }
.forecast-thr-line { stroke-width: 1.2; stroke-dasharray: 4 3; opacity: 0.7; fill: none; }
.forecast-thr-deg  { stroke: var(--amber); }
.forecast-thr-down { stroke: var(--danger); }
.forecast-series { fill: none; stroke-width: 1.6; }
.forecast-series-deg  { stroke: var(--amber); }
.forecast-series-down { stroke: var(--danger); }

.forecast-model-info {
    background: var(--paper-2);
    border-radius: var(--radius-sm);
    padding: 12px 16px;
    font-size: 13px;
}
.forecast-model-info h3 { margin: 0 0 6px 0; font-size: 13px; color: var(--ink-3); font-weight: 600; }
.forecast-model-list { margin: 0; padding-left: 18px; color: var(--ink-2); }
.forecast-model-list li { margin: 2px 0; }

body.theme-dark .forecast-summary,
body.theme-dark .forecast-chart-card {
    background: #1a1d1c;
    border-color: rgba(255, 255, 255, 0.10);
}
body.theme-dark .forecast-bar-track { background: #0E1A16; border-color: rgba(255, 255, 255, 0.10); }
body.theme-dark .forecast-bar-threshold { background: rgba(255, 255, 255, 0.45); }
body.theme-dark .forecast-grid-line { stroke: rgba(255, 255, 255, 0.08); }
body.theme-dark .forecast-axis-label { fill: rgba(255, 255, 255, 0.55); }
body.theme-dark .forecast-model-info { background: #0E1A16; }

/* ---- Incidents (Phase 1) -------------------------------------------------
   Pills for state + severity + impact, plus the timeline ordered list and
   the simple list table on /Dashboard/Incidents. Lifecycle states are
   neutral-coloured (the lifecycle is informational); severity pulls amber
   / coral / danger depending on customer impact. */
.incident-state-pill,
.incident-severity-pill {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
    line-height: 18px;
    letter-spacing: 0.01em;
    border: 1px solid transparent;
}
.incident-state-investigating { background: var(--amber-soft); color: var(--amber); }
.incident-state-identified    { background: var(--coral-soft); color: var(--coral-ink); }
.incident-state-monitoring    { background: var(--pulse-soft); color: var(--pulse-ink); }
.incident-state-resolved      { background: var(--paper-2); color: var(--ink-3); }
.incident-state-postmortempublished { background: var(--paper-2); color: var(--ink-3); }
.incident-state-comment       { background: var(--paper-2); color: var(--ink-4); }
.incident-state-scheduled     { background: var(--paper-2); color: var(--coral-ink); border-color: var(--coral-soft); }

.incident-severity-none     { background: var(--paper-2); color: var(--ink-4); }
.incident-severity-minor    { background: var(--amber-soft); color: var(--amber); }
.incident-severity-major    { background: var(--coral-soft); color: var(--coral-ink); }
.incident-severity-critical { background: var(--danger-soft); color: var(--danger); }

.incident-header-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    color: var(--ink-3);
    font-size: 13.5px;
}
.incident-meta-sep { color: var(--ink-4); }

.subtab-count {
    display: inline-flex;
    min-width: 20px;
    height: 18px;
    padding: 0 6px;
    margin-left: 6px;
    border-radius: 999px;
    background: var(--paper-2);
    color: var(--ink-3);
    font-size: 11px;
    line-height: 18px;
    align-items: center;
    justify-content: center;
}
.workspace-subtab.active .subtab-count {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
}

/* Incident list table — modest, full-width inside a workspace-card. */
.incident-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}
.incident-table thead th {
    text-align: left;
    color: var(--ink-3);
    font-weight: 500;
    font-size: 12.5px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 10px 12px;
    border-bottom: 1px solid var(--line);
}
.incident-table tbody td {
    padding: 12px;
    border-bottom: 1px solid var(--line);
    color: var(--ink-2);
    vertical-align: middle;
}
.incident-table tbody tr:last-child td { border-bottom: 0; }
.incident-title-link {
    color: var(--ink);
    text-decoration: none;
    font-weight: 500;
}
.incident-title-link:hover { color: var(--pulse-ink); text-decoration: underline; }

/* Timeline — vertical bullet list, newest first. Each item is a card-like
   block with a meta-row (state pill + author + time + Internal tag) and
   the rendered Markdown body below. */
.incident-timeline {
    list-style: none;
    margin: 0;
    padding: 0;
}
.incident-timeline-item {
    border-left: 2px solid var(--line-2);
    padding: 8px 0 18px 18px;
    margin-left: 6px;
}
.incident-timeline-item:last-child { padding-bottom: 6px; }
.incident-timeline-item-internal {
    border-left-color: var(--coral);
    background: linear-gradient(90deg, var(--coral-soft) 0, transparent 60%);
}
.incident-timeline-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    color: var(--ink-3);
    font-size: 12.5px;
    margin-bottom: 6px;
}
.incident-timeline-author { color: var(--ink-2); font-weight: 500; }
.incident-timeline-body {
    color: var(--ink-2);
    font-size: 14px;
    line-height: 1.55;
}
.incident-timeline-body p { margin: 0 0 8px 0; }
.incident-timeline-body p:last-child { margin-bottom: 0; }
.incident-timeline-body code {
    background: var(--paper-2);
    padding: 1px 6px;
    border-radius: 4px;
    font-family: var(--font-mono);
    font-size: 0.92em;
}
.incident-timeline-body pre {
    background: var(--paper-2);
    padding: 10px 12px;
    border-radius: var(--radius-sm);
    overflow-x: auto;
    font-size: 13px;
}
.incident-timeline-body a { color: var(--pulse-ink); }
.incident-internal-tag {
    color: var(--coral-ink);
    font-weight: 600;
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Auto-detect badge — distinguishes engine-opened incidents from manual ones.
   Shown next to the title in the list and next to the state pill in the
   detail header. Locked variant is muted to signal the engine has stopped
   touching this row. */
.incident-auto-badge {
    display: inline-flex;
    align-items: center;
    margin-left: 8px;
    padding: 1px 8px;
    border-radius: 999px;
    background: var(--paper-2);
    color: var(--ink-3);
    border: 1px dashed var(--line-2);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}
body.theme-dark .incident-auto-badge {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.20);
    color: var(--ink-3);
}

/* Phase 4 — scheduled maintenance card on Dashboard/Incidents/Index. */
.incident-upcoming-card { margin-bottom: 18px; }
.incident-upcoming-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 10px;
}
.incident-upcoming-count {
    background: var(--coral-soft);
    color: var(--coral-ink);
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
}
.incident-upcoming-list { list-style: none; margin: 0; padding: 0; }
.incident-upcoming-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
}
.incident-upcoming-row:last-child { border-bottom: 0; }
.incident-upcoming-meta {
    margin-top: 2px;
    color: var(--ink-3);
    font-size: 12.5px;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;
}
.incident-upcoming-manual {
    color: var(--coral-ink);
    font-weight: 500;
}
.incident-maintenance-tag {
    color: var(--coral-ink);
    font-weight: 600;
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.incident-schedule-readout {
    margin: 0;
    display: grid;
    grid-template-columns: 100px 1fr;
    gap: 4px 14px;
    color: var(--ink-2);
    font-size: 13.5px;
}
.incident-schedule-readout dt { color: var(--ink-3); font-weight: 500; }
.incident-schedule-readout dd { margin: 0; }

body.theme-dark .incident-upcoming-row { border-bottom-color: rgba(255, 255, 255, 0.08); }
body.theme-dark .incident-upcoming-count { background: rgba(255, 122, 26, 0.15); color: var(--coral); }

/* Phase 6 — AI draft button on the incident detail post-update card.
   Sits next to the "Post update" kicker; visually quieter than the primary
   submit button so the operator's eye still goes to the manual flow. */
.post-update-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 6px;
}
.post-update-ai-form { margin: 0; }
.ai-draft-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 5px 12px;
    border-radius: 999px;
    border: 1px dashed var(--line-2);
    background: var(--paper-2);
    color: var(--ink-3);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.02em;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.ai-draft-btn:hover {
    background: var(--pulse-soft);
    border-color: var(--pulse);
    color: var(--pulse-ink);
}
.ai-draft-btn:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}
.ai-draft-quota {
    color: var(--ink-4);
    font-weight: 500;
    font-size: 11px;
    margin-left: 2px;
}
body.theme-dark .ai-draft-btn {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.20);
    color: var(--ink-3);
}
body.theme-dark .ai-draft-btn:hover {
    background: rgba(16, 192, 116, 0.15);
    border-color: var(--pulse);
    color: var(--pulse);
}

/* Phase 7 — Post-mortem editor on Dashboard/Incidents/PostMortem. */
.postmortem-status {
    display: inline-flex;
    align-items: center;
    padding: 2px 9px;
    border-radius: 999px;
    font-size: 11.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.postmortem-status-draft {
    background: var(--paper-2);
    color: var(--ink-3);
    border: 1px dashed var(--line-2);
}
.postmortem-status-published {
    background: var(--pulse-soft);
    color: var(--pulse-ink);
}
.postmortem-actions {
    display: flex;
    gap: 10px;
    margin-top: 16px;
    flex-wrap: wrap;
}
.postmortem-meta {
    margin: 12px 0 0 0;
    color: var(--ink-4);
    font-size: 12.5px;
}
body.theme-dark .postmortem-status-draft {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.20);
    color: var(--ink-3);
}

/* Phase 8 — Admin Incidents page metric tiles + sortable column headers. */
.admin-metric-tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 14px;
    margin: 18px 0 24px 0;
}
.admin-metric-tile {
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    padding: 16px 18px;
}
.admin-metric-label {
    margin: 0 0 6px 0;
    font-size: 12px;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
}
.admin-metric-value {
    margin: 0;
    font-size: 28px;
    font-weight: 600;
    color: var(--ink);
    font-family: var(--font-mono);
}
.admin-metric-value.admin-metric-warn { color: var(--coral-ink); }
.admin-metric-empty {
    font-size: 14px;
    font-weight: 400;
    color: var(--ink-4);
    font-family: inherit;
}
.admin-metric-sub {
    margin: 4px 0 0 0;
    font-size: 11.5px;
    color: var(--ink-4);
}
.admin-list-meta {
    color: var(--ink-3);
    font-size: 13px;
    margin: 0 0 12px 0;
}
.admin-tenant-plan {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--paper-2);
    color: var(--ink-3);
    font-size: 10.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.admin-table th a {
    color: inherit;
    text-decoration: none;
}
.admin-table th a:hover { color: var(--pulse-ink); }

body.theme-dark .admin-metric-tile {
    background: rgba(255, 255, 255, 0.04);
    border-color: rgba(255, 255, 255, 0.10);
}
body.theme-dark .admin-tenant-plan {
    background: rgba(255, 255, 255, 0.08);
}

/* Component impact matrix — name on the left, impact dropdown on the right. */
.incident-component-list { list-style: none; margin: 0; padding: 0; }
.incident-component-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    border-bottom: 1px solid var(--line);
}
.incident-component-row:last-child { border-bottom: 0; }
.incident-component-name {
    font-size: 14px;
    color: var(--ink-2);
    font-weight: 500;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Inline impact dropdowns next to each component name. The selects sit
   outside any `.field` wrapper so we replicate the standard form-control
   look here directly — border, padding, paper background, focus ring. */
.incident-component-form select,
.incident-component-add select {
    min-width: 140px;
    padding: var(--input-pad-y-lg) var(--input-pad-x-lg);
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    font: inherit;
    font-size: 14px;
    background: var(--paper);
    color: var(--ink);
    transition: border-color 0.15s, background 0.15s;
}
.incident-component-form select:focus,
.incident-component-add select:focus {
    outline: none;
    border-color: var(--pulse);
    background: #fff;
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
.incident-component-add { margin-top: 14px; }

body.theme-dark .incident-component-form select,
body.theme-dark .incident-component-add select {
    background: var(--paper-2);
}
body.theme-dark .incident-component-form select:focus,
body.theme-dark .incident-component-add select:focus {
    background: #1a1d1c;
}

/* Two-column form row used on Detail page (state + visibility, severity +
   initial state, etc). Stacks on narrow screens.
   `margin-bottom` matches the standard `.field` so the next sibling field
   doesn't end up flush against the row (the inner `.field`s have their
   own bottom margin zeroed). */
.form-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-bottom: 18px;
}
.form-row > .field { margin-bottom: 0; }
@media (max-width: 600px) {
    .form-row { grid-template-columns: 1fr; }
}

/* Form-actions — right-aligned button row at the bottom of forms.
   Save/Submit comes first, Cancel after, per the project convention. */
.form-actions {
    display: flex;
    gap: 10px;
    margin-top: 14px;
}

/* Multi-select component list inside the Create modal. */
.checkbox-list {
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    padding: 8px 10px;
    background: var(--paper);
}
.checkbox-list-group-title {
    margin: 8px 0 4px 0;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.checkbox-list-group-title:first-child { margin-top: 0; }
.checkbox-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    font-size: 14px;
    color: var(--ink-2);
    cursor: pointer;
}
.checkbox-row input[type="checkbox"] { margin: 0; }

/* Affected-components grid in the New incident / Schedule maintenance
   modals. Two columns of `.toggle-row` items (toggle pill + name +
   bracketed probe-type label), grouped by status page. Capped height
   with a scrollbar for tenants with many monitors. */
.incident-component-grid-wrap {
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    padding: 10px 12px;
    background: var(--paper);
    max-height: 240px;
    overflow-y: auto;
}
.incident-component-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    column-gap: 16px;
    row-gap: 4px;
    margin-bottom: 4px;
}
@media (max-width: 540px) {
    .incident-component-grid { grid-template-columns: 1fr; }
}
.incident-component-grid-label {
    font-size: 14px;
    color: var(--ink-2);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.incident-component-grid-type {
    font-size: 12px;
    color: var(--ink-4);
    margin-left: 4px;
}
body.theme-dark .incident-component-grid-wrap {
    background: #1a1d1c;
    border-color: rgba(255, 255, 255, 0.10);
}

/* Dark theme overrides — pills keep their accent colours; only the neutral
   surfaces flip. */
body.theme-dark .incident-state-resolved,
body.theme-dark .incident-state-postmortempublished,
body.theme-dark .incident-state-comment,
body.theme-dark .incident-severity-none,
body.theme-dark .subtab-count {
    background: #1a1d1c;
    color: var(--ink-4);
}
body.theme-dark .incident-table thead th { color: var(--ink-4); }
body.theme-dark .incident-table tbody td { color: var(--ink-2); border-bottom-color: rgba(255, 255, 255, 0.08); }
body.theme-dark .incident-timeline-item { border-left-color: rgba(255, 255, 255, 0.16); }
body.theme-dark .incident-component-row { border-bottom-color: rgba(255, 255, 255, 0.08); }
body.theme-dark .checkbox-list { background: #1a1d1c; border-color: rgba(255, 255, 255, 0.10); }

/* /Onboarding signup page
   ============================================================================= */
.onboarding {
    padding: 60px 0 80px;
    display: flex;
    justify-content: center;
}
.onboarding-card {
    background: #fff;
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 36px;
    width: 100%;
    max-width: 520px;
}
.onboarding-title {
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 500;
    margin: 4px 0 10px;
    letter-spacing: -0.01em;
    color: var(--ink);
}
.onboarding-lede {
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-3);
    margin-bottom: 22px;
}
.onboarding-cancelled {
    margin-bottom: 18px;
}
.onboarding-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 540px) {
    .onboarding-grid { grid-template-columns: 1fr; gap: 0; }
}
body.theme-dark .onboarding-card { background: var(--paper-2); }

/* ── Branding tab — custom file picker ──────────────────────────────────
   The native <input type="file"> button is impossible to style consistently
   across browsers. We hide the native control, render a label-as-button on
   the right (matches .btn-ghost), and a textbox-style filename area on the
   left. The wrapper mimics .field input / .field select shape (border,
   radius, background, padding, font-size) so it lines up visually with the
   Font family combobox below. JS at the bottom of
   Pages/Dashboard/Index.cshtml writes the selected file's name into the
   filename span. */
.branding-file-picker {
    /* Wrapper mimics .field input shape (border, radius, background,
       height) so the picker lines up vertically with sibling fields.
       The Browse button is a *pill inside* the textbox — not edge-flush
       with a separator — so a small inner padding hosts it visually
       inside the field. */
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-md);
    background: var(--paper);
    padding: 4px;
    transition: border-color 0.15s, background 0.15s;
}
.branding-file-picker:focus-within {
    border-color: var(--pulse);
    background: #fff;
    box-shadow: 0 0 0 3px var(--pulse-soft);
}
.branding-file-picker-name {
    flex: 1 1 auto;
    /* font: inherit anchors the family explicitly (defends against
       any ambient span styling); 14px font-size + 7px vertical padding
       sums with the wrapper's 4px to match .field input's 11px. */
    font: inherit;
    font-size: 14px;
    padding: 7px 10px;
    color: var(--ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.branding-file-picker-name.is-empty { color: var(--ink-4); }
.branding-file-picker-input {
    /* Hidden but keyboard-focusable via label[for]. Not display:none so
       label[for] activation still routes the click to the input. */
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}
.branding-file-picker-btn {
    /* Self-contained pill — does NOT inherit .btn / .btn-ghost. Sits
       inside the field; no own border, blends via paper-2 background. */
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    padding: 6px 14px;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    color: var(--ink);
    background: var(--paper-2);
    border: 0;
    border-radius: calc(var(--radius-md) - 2px);
    cursor: pointer;
    transition: background 0.15s;
    user-select: none;
}
.branding-file-picker-btn:hover { background: var(--paper-3); }
body.theme-dark .branding-file-picker { background: var(--paper-3); }
body.theme-dark .branding-file-picker:focus-within { background: var(--paper-3); }
body.theme-dark .branding-file-picker-btn { background: var(--paper-2); }
body.theme-dark .branding-file-picker-btn:hover { background: var(--paper); }

/* =============================================================================
   Dashboard tab probe rows — mirrors the public status page's service-row
   layout so the operator's read-only Dashboard tab looks like what visitors
   see (probe heatmap, latency, SLA badges, modals). Branding overrides are
   intentionally NOT applied here — the dashboard uses platform tokens
   (--pulse / --coral / --danger) instead of the StatusPages tokens
   (--ok / --warn / --down) so the operator sees a neutral platform view.
   ============================================================================ */
.services { list-style: none; margin: 0; padding: 0; }
.service-row {
    display: flex; flex-direction: column;
    gap: 12px;
    padding: 16px 18px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-left-width: 4px;
    border-left-color: var(--pulse);
    border-radius: var(--radius-md);
    margin-bottom: 8px;
    overflow: visible; /* heatmap tooltip needs to escape row bounds */
}
.service-row-top {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 16px;
}
.service-row-chart {
    padding-top: 10px;
    border-top: 1px dashed var(--line);
}
.service-row-metrics {
    display: flex; flex-wrap: wrap; align-items: center; gap: 18px;
    padding-top: 8px;
    border-top: 1px dashed var(--line);
    font-size: 12.5px; color: var(--ink-3);
}
.metric-uptime { margin-left: auto; }
.service-info { min-width: 0; }
.service-row strong { display: block; font-size: 15px; }
.service-meta {
    display: block; margin-top: 2px;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11.5px; color: var(--ink-4);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Heatmap chart — 48 columns × 6 ten-min rows = 288 cells of 10 minutes
   each. Cells stretch via 1fr columns; rows are fixed at 10px so the chart
   stays a thin band regardless of viewport width. */
.chart {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-rows: auto auto;
    column-gap: 8px;
    row-gap: 4px;
    width: 100%;
}
.chart-y-axis {
    grid-column: 1; grid-row: 1;
    display: flex; flex-direction: column; justify-content: space-between;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 10px; line-height: 1;
    color: var(--ink-4);
}
.chart-grid {
    grid-column: 2; grid-row: 1;
    display: grid;
    grid-template-columns: repeat(48, 1fr);
    grid-template-rows: repeat(6, 10px);
    grid-auto-flow: column;
    gap: 2px;
    width: 100%;
}
.cell {
    border-radius: 2px;
    background: var(--ink-4);
    position: relative;
    transition: filter 0.15s, transform 0.15s;
    cursor: default;
    min-width: 0; min-height: 0;
}
.cell:hover { filter: brightness(1.15); transform: scale(1.25); z-index: 5; }
.cell-ok      { background: var(--pulse); }
.cell-warn    { background: var(--coral); }
.cell-down    { background: var(--danger); }
.cell-unknown { background: var(--ink-4); }
.cell-empty   { background: var(--paper-2); }

/* Heatmap colour legend — three swatches (Operational, Degraded, Down)
   rendered above the probe list on the dashboard. Reuses the same
   semantic colour tokens as the heatmap cells so any theme tweak
   propagates automatically (dark theme inherits via --pulse / --coral
   / --danger redefinitions). */
.heatmap-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    align-items: center;
    margin: 0 0 14px;
    padding: 6px 12px;
    font-size: 12.5px;
    color: var(--ink-3);
}
.heatmap-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.heatmap-legend-swatch {
    width: 10px; height: 10px;
    border-radius: 2px;
    display: inline-block;
    flex-shrink: 0;
}
.heatmap-legend-swatch-ok   { background: var(--pulse); }
.heatmap-legend-swatch-warn { background: var(--coral); }
.heatmap-legend-swatch-down { background: var(--danger); }
/* CSS tooltip — replaces the slow native title tooltip. Positions above the
   cell with a small arrow. */
.cell[data-tip]:hover::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%) scale(0.8);
    padding: 6px 10px;
    background: var(--ink);
    color: var(--paper);
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 11px; line-height: 1.3;
    border-radius: 4px;
    white-space: nowrap;
    z-index: 10;
    pointer-events: none;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.cell[data-tip]:hover::before {
    content: "";
    position: absolute;
    bottom: calc(100% + 2px);
    left: 50%;
    transform: translateX(-50%) scale(0.8);
    border: 4px solid transparent;
    border-top-color: var(--ink);
    z-index: 10;
    pointer-events: none;
}
.chart-x-axis {
    grid-column: 2; grid-row: 2;
    display: flex; justify-content: space-between;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-size: 10px; line-height: 1;
    color: var(--ink-4);
    padding-top: 2px;
}

.metric-pair { display: inline-flex; gap: 6px; align-items: baseline; }
.metric-pair strong {
    display: inline;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    font-weight: 500; font-size: 13px;
    color: var(--ink);
}

.service-badges {
    display: flex; align-items: center; gap: 8px;
    flex-shrink: 0;
}
.service-status {
    padding: 4px 12px;
    border-radius: 6px;
    font-size: 13px; font-weight: 500;
    flex-shrink: 0;
}
.status-ok      { background: var(--pulse-soft);  color: var(--pulse); }
.status-warn    { background: var(--coral-soft);  color: var(--coral); }
.status-down    { background: var(--danger-soft); color: var(--danger); }
.status-paused  { background: var(--paper-2);    color: var(--ink-4); }
.status-unknown { background: var(--paper-2);    color: var(--ink-3); }

/* SLA badge — twin pill next to .service-status. Reflects rolling-window vs.
   the monitor's configured SLA target; the status pill next to it is
   independent and reflects the latest check only. */
.sla-badge {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 10px;
    border-radius: 6px;
    font-size: 12px; font-weight: 500;
    font-family: "JetBrains Mono", ui-monospace, monospace;
    flex-shrink: 0;
}
.sla-badge-ok      { background: var(--pulse-soft);  color: var(--pulse); }
.sla-badge-breach  { background: var(--danger-soft); color: var(--danger); }
.sla-badge-unknown { background: var(--paper-2);    color: var(--ink-3); }

/* Status-driven row tint — border + background track the latest status. SLA
   breach does NOT alter the row; it's conveyed only by the SLA badge above. */
.service-row.status-row-ok      { background: var(--paper-2);    border-left-color: var(--pulse); }
.service-row.status-row-warn    { background: var(--coral-soft); border-left-color: var(--coral); }
.service-row.status-row-down    { background: var(--danger-soft); border-left-color: var(--danger); }
.service-row.status-row-paused  { border-left-color: var(--ink-4); }
.service-row.status-row-unknown { border-left-color: var(--ink-4); }

/* History buttons — small icon buttons that sit next to the SLA badge and
   the latency metric and open the shared latency/SLA modals. Same visual
   recipe so they read as a pair. */
.latency-history-btn,
.sla-history-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 24px;
    margin-left: 6px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--line);
    border-radius: 6px;
    color: var(--ink-3);
    cursor: pointer;
    transition: color 80ms ease, border-color 80ms ease, background 80ms ease;
}
.latency-history-btn:hover,
.sla-history-btn:hover {
    color: var(--pulse);
    border-color: var(--pulse);
    background: var(--pulse-soft);
}
.latency-history-btn:focus-visible,
.sla-history-btn:focus-visible {
    outline: 2px solid var(--pulse);
    outline-offset: 2px;
}

/* Empty list message — no probes configured yet on this page. */
.services-empty {
    text-align: center;
    padding: 48px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    color: var(--ink-3);
}

/* Dark theme — empty cells need a higher-contrast background than --paper-2,
   which collapses into the row tint. The tooltip flips to the light ink so it
   contrasts with the dark surroundings. */
body.theme-dark .cell-empty { background: rgba(255, 255, 255, 0.06); }
body.theme-dark .cell[data-tip]:hover::after { background: var(--ink); color: var(--paper); }
body.theme-dark .cell[data-tip]:hover::before { border-top-color: var(--ink); }

/* Reconnecting pill from the soft-refresh handler (defined in
   StatusPulse.StatusPages) reused here too — declared inline in the cshtml
   for that page, but the dashboard tab adds its own copy below. */

/* =============================================================================
   Main dashboard — KPI strip + page grid for /Dashboard/Probes/Index
   (the "Dashboard" item in the top nav). Each card represents one status
   page; probe badges are coloured by current LastStatus. Cards are
   anchors that link to the per-page detail view (/Dashboard/Index?pageId=…)
   so all CRUD operations still live there.
   ============================================================================ */

/* Two-row KPI layout on a 12-col grid (LCM of 3 and 4):
     row 1 — 3 cards × span 4 = Status pages / Active incidents / Uptime
     row 2 — 4 cards × span 3 = Configured probes / Up / Degraded / Down
   nth-child rules key off document order, so the cshtml must keep the
   row-1 cards first. */
.kpi-strip {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 10px;
    margin-bottom: 24px;
}
.kpi-strip > .kpi-card:nth-child(-n+3) { grid-column: span 4; }
.kpi-strip > .kpi-card:nth-child(n+4)  { grid-column: span 3; }
@media (max-width: 720px) {
    /* Narrow viewports: collapse both rows to two-up. */
    .kpi-strip { grid-template-columns: repeat(2, 1fr); }
    .kpi-strip > .kpi-card:nth-child(-n+3),
    .kpi-strip > .kpi-card:nth-child(n+4)  { grid-column: span 1; }
}
/* KPI card — outer container is a div, not an anchor, because it hosts
   TWO anchors: the main body (opens the breakdown modal) and the small
   chart icon in the bottom-right (opens the chart modal). position:
   relative anchors the chart button. */
.kpi-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    padding: 14px 14px 18px;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    min-width: 0;
    transition: border-color 0.15s, background 0.15s, transform 0.15s;
}
.kpi-card:hover {
    border-color: var(--pulse);
    background: color-mix(in srgb, var(--pulse) 4%, var(--paper-2));
    transform: translateY(-1px);
}
body.theme-dark .kpi-card:hover {
    background: color-mix(in srgb, var(--pulse) 6%, var(--paper-2));
}
.kpi-card-body {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    color: inherit;
    text-decoration: none;
    flex: 1;
    /* Leave clearance for the chart icon in the bottom-right so the
       value text never overlaps it on narrow cards. */
    padding-bottom: 4px;
}
.kpi-card-chart-btn {
    position: absolute;
    right: 8px;
    bottom: 8px;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 6px;
    color: var(--ink-3);
    background: transparent;
    border: 1px solid transparent;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
    text-decoration: none;
}
.kpi-card-chart-btn:hover {
    color: var(--pulse);
    border-color: var(--pulse);
    background: var(--pulse-soft);
}
.kpi-label {
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.03em;
    color: var(--ink);
    margin-bottom: 4px;
}
.kpi-desc {
    font-size: 11px;
    color: var(--ink-3);
    line-height: 1.3;
    margin-bottom: 12px;
    min-height: 28px; /* keeps all 7 cards the same height even when description
                        is 1 vs 2 lines */
}
.kpi-value {
    font-family: var(--font-mono);
    font-size: 24px;
    font-weight: 600;
    color: var(--ink);
    line-height: 1;
}
.kpi-value-ok   { color: var(--pulse-ink); }
.kpi-value-warn { color: var(--coral-ink); }
.kpi-value-down { color: var(--danger); }
.kpi-value-muted { color: var(--ink-4); font-family: inherit; }

body.theme-dark .kpi-value-ok   { color: var(--pulse); }
body.theme-dark .kpi-value-warn { color: var(--coral-ink); }
body.theme-dark .kpi-value-down { color: #ff8a8a; }

/* KPI modal content shapes — reuse the platform .modal-content shell
   and only add what's specific to the listing inside (lead paragraph,
   ordered list of monitors/incidents, big-figure for uptime). */
.kpi-modal-lead {
    margin: 0 0 16px;
    font-size: 14px;
    line-height: 1.55;
    color: var(--ink-2);
}
.kpi-modal-list {
    margin: 0;
    padding: 0;
    list-style: none;
    max-height: 360px;
    overflow-y: auto;
    border-top: 1px solid var(--line);
}
.kpi-modal-list li {
    padding: 10px 0;
    border-bottom: 1px solid var(--line);
    font-size: 13.5px;
    line-height: 1.45;
}
.kpi-modal-list li a {
    color: var(--ink);
    font-weight: 500;
    text-decoration: none;
}
.kpi-modal-list li a:hover { text-decoration: underline; }
.kpi-modal-meta {
    color: var(--ink-3);
    font-size: 12.5px;
}
.kpi-modal-empty {
    margin: 16px 0 0;
    padding: 16px;
    background: var(--paper-2);
    border-radius: var(--radius-sm);
    font-size: 13px;
    color: var(--ink-4);
    text-align: center;
}
.kpi-modal-figure {
    margin: 16px 0;
    padding: 24px;
    background: var(--paper-2);
    border-radius: var(--radius-md);
    text-align: center;
    font-family: var(--font-mono);
    font-size: 40px;
    font-weight: 600;
    color: var(--ink);
}
.kpi-modal-note {
    margin: 0;
    font-size: 12.5px;
    color: var(--ink-4);
    line-height: 1.5;
}

/* Split-row variant — left side (name + meta), right side (URL link
   anchored to the right). Used by the Status pages KPI modal. */
.kpi-modal-list-split li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
}
.kpi-modal-row-left {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.kpi-modal-row-right {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-family: var(--font-mono);
    font-size: 12px;
    color: var(--ink-3);
    text-decoration: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 60%;
    flex-shrink: 0;
}
.kpi-modal-row-right:hover { color: var(--pulse); }

/* Configured-probes breakdown table — 1 row per MonitorType with
   active / inactive / total columns. */
.kpi-modal-table {
    width: 100%;
    border-collapse: collapse;
    margin-top: 8px;
    font-size: 13.5px;
}
.kpi-modal-table th,
.kpi-modal-table td {
    padding: 8px 12px;
    border-bottom: 1px solid var(--line);
    text-align: left;
}
.kpi-modal-table th {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-3);
}
.kpi-modal-num {
    text-align: right;
    font-family: var(--font-mono);
}

/* Grouped-by-type lists for Up / Degraded / Down modals. Each group
   has a small header showing the type label + count, followed by a
   compact list of "Page · Probe" entries. */
.kpi-modal-groups {
    margin: 0;
    max-height: 420px;
    overflow-y: auto;
}
.kpi-modal-group {
    margin-bottom: 14px;
}
.kpi-modal-group:last-child { margin-bottom: 0; }
.kpi-modal-group-title {
    margin: 0 0 4px;
    padding: 0 0 4px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-3);
    border-bottom: 1px solid var(--line);
}
.kpi-modal-list-compact { border-top: 0; }
.kpi-modal-list-compact li {
    padding: 6px 0;
    border-bottom: 0;
    display: flex;
    align-items: baseline;
    gap: 6px;
}
/* Probe-type chip on the right edge of each row. margin-left:auto pushes
   it past the page+probe-name on the left without needing space-between
   on the parent (which would also stretch the middle gap). Same visual
   weight as kpi-modal-meta so it doesn't compete with the probe name. */
.kpi-modal-row-type {
    margin-left: auto;
    padding-left: 12px;
    font-family: var(--font-mono);
    font-size: 11.5px;
    color: var(--ink-3);
    white-space: nowrap;
}

/* Active-incident detail — definition list inside each list item gives
   a labelled "card" look without a heavy border. Severity pill mirrors
   the public status-page incident-severity-pill colour scheme. */
.incident-modal-item {
    padding: 14px 0;
    border-bottom: 1px solid var(--line);
}
.incident-modal-item:last-child { border-bottom: 0; }
.incident-modal-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
}
.incident-modal-title {
    color: var(--ink);
    font-weight: 600;
    font-size: 14.5px;
    text-decoration: none;
}
.incident-modal-title:hover { text-decoration: underline; }
.incident-modal-meta {
    margin: 0;
    display: grid;
    grid-template-columns: 110px 1fr;
    row-gap: 4px;
    column-gap: 12px;
    font-size: 12.5px;
}
.incident-modal-meta dt {
    color: var(--ink-3);
    font-weight: 500;
}
.incident-modal-meta dd { margin: 0; color: var(--ink); }

.incident-sev-pill {
    display: inline-flex;
    align-items: center;
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}
.incident-sev-critical { background: var(--danger-soft); color: var(--danger); }
.incident-sev-major    { background: var(--coral-soft);  color: var(--coral-ink); }
.incident-sev-minor    { background: var(--pulse-soft);  color: var(--pulse-ink); }
.incident-sev-none     { background: var(--paper-2);    color: var(--ink-4); }
body.theme-dark .incident-sev-critical { color: #ff8a8a; background: rgba(239, 107, 107, 0.12); }
body.theme-dark .incident-sev-major    { color: var(--coral-ink); }
body.theme-dark .incident-sev-minor    { color: var(--pulse); }

/* KPI chart modal — window combobox at the top, SVG fills the wrap,
   meta line below states bucket size + point count. */
.kpi-chart-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
}
.kpi-chart-controls label {
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-3);
}
.kpi-chart-window {
    padding: 5px 10px;
    border: 1px solid var(--line-2);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: 13px;
}
body.theme-dark .kpi-chart-window { background: var(--paper-3); }
.kpi-chart-wrap {
    width: 100%;
    aspect-ratio: 1000 / 320;
    background: var(--paper-2);
    border-radius: var(--radius-sm);
    padding: 10px;
    overflow: hidden;
}
.kpi-chart-svg { width: 100%; height: 100%; display: block; }
.kpi-chart-line {
    fill: none;
    stroke: var(--pulse);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
.kpi-chart-dot { fill: var(--pulse); }
.kpi-chart-loading,
.kpi-chart-empty,
.kpi-chart-error {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--ink-3);
    font-size: 13px;
}
.kpi-chart-error { color: var(--danger); }
.kpi-chart-meta {
    margin: 10px 0 0;
    font-size: 12px;
    color: var(--ink-4);
    text-align: right;
}

/* Page grid — exactly two columns at desktop sizes (each card 50% of
   the available row width). Collapses to a single column on narrow
   viewports so cards still breathe. */
.page-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
}
@media (max-width: 720px) {
    .page-grid { grid-template-columns: 1fr; }
}
.page-card {
    display: block;
    padding: 18px 20px;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s, box-shadow 0.15s, transform 0.15s;
}
.page-card:hover {
    border-color: var(--pulse);
    box-shadow: 0 1px 6px rgba(14, 26, 22, 0.06);
    transform: translateY(-1px);
}
body.theme-dark .page-card { background: var(--paper-2); }
body.theme-dark .page-card:hover {
    border-color: var(--pulse);
    box-shadow: 0 1px 8px rgba(0, 0, 0, 0.2);
}

.page-card-header {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 8px 12px;
    margin-bottom: 14px;
}
.page-card-title {
    margin: 0;
    font-size: 17px;
    font-weight: 600;
    color: var(--ink);
    line-height: 1.2;
}
.page-card-incident {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 500;
    color: var(--danger);
    background: var(--danger-soft);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}
body.theme-dark .page-card-incident { color: #ff8a8a; background: rgba(239, 107, 107, 0.12); }

.page-card-empty {
    margin: 0;
    font-size: 13px;
    color: var(--ink-4);
    font-style: italic;
}

/* Probe badge groups — one section per MonitorType inside a page card,
   small uppercase label above the badge grid. The grid itself is the
   same shape as before so badges still stretch to equal widths within
   a group. */
.probe-badge-groups {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.probe-badge-group-label {
    margin: 0 0 4px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink-3);
}

/* Probe badges — auto-fill grid with a fixed minimum so every badge on
   the row is exactly the same width. Wraps onto subsequent rows when
   the card runs out of horizontal space; each row's badges stay the
   same width as the row above thanks to the 1fr stretch. */
.probe-badges {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 6px;
}
.probe-badge {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px 10px;
    font-size: 12px;
    font-weight: 500;
    border-radius: 999px;
    border: 1px solid transparent;
    line-height: 1.45;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Badge is an <a> on the main dashboard so each one navigates to the
       probe detail. Suppress the default anchor styling — the badge's own
       palette already encodes state via its variant class. */
    text-decoration: none;
    cursor: pointer;
    transition: filter 0.12s, transform 0.12s;
}
.probe-badge:hover {
    filter: brightness(0.96);
    transform: translateY(-1px);
}

.page-card-title-link {
    color: inherit;
    text-decoration: none;
}
.page-card-title-link:hover {
    color: var(--pulse-ink);
}
.probe-badge-ok      { background: var(--pulse-soft);  color: var(--pulse-ink);  border-color: color-mix(in srgb, var(--pulse) 30%, transparent); }
.probe-badge-warn    { background: var(--coral-soft);  color: var(--coral-ink);  border-color: color-mix(in srgb, var(--coral) 30%, transparent); }
.probe-badge-down    { background: var(--danger-soft); color: var(--danger);     border-color: color-mix(in srgb, var(--danger) 30%, transparent); }
.probe-badge-paused  { background: var(--paper-2);    color: var(--ink-4);      border-color: var(--line-2); }
.probe-badge-unknown { background: var(--paper-2);    color: var(--ink-3);      border-color: var(--line-2); }

body.theme-dark .probe-badge-ok      { color: var(--pulse); }
body.theme-dark .probe-badge-warn    { color: var(--coral-ink); }
body.theme-dark .probe-badge-down    { color: #ff8a8a; }

