/* ===== Variables =====
 *
 * Theme-aware via the `data-theme` attribute on <html>. Three states:
 *   - dark   — Bowire brand dark (default for back-compat)
 *   - light  — on-brand light variant
 *   - auto   — follows the OS prefers-color-scheme media query
 *
 * The theme is driven by site/assets/js/main.js, which reads
 * localStorage['theme'] (same key the docfx site uses, so the choice
 * persists across the marketing → docs jump).
 *
 * The :root selector is kept as a default so a stale browser without
 * JS still sees the dark theme rather than unstyled garbage.
 */
:root,
:root[data-theme="dark"] {
    --bg: #0f0f17;
    --bg-elevated: #161621;
    --bg-footer: #08080d;
    --surface: #1a1a2e;
    --border: #2a2a3d;
    --text: #e8e8f0;
    --text-secondary: #9898b0;
    --accent: #6366f1;
    --accent-hover: #818cf8;
    /* Higher-contrast accent variant for inline links inside text
       blocks — --accent (#6366f1) on the elevated bg sits at ~4.4:1,
       just under WCAG AA. --accent-light hits ≥ 6:1 against both bg
       and bg-elevated in dark mode. */
    --accent-light: #a5b4fc;
    --success: #34d399;
    --warning: #fbbf24;
    --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', monospace;
    --radius: 8px;
    --radius-lg: 12px;
    --container: 1120px;
    --header-height: 64px;
}

:root[data-theme="light"] {
    --bg: #fafaff;
    --bg-elevated: #f4f4fa;
    --bg-footer: #eaeaf0;
    --surface: #eeeef0;
    --border: #e1e1ee;
    --text: #1a1a2e;
    --text-secondary: #5a5a72;
    /* Tailwind indigo-600 — slightly darker than the dark-mode accent so
       body links hit AA contrast on the near-white background. The
       brighter #6366f1 is still used for buttons and UI accents. */
    --accent: #4f46e5;
    --accent-hover: #6366f1;
    /* Darker accent for higher AA contrast against the near-white bg
       in light mode (mirrors --accent-light in dark mode but in the
       opposite direction). */
    --accent-light: #3730a3;
    --success: #059669;
    --warning: #d97706;
}

/* Auto mode: defer to the OS color scheme */
@media (prefers-color-scheme: light) {
    :root[data-theme="auto"] {
        --bg: #fafaff;
        --bg-elevated: #f4f4fa;
        --bg-footer: #eaeaf0;
        --surface: #eeeef0;
        --border: #e1e1ee;
        --text: #1a1a2e;
        --text-secondary: #5a5a72;
        --accent: #4f46e5;
        --accent-hover: #6366f1;
        --accent-light: #3730a3;
        --success: #059669;
        --warning: #d97706;
    }
}

/* ===== Reset ===== */
*, *::before, *::after {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
    /* Land section tops right at the viewport top — the section's own
       padding keeps the h2 below the translucent header, and the previous
       section's bg is pushed entirely out of view (no bleed through the
       blurred header). */
    scroll-padding-top: 0;
}

body {
    font-family: var(--font-sans);
    background: var(--bg);
    color: var(--text);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

a {
    color: var(--accent);
    text-decoration: none;
    transition: color 0.2s;
}

a:hover {
    color: var(--accent-hover);
}

code {
    font-family: var(--font-mono);
    font-size: 0.875em;
    background: var(--surface);
    padding: 0.15em 0.4em;
    border-radius: 4px;
    color: var(--accent-hover);
}
/* Block-level code (inside <pre>) doesn't want the inline pill
   styling — the surrounding <pre> already provides spacing and
   colour. The 0.4em left/right padding from the rule above showed
   up as a stray leading "space" in front of every command line. */
pre > code {
    padding: 0;
    background: none;
    color: inherit;
    border-radius: 0;
}

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

/* ===== Header ===== */
.site-header {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 100;
    height: var(--header-height);
    background: transparent;
    transition: background 0.3s, border-color 0.3s, backdrop-filter 0.3s;
    border-bottom: 1px solid transparent;
}

.site-header.scrolled {
    /* Hardcoded rgba values per theme — can't easily mix var(--bg) into
       an alpha channel. Light-mode fallback + auto-light media query keep
       the scrolled header translucent but on-theme. */
    background: rgba(15, 15, 23, 0.88);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom-color: var(--border);
}
:root[data-theme="light"] .site-header.scrolled {
    background: rgba(250, 250, 255, 0.85);
}
@media (prefers-color-scheme: light) {
    :root[data-theme="auto"] .site-header.scrolled {
        background: rgba(250, 250, 255, 0.85);
    }
}

.header-inner {
    /* Three zones: logo left, nav centred, actions right. The 1fr-auto-1fr
       grid lets the nav stay horizontally centred even when logo and actions
       have different widths. */
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 24px;
    height: 100%;
}

.header-actions {
    display: flex;
    align-items: center;
    /* Same gap as .bowire-docs-header-actions so the icon row doesn't
       shift horizontally when the user navigates site ↔ docs. */
    gap: 12px;
    justify-self: end;
}

.logo {
    /* Sits in the first 1fr column of the .header-inner grid —
       justify-self: start keeps the click target snug around the
       mark + wordmark instead of stretching across the entire 1fr
       cell (otherwise clicks on "empty" space in the left column
       still fire the link, which confuses the user). */
    display: inline-flex;
    justify-self: start;
    align-items: center;
    gap: 8px;
    font-weight: 700;
    font-size: 1.125rem;
    color: var(--text);
    transition: color 0.2s;
}

.logo:hover {
    color: var(--accent);
}

.logo-icon {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    /* Brand mark next to the site title — fill inherited via
       currentColor. Color inherits from the parent .logo so hover on
       the link tints both the text and the icon together. */
    transition: color 0.2s;
}

.header-nav {
    display: flex;
    align-items: center;
    gap: 28px;
    /* Baseline-align the 14px nav text with the 18px "Bowire" wordmark —
       centring two different font sizes in the same row lifts the smaller
       text a touch too high, so we nudge the nav down. */
    margin-top: 3px;
}

.header-nav a {
    color: var(--text-secondary);
    font-size: 0.875rem;
    font-weight: 500;
    transition: color 0.2s;
}

.header-nav a:hover {
    color: var(--accent);
}
/* Active section (current page) — distinct from hover so the user can
   tell "I am here" vs "I can go here". Lifts to emphasis colour +
   semibold while hover stays on accent. */
.header-nav a.active {
    color: var(--text);
    font-weight: 600;
}

.nav-home {
    display: inline-flex;
    align-items: center;
    color: var(--text-secondary);
    transition: color 0.2s;
}
.nav-home:hover {
    color: var(--accent);
}

.nav-github {
    display: flex;
    align-items: center;
    /* Match the monochrome header feel — inherits to the SVG via
       currentColor, otherwise the link picks up the global accent. */
    color: var(--text-secondary);
    transition: color 0.15s;
}
.nav-github:hover {
    /* Match the theme-toggle hover — both header icons tint to accent. */
    color: var(--accent);
}
.nav-github:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

.mobile-menu-toggle {
    display: none;
    background: none;
    border: none;
    color: var(--text);
    cursor: pointer;
    padding: 4px;
}

/* ===== Hero ===== */
.hero {
    position: relative;
    padding: 112px 0 72px;
    text-align: center;
    overflow: hidden;
}

.hero-glow {
    position: absolute;
    top: -200px;
    left: 50%;
    transform: translateX(-50%);
    width: 800px;
    height: 600px;
    background: radial-gradient(ellipse at center, rgba(99, 102, 241, 0.12) 0%, transparent 70%);
    pointer-events: none;
}

.hero-inner {
    position: relative;
    z-index: 1;
}

.hero-logo {
    display: block;
    /* Horizontal logo (~1.69:1 aspect) wants roughly double the old
       square footprint — sizing by width so the height stays
       proportional and scales naturally between small and wide
       viewports. Range widened to 200–340 px from the old 96–144 px.
       `color: var(--text)` (instead of --accent) flips the brand
       white on dark / black on light in step with the rest of the
       page — the drop-shadow keeps the indigo glow around it. */
    width: clamp(120px, 16vw, 195px);
    height: auto;
    margin: 0 auto 20px;
    color: var(--text);
    filter: drop-shadow(0 8px 24px rgba(99, 102, 241, 0.25));
}

.hero-title {
    font-size: clamp(3rem, 8vw, 5rem);
    font-weight: 800;
    letter-spacing: -0.03em;
    line-height: 1.1;
    margin-bottom: 20px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.hero-tagline {
    font-size: clamp(1.375rem, 3vw, 1.75rem);
    font-weight: 700;
    color: var(--text);
    max-width: 640px;
    margin: 0 auto 12px;
    line-height: 1.3;
    letter-spacing: -0.01em;
}

.hero-slogan {
    font-size: clamp(0.9375rem, 2vw, 1.0625rem);
    font-weight: 400;
    color: var(--text-secondary);
    /* Wide enough that line 1 — "Like Swashbuckle ... and more —" — fits
       in a single row at the desktop em-dash forced break. The <br> in
       the markup handles the actual line split; max-width just prevents
       a too-narrow column from causing extra natural wraps. On mobile
       (<640px) this column is naturally constrained by viewport width. */
    max-width: 880px;
    margin: 0 auto 28px;
    line-height: 1.6;
    font-style: italic;
}

.hero-actions {
    display: flex;
    gap: 16px;
    justify-content: center;
    margin-bottom: 20px;
}
.hero-actions .btn {
    /* Fixed width keeps the two CTAs visually identical regardless of
       content length — matches the CTA block's button pair. */
    width: 220px;
    justify-content: center;
}

.hero-badges {
    display: flex;
    gap: 8px;
    justify-content: center;
    flex-wrap: wrap;
    margin-bottom: 8px;
}

/* Native pill badges — match the rest of the site's surface cards rather
   than shields.io's generic README aesthetic. Values land via JS fetch. */
.hero-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 5px 12px 5px 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--text-secondary);
    font-family: var(--font-sans);
    text-decoration: none;
    transition: border-color 0.15s, color 0.15s, transform 0.15s, background 0.15s;
}
.hero-badge:hover {
    border-color: rgba(99, 102, 241, 0.5);
    background: var(--surface);
    color: var(--text);
    transform: translateY(-1px);
}
.hero-badge-icon {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    color: var(--text-secondary);
    transition: color 0.15s;
}
.hero-badge:hover .hero-badge-icon {
    color: var(--accent);
}
.hero-badge-label {
    color: var(--text-secondary);
    font-weight: 500;
    letter-spacing: 0.01em;
}
.hero-badge-value {
    color: var(--text);
    font-weight: 600;
    font-family: var(--font-mono);
    font-size: 0.8125em;
    font-variant-numeric: tabular-nums;
    padding-left: 8px;
    border-left: 1px solid var(--border);
    margin-left: 2px;
}
/* While loading — the em-dash placeholder gets a subtle pulse so the badge
   doesn't look broken while waiting for the API response. */
.hero-badge-value[data-badge-value]:empty {
    display: none;
}

.hero-install {
    max-width: 420px;
    margin: 0 auto;
}

/* ===== Hero terminal demo =====
   Animated reveal: each line fades in with a left-slide; step 6 ends with
   a blinking cursor so the frame feels "live". The 12 s loop cycles back
   to hidden, pauses, then replays — readers who stay on the hero see the
   demo repeat. prefers-reduced-motion shows everything at once. */
.hero-terminal {
    max-width: 720px;
    margin: 28px auto 0;
    text-align: left;
    background: #0b0b13;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: 0 20px 48px rgba(0, 0, 0, 0.45);
    overflow: hidden;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    line-height: 1.6;
    color: #e4e4ef;
}
:root[data-theme="light"] .hero-terminal {
    background: #1a1a2e;
    box-shadow: 0 20px 48px rgba(15, 15, 23, 0.2);
    color: #e4e4ef;
}
.hero-terminal-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: rgba(255, 255, 255, 0.04);
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.55);
}
.hero-terminal-dots {
    display: inline-flex;
    gap: 6px;
}
.hero-terminal-dots > span {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: #5a5a72;
}
.hero-terminal-dots > span:nth-child(1) { background: #ff5f57; }
.hero-terminal-dots > span:nth-child(2) { background: #febc2e; }
.hero-terminal-dots > span:nth-child(3) { background: #28c840; }
.hero-terminal-body {
    padding: 18px 20px 20px;
    min-height: 196px;
}
.hero-terminal-line {
    white-space: pre-wrap;
    word-break: break-word;
    opacity: 0;
    transform: translateX(-6px);
    animation: hero-term-in 0.45s ease-out forwards;
}
.hero-terminal-prompt {
    color: #6366f1;
    font-weight: 700;
    margin-right: 8px;
    user-select: none;
}
.hero-terminal-pkg {
    color: #a5b4fc;
}
.hero-terminal-url {
    color: #34d399;
    text-decoration: underline dotted;
    text-underline-offset: 3px;
}
.hero-terminal-out {
    color: rgba(228, 228, 239, 0.7);
}
.hero-terminal-success {
    color: #34d399;
}
.hero-terminal-cursor {
    display: inline-block;
    width: 8px;
    height: 1em;
    background: #e4e4ef;
    vertical-align: text-bottom;
    margin-left: 4px;
    animation: hero-term-cursor 1.1s steps(2) infinite;
}

/* Each step fades in at its own offset inside the 12 s loop. Staying at full
   opacity for the bulk of the cycle, then the whole frame fades back to zero
   briefly before the next pass. */
.hero-terminal-step-1 { animation-delay: 0.3s; }
.hero-terminal-step-2 { animation-delay: 1.8s; }
.hero-terminal-step-3 { animation-delay: 3.4s; }
.hero-terminal-step-4 { animation-delay: 4.7s; }
.hero-terminal-step-5 { animation-delay: 6.0s; }
.hero-terminal-step-6 { animation-delay: 7.3s; }

@keyframes hero-term-in {
    from { opacity: 0; transform: translateX(-6px); }
    to   { opacity: 1; transform: translateX(0); }
}
@keyframes hero-term-cursor {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
    .hero-terminal-line {
        animation: none;
        opacity: 1;
        transform: none;
    }
    .hero-terminal-cursor {
        animation: none;
    }
}

/* Fastlane text link below the terminal demo — same .features-detail-cta
   typography the rest of the landing uses, just with extra top margin
   so it breathes after the animated demo. */
.hero-fastlane-text {
    margin-top: 24px;
}

/* ===== Buttons ===== */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 12px 28px;
    border-radius: var(--radius);
    font-size: 0.9375rem;
    font-weight: 600;
    transition: all 0.2s;
    border: none;
    cursor: pointer;
}

.btn-primary {
    background: var(--accent);
    color: #fff;
}

.btn-primary:hover {
    background: var(--accent-hover);
    color: #fff;
    transform: translateY(-1px);
    box-shadow: 0 4px 20px rgba(99, 102, 241, 0.3);
}

.btn-secondary {
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.15s;
}

/* Match .hero-badge / .protocol-card / .feature-card hover signature so
   every interactive surface on the page shares the same "accent border
   + lift" affordance. */
.btn-secondary:hover {
    background: var(--bg-elevated);
    color: var(--text);
    border-color: rgba(99, 102, 241, 0.5);
    transform: translateY(-1px);
}
.btn-secondary:hover svg {
    color: var(--accent);
    transition: color 0.15s;
}

/* ===== Code Blocks ===== */
.code-block {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    text-align: left;
    /* Same depth as the feature-page screenshot <img> — so install
       snippets, download snippets, and feature demos all read with the
       same weight when they sit on the page. */
    box-shadow: 0 20px 48px rgba(0, 0, 0, 0.25);
}

.code-block-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 16px;
    border-bottom: 1px solid var(--border);
    background: var(--surface);
}
.code-block-header .copy-btn {
    margin-left: auto;
}

.code-block-lang {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
/* Right-aligned, normal-case hint — visually distinct from the
   uppercased language tag on the left so it doesn't read like a
   second title. */
.code-block-hint {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--text-secondary);
    opacity: 0.75;
    letter-spacing: 0;
}
.code-block-hint kbd {
    font-size: inherit;
}
/* When both .code-block-hint (margin-left: auto) and .copy-btn
   (also margin-left: auto) live in the header, keep the hint pushed
   all the way right and nudge the button after it. */
.code-block-header .code-block-hint + .copy-btn {
    margin-left: 8px;
}

.copy-btn {
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 4px;
    display: flex;
    align-items: center;
    border-radius: 4px;
    transition: color 0.2s, background 0.2s;
}

.copy-btn:hover {
    color: var(--text);
    background: rgba(255, 255, 255, 0.05);
}

.copy-btn.copied {
    color: var(--success);
}

.code-block pre {
    padding: 16px;
    overflow-x: auto;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    line-height: 1.6;
    color: var(--text);
}

.code-block pre code {
    background: none;
    padding: 0;
    font-size: inherit;
    color: inherit;
}

.code-block .c {
    color: var(--text-secondary);
}

/* ===== Section Shared ===== */
.section-title {
    font-size: clamp(1.75rem, 4vw, 2.25rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    text-align: center;
    margin-bottom: 12px;
}

.section-subtitle {
    text-align: center;
    color: var(--text-secondary);
    font-size: 1.0625rem;
    max-width: 760px;
    margin: 0 auto 56px;
}

/* ===== Screenshots ===== */
.screenshots {
    /* Top padding matches every other landing-page section so the
       "See it in action" headline lands at the same vertical offset
       as .usp / .protocols / .launch when a nav-anchor click
       scrolls here. */
    padding: 100px 0;
    background: var(--bg-elevated);
}

.screenshot-hero {
    margin: 32px auto 24px;
    max-width: 1200px;
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    overflow: hidden;
    background: var(--surface);
    box-shadow: 0 24px 80px rgba(0, 0, 0, 0.4),
                0 0 0 1px rgba(99, 102, 241, 0.15),
                0 0 80px rgba(99, 102, 241, 0.08);
    transition: transform 0.3s, box-shadow 0.3s, border-color 0.3s;
}

.screenshot-hero:hover {
    transform: translateY(-3px);
    box-shadow: 0 32px 100px rgba(0, 0, 0, 0.45),
                0 0 0 1px rgba(99, 102, 241, 0.25),
                0 0 100px rgba(99, 102, 241, 0.12);
    border-color: var(--accent);
}

.screenshot-hero a {
    display: block;
    line-height: 0;
}

.screenshot-hero img,
.screenshot-hero video.demo-video {
    width: 100%;
    height: auto;
    display: block;
}

.screenshot-hero video.demo-video {
    background: var(--bg);
}

/* Video hero as a button — click anywhere to go fullscreen. Hint overlay
   fades in on hover so the affordance is discoverable without crowding
   the demo when idle. */
.demo-video-expand {
    padding: 0;
    cursor: zoom-in;
    font: inherit;
    color: inherit;
    position: relative;
    display: block;
}
.demo-video-expand:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}
.demo-video-hint {
    position: absolute;
    top: 16px;
    right: 16px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(15, 15, 23, 0.75);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    color: #fff;
    font-size: 0.8125rem;
    font-weight: 500;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.15s, transform 0.15s;
    pointer-events: none;
}
.demo-video-expand:hover .demo-video-hint,
.demo-video-expand:focus-visible .demo-video-hint {
    opacity: 1;
    transform: translateY(0);
}

.screenshot-caption {
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    max-width: 720px;
    margin: 0 auto 64px;
}

.screenshot-grid-title {
    font-size: 1.5rem;
    font-weight: 700;
    text-align: center;
    margin-bottom: 12px;
    letter-spacing: -0.01em;
}

.screenshot-grid-subtitle {
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    max-width: 640px;
    margin: 0 auto 40px;
}

/* Legacy 2-column grid kept as a fallback for pages that still use it. */
.screenshot-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 24px;
    max-width: 1100px;
    margin: 0 auto;
}

/* ---- Carousel wrapper: holds prev/next buttons on the flanks + the
       scrolling strip in the middle. Keeps the buttons at the viewport
       edge so they don't cover the cards. ---- */
.screenshot-carousel-wrap {
    display: flex;
    align-items: stretch;
    gap: 8px;
    max-width: 1100px;
    margin: 0 auto;
}

.screenshot-nav-btn {
    flex: 0 0 40px;
    width: 40px;
    align-self: center;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.screenshot-nav-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}
.screenshot-nav-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* ---- Dot indicators row ---- */
.screenshot-dots {
    display: flex;
    justify-content: center;
    gap: 8px;
    margin-top: 20px;
    flex-wrap: wrap;
    max-width: 640px;
    margin-left: auto;
    margin-right: auto;
}
.screenshot-dot {
    position: relative;
    width: 8px;
    height: 8px;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: var(--border);
    cursor: pointer;
    transition: background 0.2s, transform 0.2s;
}
.screenshot-dot:hover {
    background: var(--text-secondary);
    transform: scale(1.2);
}
.screenshot-dot.active {
    background: var(--accent);
    transform: scale(1.3);
}
.screenshot-dot:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
/* Tooltip label above each dot — mirrors the section-nav dots on the
   right edge. Hidden by default, appears on hover / keyboard focus. */
.screenshot-dot-label {
    position: absolute;
    bottom: calc(100% + 10px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    white-space: nowrap;
    padding: 4px 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.8125rem;
    color: var(--text);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s, transform 0.15s;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}
.screenshot-dot:hover .screenshot-dot-label,
.screenshot-dot:focus-visible .screenshot-dot-label {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}

/* ---- Floating section-rail — wraps the scrollspy dots and (when the
   page outline modal is wired up) the Outline tools pill below them.
   Both pills sit on the same right-edge axis as separate flex children
   so each can grow/shrink independently while sharing the vertical
   centering. Mirrors the docs site .docs-rail pattern. */
.section-rail {
    position: fixed;
    right: 18px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    z-index: 90;
}
.section-rail[hidden] { display: none; }

/* Section-nav pill — sits inside the rail, no longer fixed-positioned
   itself. */
.section-nav {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 8px 6px;
    background: rgba(15, 15, 23, 0.55);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-radius: 999px;
    border: 1px solid var(--border);
}
:root[data-theme="light"] .section-nav,
:root[data-theme="light"] .section-tools {
    background: rgba(250, 250, 255, 0.7);
}
@media (prefers-color-scheme: light) {
    :root[data-theme="auto"] .section-nav,
    :root[data-theme="auto"] .section-tools {
        background: rgba(250, 250, 255, 0.7);
    }
}

/* Outline tools pill — currently single-button (Outline trigger), same
   pill chrome as the dot-nav so the two read as siblings on the rail. */
.section-tools {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 6px;
    background: rgba(15, 15, 23, 0.55);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border-radius: 999px;
    border: 1px solid var(--border);
}
.section-tools[hidden] { display: none; }
.section-tools-trigger {
    width: 24px;
    height: 24px;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    transition: color 0.15s, background 0.15s;
}
.section-tools-trigger:hover,
.section-tools-trigger:focus-visible,
.section-tools-trigger[aria-expanded="true"] {
    color: var(--accent);
    background: rgba(99, 102, 241, 0.12);
    outline: none;
}

.section-nav-dot {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    cursor: pointer;
    background: transparent;
    border: none;
    padding: 0;
}
.section-nav-dot::before {
    content: '';
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--text-secondary);
    opacity: 0.4;
    transition: opacity 0.15s, transform 0.15s, background 0.15s;
}
.section-nav-dot:hover::before,
.section-nav-dot:focus-visible::before {
    opacity: 0.85;
    transform: scale(1.25);
}
.section-nav-dot.is-active::before {
    background: var(--accent);
    opacity: 1;
    transform: scale(1.35);
}
.section-nav-dot:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Tooltip-style label to the left of each dot. */
.section-nav-dot-label {
    position: absolute;
    right: calc(100% + 8px);
    top: 50%;
    transform: translateY(-50%) translateX(4px);
    white-space: nowrap;
    padding: 4px 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    font-size: 0.8125rem;
    color: var(--text);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s, transform 0.15s;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}
.section-nav-dot:hover .section-nav-dot-label,
.section-nav-dot:focus-visible .section-nav-dot-label {
    opacity: 1;
    transform: translateY(-50%) translateX(0);
}

/* Gap marker — inserted between two non-adjacent picked dots when the
   page has more sections than the pill can show (sampled mode). Two
   stacked micro-dots in the same dot-language as the surrounding pill
   so the strip reads as "… some entries hidden here", without adding
   clickable noise. Mirrors the docs site pattern. */
.section-nav-gap {
    width: 24px;
    height: 10px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    pointer-events: none;
}
.section-nav-gap::before,
.section-nav-gap::after {
    content: '';
    width: 2px;
    height: 2px;
    border-radius: 50%;
    background: var(--text-secondary);
    opacity: 0.35;
}

@media (max-width: 768px) {
    /* Hide the floating section-rail on phones again. The scrollspy
       dots overlapped article text on the right edge (no fixed gutter
       to retreat into on mobile), and the outline ≡ trigger duplicated
       the burger menu icon in the header — same glyph, same idea, two
       buttons. The header burger plus an article's anchor links cover
       this functionality already. */
    .section-rail { display: none; }
}

/* ---- Page outline modal — opened from the .section-tools-trigger pill
   below the dot-nav. Same modal idiom as the docs Outline overlay
   (translucent backdrop, centred panel, three-band layout: tertiary
   header capsule, secondary list area, tertiary footer hint). Lists
   every section on the page (full, not sampled) so it complements
   the dot-nav by always exposing every entry. */
.bowire-page-overlay {
    position: fixed;
    inset: 0;
    z-index: 1100;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: min(12vh, 120px);
    background: rgba(15, 15, 23, 0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
}
:root[data-theme="light"] .bowire-page-overlay {
    background: rgba(200, 200, 220, 0.55);
}
@media (prefers-color-scheme: light) {
    :root[data-theme="auto"] .bowire-page-overlay {
        background: rgba(200, 200, 220, 0.55);
    }
}
.bowire-page-overlay.is-open {
    opacity: 1;
    pointer-events: auto;
}
.bowire-page-overlay-panel {
    width: min(560px, calc(100% - 48px));
    max-height: 80vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
    transform: translateY(-8px);
    transition: transform 0.2s ease;
}
.bowire-page-overlay.is-open .bowire-page-overlay-panel {
    transform: translateY(0);
}
.bowire-page-overlay-title {
    flex-shrink: 0;
    font-size: 0.85em;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-secondary);
    margin: 0;
    font-weight: 600;
    padding: 16px 20px;
    background: var(--bg-elevated);
    border-bottom: 1px solid var(--border);
}
.bowire-page-overlay nav.page-outline {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
    background: var(--surface);
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
    margin: 0;
    padding: 16px 20px;
    display: flex;
    flex-direction: column;
}
.bowire-page-overlay nav.page-outline::-webkit-scrollbar { width: 6px; }
.bowire-page-overlay nav.page-outline::-webkit-scrollbar-track { background: transparent; }
.bowire-page-overlay nav.page-outline::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 3px;
}
.bowire-page-overlay nav.page-outline a {
    color: var(--text);
    text-decoration: none;
    font-size: 13.5px;
    display: block;
    padding: 6px 10px;
    margin: 1px 0;
    border-radius: 4px;
    line-height: 1.45;
    transition: color 0.15s, background 0.15s;
}
.bowire-page-overlay nav.page-outline a:hover,
.bowire-page-overlay nav.page-outline a:focus-visible {
    color: var(--accent);
    background: var(--bg-elevated);
    outline: none;
}
.bowire-page-overlay nav.page-outline a.is-active {
    color: var(--accent);
    font-weight: 600;
    background: var(--bg-elevated);
}
/* Keyboard / hover cursor — separate from the active "you are here"
   marker so both can coexist. Matches the search overlay's
   .pagefind-ui__result.is-highlighted treatment for one consistent
   selection idiom. */
.bowire-page-overlay nav.page-outline a.is-highlighted {
    color: var(--accent);
    background: rgba(99, 102, 241, 0.08);
}
.bowire-page-overlay-hint {
    flex: 0 0 auto;
    padding: 14px 20px;
    border-top: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-size: 0.75rem;
    text-align: center;
}
.bowire-page-overlay-hint kbd {
    display: inline-block;
    min-width: 20px;
    padding: 1px 5px;
    margin: 0 2px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-bottom-width: 2px;
    border-radius: 4px;
    font-family: var(--font-sans);
    font-size: 0.6875rem;
    color: var(--text);
    line-height: 1.4;
}


/* ---- Horizontal carousel — auto-scroll with hover / focus pause ---- */
.screenshot-carousel {
    position: relative;
    overflow-x: auto;
    overflow-y: hidden;
    max-width: 100%;
    /* Soft edge-fade so cards scroll out under a gradient instead of
       hitting a hard clip — reads like a continuous film strip.
       Kept narrow (20px) so it hints at "more cards coming" without
       swallowing a meaningful slice of the last visible card. */
    mask-image: linear-gradient(90deg, transparent 0, #000 20px, #000 calc(100% - 20px), transparent 100%);
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 20px, #000 calc(100% - 20px), transparent 100%);
    /* scroll-snap-type was x-mandatory, but that cancelled every 1-pixel
       auto-drift step ("snap back to the nearest card"). Using none here
       lets the JS drift accumulate and also keeps programmatic scrollTo
       smoothly animated without getting clamped to snap points. */
    scroll-snap-type: none;
    /* Hide the native scrollbar — it breaks the clean film-strip look.
       Manual horizontal scroll still works via mouse-wheel-with-shift,
       trackpad / touch gestures, or keyboard arrows (tabindex on the
       section makes it focusable). */
    scrollbar-width: none;
    -ms-overflow-style: none;
}
.screenshot-carousel::-webkit-scrollbar {
    display: none;
}

.screenshot-carousel-track {
    display: flex;
    gap: 20px;
    /* Horizontal padding is set dynamically by main.js so the first and
       last cards can be centred inside the viewport — it depends on the
       actual carousel width, which CSS calc can't reliably observe. */
    padding: 6px 0 16px;
    width: max-content;
}
/* The drift used to be a CSS keyframe animation, but that made pausing /
   resuming painful — every resume snapped to animation-start. The JS
   controller in main.js now increments carousel.scrollLeft directly,
   which preserves position across pause/resume cycles. */

.screenshot-card {
    display: block;
    flex: 0 0 340px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    text-decoration: none;
    color: inherit;
    /* snap-align left here for completeness even though scroll-snap-type is
       currently 'none' — lets us re-enable proximity snap later with one flip. */
    scroll-snap-align: center;
    transition: border-color 0.2s, transform 0.2s, box-shadow 0.2s;
}

.screenshot-card:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.3);
}

.screenshot-card img {
    width: 100%;
    height: 192px;
    object-fit: cover;
    object-position: top left;
    display: block;
    border-bottom: 1px solid var(--border);
    background: var(--bg-elevated);
}

.screenshot-card kbd {
    font-family: var(--font-mono);
    font-size: 0.85em;
    padding: 1px 5px;
    background: rgba(255,255,255,0.06);
    border: 1px solid var(--border);
    border-radius: 3px;
}

.screenshot-card-body {
    padding: 18px 20px 22px;
}

.screenshot-card-body h4 {
    font-size: 1rem;
    font-weight: 600;
    margin-bottom: 6px;
    color: var(--text);
}

.screenshot-card-body p {
    font-size: 0.875rem;
    color: var(--text-secondary);
    line-height: 1.55;
    margin: 0;
}

/* "More details →" affordance — the whole card is already a link, but the
   pseudo element makes it obvious *that* it is. Nudges forward on hover to
   telegraph the click target. */
.screenshot-card-body::after {
    content: 'More details →';
    display: inline-block;
    margin-top: 12px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--accent);
    letter-spacing: 0.01em;
    transition: transform 0.2s, color 0.2s;
}
.screenshot-card:hover .screenshot-card-body::after {
    color: var(--accent-hover);
    transform: translateX(3px);
}

/* ===== Features ===== */
.features {
    padding: 100px 0;
}

/* When features are nested under "Why Bowire?", this heading introduces
   the whole feature block as a sub-answer. Smaller than a section-title
   because it's a sub-section inside the parent USP section. */
.features-heading {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    text-align: center;
    color: var(--text);
    margin: 80px 0 8px;
}
.features-subheading {
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    max-width: 780px;
    margin: 0 auto 32px;
}

.feature-group {
    margin-top: 40px;
}
.feature-group:first-of-type {
    margin-top: 16px;
}

.feature-group-title {
    font-size: 1.125rem;
    font-weight: 600;
    letter-spacing: -0.01em;
    text-align: center;
    color: var(--text);
    margin: 0 0 20px;
    /* Thin accent rule on either side of the heading so groups read as
       separate sub-sections without adding a full-width divider. */
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
}
.feature-group-title::before,
.feature-group-title::after {
    content: '';
    flex: 0 0 48px;
    height: 1px;
    background: var(--border);
}

.feature-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
}

.feature-card {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 32px 28px;
    transition: border-color 0.2s, transform 0.2s;
}

.feature-card:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
}

.feature-icon {
    margin-bottom: 16px;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(99, 102, 241, 0.08);
    border-radius: var(--radius);
}

.feature-card h3,
.feature-card h5 {
    font-size: 1.0625rem;
    font-weight: 600;
    margin: 0 0 8px;
}

.feature-card p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
}

/* ===== USP Section ===== */
.usp {
    padding: 100px 0 80px;
    /* Elevated background gives the "Why Bowire?" block a visual
       break from the .launch section above (which sits on the
       base bg). Without the contrast launch and the USP grid
       blur into one long stretch of base-coloured page. */
    background: var(--bg-elevated);
}

.usp-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 24px;
}

.usp-hero-card {
    grid-column: 1 / -1;
    text-align: center;
    background: linear-gradient(135deg, rgba(99,102,241,0.08), rgba(99,102,241,0.02));
    border-color: var(--accent) !important;
}

/* Protocol badges inside the hero card — neater than a comma-separated
   sentence that wraps in unpredictable places. Tight max-width forces a
   balanced two-row layout (roughly 5+5) so MCP never ends up alone on
   its own line. Still wraps further on narrower viewports. */
.usp-protocol-badges {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px;
    list-style: none;
    padding: 0;
    margin: 16px auto 20px;
    max-width: 520px;
}
.usp-protocol-badges li {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 500;
    padding: 4px 10px 4px 8px;
    border-radius: 999px;
    background: rgba(99, 102, 241, 0.12);
    border: 1px solid rgba(99, 102, 241, 0.28);
    color: var(--text);
    white-space: nowrap;
}
.usp-protocol-badges li svg {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    color: var(--accent);
}
.usp-protocol-badges-custom svg {
    color: var(--text-secondary) !important;
}
/* "+ Custom" chip — dashed border signals "slot for your own plugin"
   and sets it apart visually from the built-in protocols. */
.usp-protocol-badges-custom {
    background: transparent !important;
    border-style: dashed !important;
    color: var(--text-secondary) !important;
    cursor: help;
}

/* Closing tile at the bottom of the USP grid — sister to the 10+ hero
   card at the top, but with a license-badge hit instead of a number. */
.usp-closer-card {
    background: linear-gradient(135deg, rgba(52, 211, 153, 0.08), rgba(52, 211, 153, 0.02));
    border-color: var(--success) !important;
}
.usp-closer-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    padding: 6px 14px;
    border-radius: 999px;
    background: var(--success);
    color: #0a0f1c;
    margin-bottom: 14px;
}
.usp-closer-card .usp-vs {
    justify-content: center;
}
.usp-closer-cta {
    text-align: center;
    margin: 28px 0 0;
    font-size: 0.875rem;
    color: var(--text-secondary);
}
.usp-closer-cta a {
    color: var(--accent);
    text-decoration: none;
    font-weight: 600;
}
.usp-closer-cta a:hover {
    text-decoration: underline;
}

.usp-number {
    font-size: 4rem;
    font-weight: 800;
    color: var(--accent);
    line-height: 1;
    margin-bottom: 4px;
}

.usp-card {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 28px 24px;
    transition: border-color 0.2s, transform 0.2s;
}

/* `.usp-card-link` is the shared "this card is clickable" surface;
   it works for both <a> targets (10+ hero card → anchor, Apache 2.0
   closer card → external) and <div data-feature-modal> triggers
   (the popup-driven cards in between). */
.usp-card-link {
    display: block;
    color: inherit;
    text-decoration: none;
}
.usp-card-link[data-feature-modal] {
    cursor: pointer;
}
.usp-card-link h3 {
    transition: color 0.2s;
}
.usp-card-link:hover h3,
.usp-card-link:focus-visible h3 {
    color: var(--accent);
}
.usp-card-link[data-feature-modal]:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.usp-card:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
}

.usp-icon {
    margin-bottom: 14px;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(99, 102, 241, 0.08);
    border-radius: var(--radius);
}

.usp-card h3 {
    font-size: 1.0625rem;
    font-weight: 600;
    margin-bottom: 8px;
}

.usp-card p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
    margin: 0 0 10px;
}
.usp-card p:last-of-type {
    margin-bottom: 0;
}

.usp-vs {
    margin-top: 14px;
    font-size: 0.8125rem;
    color: var(--text-secondary);
    line-height: 1.6;
}
.usp-vs-label {
    font-weight: 600;
    color: var(--text);
}
.usp-vs-sep {
    margin: 0 6px;
    opacity: 0.4;
}

.usp-card kbd {
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    padding: 1px 6px;
    background: rgba(255,255,255,0.06);
    border: 1px solid var(--border);
    border-radius: 4px;
}

@media (max-width: 900px) {
    .usp-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
    .usp-grid { grid-template-columns: 1fr; }
    .usp-number { font-size: 3rem; }
}

/* ===== Protocols ===== */
.protocols {
    padding: 100px 0;
    /* Base bg so the zigzag from .usp (elevated) above flips here.
       Pattern across the landing page: E-B-E-B-E-B-E-B-E starting
       from .screenshots, gives every section heading a clear visual
       break from its neighbour. */
    background: var(--bg);
}

.protocol-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
}

.protocol-card {
    /* Grid layout so the icon sits next to the title only — description
       text + install command run full card-width below instead of being
       indented under a reserved icon column. `display: contents` on
       .protocol-content lets its children become direct grid items of
       this card. */
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 14px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 22px 22px 18px;
    transition: border-color 0.2s, transform 0.2s;
    /* Cards render as <a> tags — strip link underlines + keep text
       colour inheriting from the surrounding section. */
    color: inherit;
    text-decoration: none;
}

.protocol-card:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
}
.protocol-card:hover h3 {
    color: var(--accent);
    transition: color 0.2s;
}

.protocol-icon {
    /* In the card's grid: row 1, column 1 (next to the h3). The
       description text + install command run full-width below. */
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface);
    border-radius: var(--radius);
}
.protocol-icon svg {
    width: 22px;
    height: 22px;
}

/* `display: contents` so the children (h3, p, .protocol-install)
   become direct grid items of .protocol-card, not nested in their
   own block. The icon next to h3, description + install row span
   the full grid width below. */
.protocol-content {
    display: contents;
}
.protocol-content h3 {
    grid-column: 2;
    grid-row: 1;
    align-self: center;
    font-size: 1.0625rem;
    font-weight: 600;
    margin: 0;
}

.protocol-content p {
    grid-column: 1 / -1;
    grid-row: 2;
    color: var(--text-secondary);
    font-size: 0.875rem;
    line-height: 1.5;
    margin: 12px 0;
}

.protocol-tag {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--accent);
    background: rgba(99, 102, 241, 0.1);
    padding: 4px 10px;
    border-radius: 4px;
}

.protocol-tag-dim {
    color: var(--text-secondary);
    background: var(--surface);
}

/* Terminal-style install snippet replaces the old protocol-tag — the actual
   command reads as a hint AND a one-click copy, which is more useful than a
   bare package name. Sized so card heights stay comparable to the old design. */
.protocol-install {
    /* Spans full card width, sits at the bottom of the grid so
       install commands align across all cards in a row regardless
       of description length. */
    grid-column: 1 / -1;
    grid-row: 3;
    align-self: end;
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 6px 10px;
    font-family: var(--font-mono);
    font-size: 0.78rem;
    color: var(--text);
    max-width: 100%;
    /* Long package names — allow horizontal scroll in the code region without
       pushing the copy button off-screen. */
    min-width: 0;
}
.protocol-install code {
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    white-space: nowrap;
    background: transparent;
    padding: 0;
    color: var(--text);
    /* Hide the scrollbar chrome on webkit — the overflow is there for very
       narrow cards but we don't want it to dominate visually. */
    scrollbar-width: none;
}
.protocol-install code::-webkit-scrollbar { display: none; }
.protocol-install-prompt {
    color: var(--accent);
    font-weight: 700;
    margin-right: 4px;
    user-select: none;
}
.protocol-install-copy {
    flex-shrink: 0;
    background: transparent;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 4px;
    border-radius: 4px;
    transition: color 0.15s, background 0.15s;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.protocol-install-copy:hover {
    color: var(--accent);
    background: rgba(99, 102, 241, 0.1);
}
.protocol-install-copy.copied {
    color: var(--success);
}
.protocol-install-dim {
    border-style: dashed;
    color: var(--text-secondary);
}
.protocol-install-dim code {
    color: var(--text-secondary);
    white-space: normal;
}

.protocol-card-custom {
    border-style: dashed;
}

/* "Coming soon" card — pairs visually with the Custom card (both dashed,
   both at the end of the grid). Clickable link anchoring to #roadmap so
   the reader can jump straight to the full list. */
.protocol-card-coming {
    border-style: dashed;
    text-decoration: none;
    color: inherit;
}
.protocol-card-coming:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
    color: inherit;
}
.protocol-card-coming h3 {
    color: var(--text);
    /* Pin the Coming-soon h3 to the start of column 2 so the title
       reads left-aligned next to the icon, matching every other
       protocol card. Without this, the h3's column was effectively
       stretched and short text 'Coming soon' rendered centred-looking
       in some browsers — visibly out of pattern with the siblings. */
    justify-self: start;
    text-align: left;
}
.protocol-coming-link {
    color: var(--accent);
    font-weight: 600;
}

/* ===== Install — Tabs ===== */
.install {
    padding: 100px 0;
}

/* Tab bar — centered above the single wide panel */
.install-tabs {
    display: flex;
    gap: 4px;
    justify-content: center;
    margin-bottom: 24px;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    width: fit-content;
    margin-left: auto;
    margin-right: auto;
}

.install-tab {
    padding: 10px 24px;
    background: transparent;
    border: none;
    border-radius: var(--radius);
    color: var(--text-secondary);
    font-size: 0.9375rem;
    font-weight: 600;
    cursor: pointer;
    transition: color 0.15s, background 0.15s;
}

.install-tab:hover {
    color: var(--text);
}

.install-tab.active {
    background: var(--accent);
    color: #fff;
}

/* Panels — single full-width card holds the active panel's code blocks */
.install-panels {
    max-width: 920px;
    margin: 0 auto;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 32px;
    min-width: 0;
}

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

.install-desc {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    margin: 0 0 20px;
}

.install-panel .code-block {
    margin-bottom: 16px;
}

.install-panel .code-block:last-child {
    margin-bottom: 0;
}

/* ===== Use Cases ===== */
.use-cases {
    padding: 100px 0;
    /* Elevated bg keeps the landing-page zigzag pattern going —
       protocols (B) above, comparison (B) below, this section sits
       on the elevated tier in between. */
    background: var(--bg-elevated);
}

.use-case-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 24px;
    max-width: 1100px;
    margin: 0 auto;
}

.use-case-card {
    display: block;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 32px 28px;
    transition: border-color 0.2s, transform 0.2s;
    color: inherit;
    text-decoration: none;
}

.use-case-card:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
}
.use-case-card:hover h3 {
    color: var(--accent);
    transition: color 0.2s;
}

.use-case-icon {
    margin-bottom: 16px;
    width: 48px;
    height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(99, 102, 241, 0.08);
    border-radius: var(--radius);
}

.use-case-card h3 {
    font-size: 1.125rem;
    font-weight: 600;
    margin-bottom: 4px;
}

.use-case-tag {
    color: var(--accent);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 12px;
    font-family: var(--font-mono);
}

.use-case-card p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
    margin-bottom: 12px;
}

.use-case-tools {
    color: var(--text-secondary);
    font-size: 0.8125rem;
    font-style: italic;
    border-top: 1px solid var(--border);
    padding-top: 12px;
    margin-top: 4px;
    margin-bottom: 0;
}

/* ===== Comparison ===== */
.comparison {
    padding: 100px 0;
    /* Base bg so the zigzag from .use-cases (elevated) above flips
       here, then .roadmap (elevated) below picks the elevated tier
       back up — every section heading breaks clearly from its
       neighbours. */
    background: var(--bg);
}

/* Positioning strip above the matrix — each tool's "best for" in one glance.
   Bowire card is the static highlight; competitor cards are buttons that
   toggle an inline detail panel below the strip. */
.comparison-bestfor-strip {
    list-style: none;
    padding: 0;
    margin: 0 auto 12px;
    max-width: 1100px;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: stretch;
    gap: 10px;
}
.comparison-bestfor-strip > * {
    flex: 1 1 130px;
    min-width: 0;
    align-self: stretch;
}

/* "vs." divider between Bowire and the competitor cards. Small italic
   label that reads as "Bowire vs. [pick one]" and signals that the user
   is selecting which alternative to weigh against Bowire. */
.comparison-bestfor-strip > .comparison-bestfor-vs {
    flex: 0 0 auto;
    min-width: 0;
    align-self: center;
    padding: 0 6px;
    color: var(--text-secondary);
    font-size: 0.9rem;
    font-weight: 700;
    font-style: italic;
    letter-spacing: 0.02em;
}
@media (max-width: 640px) {
    /* On phones the flex-wrap strip turned into a 7-cell grid where
       the implicit "vs." between Bowire and the competitors got lost
       — readers couldn't tell the section was a comparison. Re-layout
       as: Bowire card on its own row, an explicit horizontal "vs."
       divider, then the five competitor cards in a 2-column grid. */
    .comparison-bestfor-strip {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 10px;
    }
    .comparison-bestfor-strip > .comparison-bestfor-card-bowire {
        grid-column: 1 / -1;
    }
    .comparison-bestfor-strip > .comparison-bestfor-vs {
        grid-column: 1 / -1;
        align-self: stretch;
        text-align: center;
        padding: 6px 0;
        font-size: 0.95rem;
        position: relative;
    }
    .comparison-bestfor-strip > .comparison-bestfor-vs::before,
    .comparison-bestfor-strip > .comparison-bestfor-vs::after {
        content: "";
        position: absolute;
        top: 50%;
        width: 64px;
        height: 1px;
        background: var(--border);
    }
    .comparison-bestfor-strip > .comparison-bestfor-vs::before {
        right: calc(50% + 28px);
    }
    .comparison-bestfor-strip > .comparison-bestfor-vs::after {
        left: calc(50% + 28px);
    }
}
.comparison-bestfor-card {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 4px;
    width: 100%;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 14px 12px 12px;
    text-align: center;
    transition: border-color 0.2s, transform 0.2s, background 0.2s;
    font: inherit;
    color: inherit;
}
button.comparison-bestfor-card {
    cursor: pointer;
}
button.comparison-bestfor-card:hover {
    border-color: rgba(99, 102, 241, 0.5);
    transform: translateY(-1px);
    background: var(--bg-elevated);
}
button.comparison-bestfor-card.active {
    /* Same fill-pattern as Bowire's highlight, but in the warning / amber
       accent — visually: "this is the alternative you selected to weigh
       against Bowire". Different colour keeps Bowire as the indigo hero
       and the chosen competitor as a clearly distinct second focus. */
    background:
        linear-gradient(180deg,
            rgba(251, 191, 36, 0.22) 0%,
            rgba(251, 191, 36, 0.08) 100%);
    border-color: rgba(251, 191, 36, 0.55);
    box-shadow: 0 8px 24px -8px rgba(251, 191, 36, 0.35);
    transform: none;
}
button.comparison-bestfor-card:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.comparison-bestfor-card-bowire {
    background:
        linear-gradient(180deg,
            rgba(99, 102, 241, 0.2) 0%,
            rgba(99, 102, 241, 0.08) 100%);
    border-color: rgba(99, 102, 241, 0.5);
    box-shadow: 0 8px 24px -8px rgba(99, 102, 241, 0.35);
}
.comparison-bestfor-name {
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--text);
    letter-spacing: -0.01em;
}
.comparison-bestfor-card-bowire .comparison-bestfor-name {
    color: var(--accent);
}
button.comparison-bestfor-card.active .comparison-bestfor-name {
    /* Name in warning colour when selected — mirrors how Bowire's name
       renders in accent colour, but in the opposite palette. */
    color: var(--warning);
}
.comparison-bestfor-tag {
    font-size: 0.75rem;
    color: var(--text-secondary);
    line-height: 1.35;
}

/* Small "Shell tools…" footnote directly under the strip. */
.comparison-bestfor-footnote {
    max-width: 1100px;
    margin: 0 auto 20px;
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.8125rem;
    font-style: italic;
}

/* Detail panel — inline expansion below the strip, only visible when a
   competitor card is active. */
.comparison-bestfor-panels {
    max-width: 900px;
    margin: 0 auto 28px;
}
.comparison-bestfor-panel {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    /* Left edge in warning colour so the panel ties visually to the
       active (warning-coloured) competitor card above. */
    border-left: 3px solid var(--warning);
    border-radius: var(--radius-lg);
    padding: 24px 28px;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.65;
}

/* Default empty-state placeholder — dashed, muted, centred CTA that asks
   the reader to pick a competitor card. Replaces the invisible void that
   used to sit above the feature matrix when no card was selected. */
.comparison-bestfor-placeholder {
    background: var(--bg-elevated);
    border: 1px dashed var(--border);
    border-radius: var(--radius-lg);
    padding: 20px 28px;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.55;
    text-align: center;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
}
.comparison-bestfor-placeholder[hidden] {
    display: none;
}
.comparison-bestfor-placeholder-arrow {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    color: var(--accent);
    opacity: 0.7;
}
.comparison-bestfor-placeholder p {
    margin: 0;
}
.comparison-bestfor-placeholder strong {
    color: var(--text);
    font-weight: 600;
}
.comparison-bestfor-panel-title strong,
.comparison-bestfor-panel p strong {
    color: var(--text);
    font-weight: 700;
}
.comparison-bestfor-panel[hidden] {
    display: none;
}
.comparison-bestfor-panel-title {
    font-size: 1rem;
    font-weight: 700;
    margin: 0 0 10px;
    color: var(--text);
}
.comparison-bestfor-panel p {
    margin: 0;
}
.comparison-bestfor-panel p + p {
    margin-top: 10px;
}
.comparison-bestfor-panel code {
    font-size: 0.85em;
}

@media (max-width: 960px) {
    .comparison-bestfor-strip {
        grid-template-columns: repeat(4, 1fr);
    }
}
@media (max-width: 640px) {
    .comparison-bestfor-strip {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* Sub-heading + description that introduces the feature matrix below the
   positioning strip — makes the transition from "quick read" to "detail
   check" explicit. */
.comparison-matrix-intro {
    text-align: center;
    max-width: 720px;
    margin: 48px auto 24px;
}
.comparison-matrix-heading {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
    margin: 0 0 8px;
}
.comparison-matrix-desc {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
    margin: 0;
}

/* Legend for the three-state circles. Sits above the table so readers see
   the symbol language before scanning the matrix. */
.comparison-legend {
    list-style: none;
    padding: 0;
    margin: 0 auto 18px;
    max-width: 1100px;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 20px;
    font-size: 0.82rem;
    color: var(--text-secondary);
}
.comparison-legend li {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.comparison-legend-marker {
    display: inline-block;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid transparent;
    box-sizing: border-box;
    flex-shrink: 0;
}
.comparison-legend-yes {
    background: var(--success);
    border-color: var(--success);
}
.comparison-legend-partial {
    background: linear-gradient(90deg, var(--warning) 50%, transparent 50%);
    border-color: var(--warning);
}
.comparison-legend-no {
    background: transparent;
    border-color: var(--text-secondary);
    opacity: 0.55;
}

.comparison-table-wrap {
    max-width: 1100px;
    margin: 0 auto;
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    background: var(--bg);
    /* overflow visible so tooltips can escape the wrap. Corner rounding is
       applied to the four outer cells instead (below). */
    overflow: visible;
    /* Soft shadow lifts the whole matrix off the section background. */
    box-shadow: 0 20px 48px rgba(0, 0, 0, 0.18);
}

/* Round the outer corners of the matrix via the four outer cells so the
   wrap can stay overflow-visible (for tooltips) while still showing a clean
   rounded frame. */
.comparison-table thead tr:first-child th:first-child {
    border-top-left-radius: var(--radius-lg);
}
.comparison-table thead tr:first-child th:last-child {
    border-top-right-radius: var(--radius-lg);
}
.comparison-table tbody tr:last-child td:first-child {
    border-bottom-left-radius: var(--radius-lg);
}
.comparison-table tbody tr:last-child td:last-child {
    border-bottom-right-radius: var(--radius-lg);
}

.comparison-table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: 0.875rem;
    /* Let columns size by content and wrap long values instead of forcing
       horizontal scroll. */
    table-layout: auto;
}

.comparison-table th,
.comparison-table td {
    padding: 10px 12px;
    text-align: center;
    /* Borderless rows — modern table style. Row separation comes from padding
       + hover bg. Bowire column keeps its accent border rails (below). */
    border: none;
    position: relative;
    vertical-align: middle;
    /* Allow long pill values to wrap into the next line if a column is narrow. */
    word-break: normal;
    overflow-wrap: anywhere;
}

.comparison-table .comparison-feature,
.comparison-table .comparison-feature-col {
    text-align: left;
}

.comparison-table thead th {
    color: var(--text-secondary);
    font-weight: 600;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    background: var(--bg-elevated);
    padding: 14px 12px;
    white-space: nowrap;
}

.comparison-table tbody tr:hover td {
    background: rgba(99, 102, 241, 0.035);
}

.comparison-feature-col {
    width: 30%;
}

.comparison-feature {
    color: var(--text);
    font-weight: 500;
    line-height: 1.4;
    padding-right: 8px;
}

/* --- Expandable rows (click-to-reveal sub-rows with per-item detail).
       Chevron in the feature cell rotates when expanded. Sub-rows are
       hidden by default via `display: none` and indent their label. --- */
.comparison-row-toggle {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
    font-weight: 500;
    cursor: pointer;
    text-align: left;
    width: 100%;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    line-height: inherit;
    /* Label on the left, chevron pushed to the right edge like a "..."
       affordance — makes the row feel clickable on either end. */
    justify-content: space-between;
}
.comparison-row-toggle-label {
    flex: 1 1 auto;
    min-width: 0;
}
.comparison-row-toggle:hover {
    color: var(--accent);
}
.comparison-chevron {
    width: 12px;
    height: 12px;
    flex-shrink: 0;
    opacity: 0.55;
    transition: transform 0.2s, opacity 0.15s;
    margin-right: 4px;
}
.comparison-row-toggle:hover .comparison-chevron {
    opacity: 1;
}
.comparison-row-toggle[aria-expanded="true"] .comparison-chevron {
    /* Collapsed: points right (▸). Expanded: points down (▾). */
    transform: rotate(90deg);
    opacity: 1;
    color: var(--accent);
}

.comparison-row-sub {
    display: none;
    background: rgba(99, 102, 241, 0.04);
}
.comparison-row-sub.is-expanded {
    display: table-row;
}
.comparison-row-sub td {
    padding-top: 7px;
    padding-bottom: 7px;
    font-size: 0.8rem;
}
.comparison-row-sub .comparison-feature-sub {
    padding-left: 36px;
    color: var(--text-secondary);
    font-weight: 400;
    font-size: 0.82rem;
}
/* Sub-row pills render smaller to match the tighter row height. */
.comparison-row-sub .c-yes::before,
.comparison-row-sub .c-no::before {
    width: 20px;
    height: 20px;
}
.comparison-row-sub .c-yes::after,
.comparison-row-sub .c-no::after {
    font-size: 0.85rem;
}
.comparison-row-sub .comparison-value {
    font-size: 0.72rem;
    padding: 2px 7px;
}

.comparison-feature code {
    font-size: 0.85em;
}

/* --- Bowire column: floating, "popped-out" highlight rail.
       Vertical gradient + accent side-rails + outer glow shadow so the
       column reads like an elevated card that's visibly closer to the
       viewer than the rest of the matrix. --- */
.comparison-table .comparison-bowire {
    background:
        linear-gradient(180deg,
            rgba(99, 102, 241, 0.16) 0%,
            rgba(99, 102, 241, 0.06) 100%);
    color: var(--accent);
    font-weight: 700;
    border-left: 1px solid rgba(99, 102, 241, 0.4);
    border-right: 1px solid rgba(99, 102, 241, 0.4);
    /* Left and right outer shadows: each cell contributes a slice of the
       column's "raised" drop-shadow. Stacks across the whole column. */
    box-shadow:
        -10px 0 28px -8px rgba(99, 102, 241, 0.22),
        10px 0 28px -8px rgba(99, 102, 241, 0.22);
}
.comparison-table thead th.comparison-bowire {
    color: var(--accent);
    padding-top: 18px;
    padding-bottom: 14px;
    border-top: 3px solid var(--accent);
    background:
        linear-gradient(180deg,
            rgba(99, 102, 241, 0.32) 0%,
            rgba(99, 102, 241, 0.16) 100%);
    /* Top cap glow + side rails — completes the "raised column" effect. */
    box-shadow:
        0 -10px 24px -4px rgba(99, 102, 241, 0.3),
        -10px 0 28px -8px rgba(99, 102, 241, 0.22),
        10px 0 28px -8px rgba(99, 102, 241, 0.22);
}
.comparison-table tbody tr:last-child td.comparison-bowire {
    padding-bottom: 16px;
    border-bottom: 2px solid var(--accent);
    box-shadow:
        0 10px 24px -4px rgba(99, 102, 241, 0.25),
        -10px 0 28px -8px rgba(99, 102, 241, 0.22),
        10px 0 28px -8px rgba(99, 102, 241, 0.22);
}
.comparison-table tbody tr:hover .comparison-bowire {
    background:
        linear-gradient(180deg,
            rgba(99, 102, 241, 0.24) 0%,
            rgba(99, 102, 241, 0.12) 100%);
}

.comparison-brand {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--accent);
    font-weight: 700;
    letter-spacing: -0.01em;
}

/* Generic non-Bowire, non-feature text cells stay muted so the Bowire
   column pops. */
.comparison-table td:not(.comparison-bowire):not(.comparison-feature) {
    color: var(--text-secondary);
}

/* --- ✓ / ✗ tokens: soft-filled circular pills via ::before pseudo.
       Keeps the glyph readable while giving the matrix a more modern,
       badge-driven visual rhythm. --- */
/* --- Three-state circle tokens (y / partial / n):
       full filled = fully supported, half filled = partial / limited,
       empty outline = not supported. Same glyph shape, different fill
       state — calmer visual language than ✓/✗, easier to scan. --- */
.comparison-table .c-yes,
.comparison-table .c-no,
.comparison-table .c-partial {
    color: transparent;  /* hide any raw ✓/✗ text content */
    position: relative;
    isolation: isolate;
    font-size: 0;
    line-height: 1;
}
.comparison-table .c-yes::before,
.comparison-table .c-no::before,
.comparison-table .c-partial::before {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 14px;
    height: 14px;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    box-sizing: border-box;
    border: 2px solid transparent;
}
.comparison-table .c-yes::before {
    background: var(--success);
    border-color: var(--success);
    box-shadow: 0 0 0 4px rgba(52, 211, 153, 0.14);
}
.comparison-table .c-partial::before {
    /* Half-filled circle: left half = filled warning colour. */
    background: linear-gradient(90deg, var(--warning) 50%, transparent 50%);
    border-color: var(--warning);
    box-shadow: 0 0 0 4px rgba(251, 191, 36, 0.12);
}
.comparison-table .c-no::before {
    background: transparent;
    border-color: var(--text-secondary);
    opacity: 0.45;
}
/* c-partial cells keep the cursor:help affordance so it's obvious there
   is more context behind the symbol via data-detail tooltip. */
.comparison-table .c-partial {
    cursor: help;
}

/* c-yes-text: "positive" text values (like "Public Workspaces") without the
   circular pill overlay — green-tinted pill via the JS wrapping below. */
.comparison-table .c-yes-text .comparison-value {
    color: var(--success);
    background: rgba(52, 211, 153, 0.12);
    border-color: rgba(52, 211, 153, 0.35);
}

/* Bowire column ✓ / ✗ share the same pill size as the rest — the column's
   gradient + glow already carries the "this is the highlighted one" signal. */

/* --- Plain-text status values (wrapped in .comparison-value via main.js):
       subtle pill-shaped chips that make "Newman", "paid cloud", "planned"
       read as status badges instead of grey text. --- */
.comparison-value {
    display: inline-block;
    padding: 3px 9px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 500;
    color: var(--text-secondary);
    line-height: 1.35;
    /* Let the pill wrap if a column is narrow instead of forcing horizontal scroll. */
    white-space: normal;
    max-width: 100%;
    position: relative;
}

/* Hover tooltip for pills carrying a data-detail attribute (e.g. the list of
   protocols behind "10+" or "3"). Subtle dotted underline signals there's
   more info; hover reveals it. Works on keyboard focus too. */
.comparison-value[data-detail] {
    cursor: help;
    border-bottom-style: dashed;
    border-bottom-width: 1px;
}
.comparison-value[data-detail]::after {
    content: attr(data-detail);
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 8px 12px;
    font-size: 0.76rem;
    font-weight: 500;
    color: var(--text);
    line-height: 1.5;
    white-space: normal;
    min-width: 200px;
    max-width: 280px;
    text-align: left;
    opacity: 0;
    pointer-events: none;
    z-index: 50;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.3);
    transition: opacity 0.15s, transform 0.15s;
}
.comparison-value[data-detail]:hover::after,
.comparison-value[data-detail]:focus::after {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
}

/* Tooltip on the <td> itself — used by c-partial / c-yes / c-no cells where
   the original text lives in data-detail rather than inside a pill span. */
.comparison-table td[data-detail]:hover::after {
    content: attr(data-detail);
    position: absolute;
    bottom: calc(100% - 4px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 8px 12px;
    font-size: 0.76rem;
    font-weight: 500;
    color: var(--text);
    line-height: 1.5;
    white-space: normal;
    min-width: 160px;
    max-width: 240px;
    text-align: center;
    z-index: 50;
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.3);
    pointer-events: none;
}
.comparison-bowire .comparison-value {
    background: rgba(99, 102, 241, 0.18);
    border-color: rgba(99, 102, 241, 0.35);
    color: var(--accent);
    font-weight: 600;
}


.comparison-footnote {
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.875rem;
    max-width: 720px;
    margin: 32px auto 0;
    line-height: 1.6;
}

.comparison-footnote strong {
    color: var(--text);
}

.comparison-footnote-correction {
    margin-top: 12px;
    font-size: 0.8125rem;
    opacity: 0.85;
}

/* ===== FAQ ===== */
.faq {
    padding: 100px 0;
    background: var(--bg);
}

/* "Coming from..." chooser — horizontal tab row + single visible panel.
   Replaces the old accordion stack so the reader only sees the answer
   relevant to their current tool. */
.faq-chooser {
    max-width: 820px;
    margin: 0 auto;
}
.faq-chooser-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: center;
    margin-bottom: 28px;
}
.faq-chooser-tab {
    padding: 8px 16px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-secondary);
    font: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
.faq-chooser-tab:hover {
    border-color: rgba(99, 102, 241, 0.5);
    color: var(--text);
}
.faq-chooser-tab.active {
    background: rgba(99, 102, 241, 0.15);
    border-color: rgba(99, 102, 241, 0.5);
    color: var(--accent);
}
.faq-chooser-panel {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 28px 32px;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.65;
}
.faq-chooser-panel[hidden] {
    display: none;
}
.faq-chooser-panel p {
    margin: 0;
}
.faq-chooser-panel p + p {
    margin-top: 12px;
}
.faq-chooser-panel code {
    font-size: 0.85em;
}

/* Legacy accordion styles kept below for any page still using them. */
.faq-list {
    max-width: 820px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.faq-item {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
    transition: border-color 0.2s;
}

.faq-item[open] {
    border-color: rgba(99, 102, 241, 0.4);
}

.faq-item summary {
    list-style: none;
    cursor: pointer;
    padding: 18px 24px;
    font-weight: 600;
    font-size: 1rem;
    color: var(--text);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    position: relative;
}
/* Wrap summary text in <span> keeps inline <code> together with the
   surrounding text as a single flex item (otherwise text nodes split). */
.faq-item summary > span {
    flex: 1 1 auto;
    min-width: 0;
}
.faq-item summary::-webkit-details-marker { display: none; }

/* Chevron marker — rotates 90° when the item opens. */
.faq-item summary::after {
    content: '';
    flex-shrink: 0;
    width: 10px;
    height: 10px;
    border-right: 2px solid var(--text-secondary);
    border-bottom: 2px solid var(--text-secondary);
    transform: rotate(-45deg);
    transition: transform 0.2s, border-color 0.2s;
    margin-right: 4px;
}
.faq-item[open] summary::after {
    transform: rotate(45deg);
    border-color: var(--accent);
}

.faq-item summary:hover {
    color: var(--accent);
}

.faq-body {
    padding: 0 24px 20px;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.65;
}

.faq-body p + p {
    margin-top: 10px;
}

.faq-body code {
    font-size: 0.85em;
}

/* ===== Roadmap teaser ===== */
.roadmap {
    padding: 100px 0;
    background: var(--bg-elevated);
}

.roadmap-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 12px;
    max-width: 800px;
    margin: 0 auto;
}

.roadmap-card {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 20px 24px;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 20px;
    align-items: start;
    transition: border-color 0.2s, transform 0.2s;
    color: inherit;
    text-decoration: none;
}
.roadmap-card:hover {
    border-color: var(--accent);
    transform: translateY(-1px);
}
.roadmap-card:hover h3 {
    color: var(--accent);
    transition: color 0.2s;
}

.roadmap-number {
    /* Theme-aware "Bowire coin" — mirrors the logo's filled disc with
       inverted text, so it reads like a brand-mark on each backlog entry. */
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--text);
    color: var(--bg);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    margin-top: 6px;
}

.roadmap-card-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    min-width: 0;
    border-left: 1px solid var(--border);
    padding-left: 20px;
    align-self: stretch;
}

.roadmap-card h3 {
    font-size: 1.0625rem;
    font-weight: 600;
    margin: 0;
    color: var(--text);
}

.roadmap-card p {
    font-size: 0.9375rem;
    color: var(--text-secondary);
    line-height: 1.55;
    margin: 0;
}

.roadmap-card code {
    font-size: 0.85em;
}

/* Subtle inline-link closer for the roadmap section — matches the
   pattern used at the bottom of compare / features / protocols / use-cases. */
.roadmap-cta {
    text-align: center;
    margin: 32px 0 0;
    font-size: 0.9375rem;
    color: var(--text-secondary);
}
.roadmap-cta a {
    color: var(--accent);
    font-weight: 600;
}
.roadmap-cta a:hover {
    color: var(--accent-hover);
    text-decoration: underline;
}

.roadmap-footnote {
    text-align: center;
    color: var(--text-secondary);
    font-size: 0.875rem;
    max-width: 760px;
    margin: 20px auto 0;
    line-height: 1.6;
}

/* ===== CTA ===== */
.cta {
    padding: 100px 0;
    /* Elevated bg so "Join the crew" lifts off the .install block
       above (which sits on base bg). Continues the landing-page
       zigzag pattern (E-B-E-B…) all the way down to the closing
       CTA — every section heading has a clear neighbour break. */
    background: var(--bg-elevated);
}

.cta-inner {
    text-align: center;
    max-width: 720px;
}

.cta-content h2 {
    font-size: clamp(2rem, 5vw, 2.75rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin-bottom: 12px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.cta-tagline {
    color: var(--text-secondary);
    font-size: 1.0625rem;
    margin-bottom: 36px;
}

.cta-snippets {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 16px;
    margin-bottom: 36px;
    text-align: left;
}

.cta-snippet {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 16px 18px;
}

.cta-snippet-label {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 10px;
    font-family: var(--font-sans);
    display: flex;
    align-items: center;
    gap: 8px;
}
.cta-snippet-icon {
    width: 16px;
    height: 16px;
    color: var(--accent);
    flex-shrink: 0;
}

.cta-snippet pre {
    margin: 0;
    padding: 0;
    background: none;
    border: none;
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    line-height: 1.55;
    color: var(--text);
    overflow-x: auto;
    white-space: pre;
}

.cta-snippet pre code {
    background: none;
    padding: 0;
    color: inherit;
    font-size: inherit;
}

/* Link lists inside community CTA cards. Share the card chrome with the
   code-snippet variant but render as clickable rows instead of a pre block. */
.cta-link-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.cta-link-list li + li {
    margin-top: 6px;
}
.cta-link-list a {
    display: inline-block;
    font-size: 0.9rem;
    color: var(--text);
    text-decoration: none;
    transition: color 0.15s, transform 0.15s;
}
.cta-link-list a:hover {
    color: var(--accent);
    transform: translateX(2px);
}

.cta-actions {
    /* Centred on the page width with the same gap as the cards above. */
    display: flex;
    gap: 16px;
    justify-content: center;
    margin-bottom: 24px;
}
.cta-actions .btn {
    /* Fixed width keeps both buttons visually identical regardless of
       content length (Get Started + rocket vs Star on GitHub + mark). */
    width: 220px;
    justify-content: center;
}
@media (max-width: 768px) {
    .cta-actions {
        flex-direction: column;
        align-items: center;
    }
}

.cta-trust {
    max-width: 640px;
    margin: 28px auto 16px;
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--text-secondary);
}

/* Final closer line — keeps the features-detail-cta typography but adds
   a bit more breathing room below so the page doesn't end flush against
   the footer. */
.cta-closer-line {
    margin-top: 28px;
    margin-bottom: 8px;
}

/* Plain-text sign-off under the closer link — matches the visual weight
   of the old .cta-setsail element but is not a link. Second half
   ("Discover APIs.") picks up --accent to echo the old CTA colouring. */
.cta-finale {
    margin: 36px auto 40px;
    font-size: 1.25rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    text-align: center;
    color: var(--text);
}
.cta-finale span {
    color: var(--accent);
}

.cta-trust strong {
    color: var(--text);
    font-weight: 700;
}
.cta-trust a {
    color: var(--accent);
}
.cta-trust a:hover {
    color: var(--accent-hover);
}

.cta-meta {
    color: var(--text-secondary);
    font-size: 0.8125rem;
    margin: 0;
}

.cta-meta a {
    color: var(--text-secondary);
    text-decoration: none;
    border-bottom: 1px dotted var(--text-secondary);
    transition: color 0.2s, border-color 0.2s;
}

.cta-meta a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

/* ===== Footer =====
   Two-tier layout: top row holds brand + three nav columns (product,
   source, company/legal). Bottom row holds the copyright, separated
   by a subtle divider. Taller than the old single-row footer to give
   the legal / privacy / about links proper home. */
.site-footer {
    padding: 40px 0 32px;
    border-top: 1px solid var(--border);
    /* Explicit footer bg so the top border line clearly marks where the
       footer begins — otherwise the site-footer inherits body bg and the
       line looks like it floats with black space on both sides. */
    background: var(--bg-footer);
}

.footer-top {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 48px;
    align-items: start;
}

.footer-nav {
    display: grid;
    grid-template-columns: repeat(3, minmax(130px, auto));
    gap: 32px 48px;
}
.footer-nav-col {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.footer-nav-title {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-secondary);
    margin: 0 0 6px;
}
.footer-nav-col a {
    color: var(--text-secondary);
    font-size: 0.875rem;
    transition: color 0.15s;
}
.footer-nav-col a:hover {
    color: var(--accent);
}

.footer-bottom {
    /* Full-width divider bar — border-top spans edge-to-edge because this
       element sits outside the .container, with its own centred container
       wrapping the copyright text. */
    margin-top: 40px;
    padding: 20px 0;
    border-top: 1px solid var(--border);
    text-align: center;
}

@media (max-width: 768px) {
    .footer-top {
        grid-template-columns: 1fr;
        gap: 32px;
    }
    .footer-nav {
        grid-template-columns: repeat(3, 1fr);
        gap: 24px;
    }
}
@media (max-width: 480px) {
    .footer-nav {
        grid-template-columns: 1fr 1fr;
    }
}

.footer-inner {
    display: block;
}

.footer-brand {
    /* 6px sits between a word-space and a visible separator so
       "Bowire is tied by Küstenlogik in Northern Germany" still
       reads as one sentence. flex-wrap lets the tagline drop to the
       next line on narrow viewports. */
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.footer-logo {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 700;
    font-size: 0.8125rem;
    color: var(--text);
    line-height: 1;
}
.footer-logo-icon {
    width: 17px;
    height: 17px;
    flex-shrink: 0;
    display: block;
}

.footer-tagline {
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

.footer-copy {
    font-size: 0.8125rem;
    color: var(--text-secondary);
}

/* ===== Responsive ===== */
@media (max-width: 1024px) {
    .feature-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 640px) {
    .install-tabs {
        width: 100%;
    }
    .install-tab {
        padding: 10px 12px;
        flex: 1;
    }
    .install-panels {
        padding: 20px;
    }
}

@media (max-width: 768px) {
    .hero {
        padding: 120px 0 72px;
    }

    .header-nav {
        display: none;
        position: absolute;
        top: var(--header-height);
        left: 0;
        right: 0;
        background: rgba(15, 15, 23, 0.97);
        backdrop-filter: blur(12px);
        flex-direction: column;
        padding: 16px 24px;
        gap: 16px;
        border-bottom: 1px solid var(--border);
    }

    .header-nav.open {
        display: flex;
    }

    .mobile-menu-toggle {
        display: block;
    }

    /* Mobile right-hand action row: keep all five icons (search,
       home, theme, github, burger) — there's enough space once the
       row is tightened up. The burger has a 3 px stroke padding
       inside its 24×24 SVG box (lines run x1=3..x2=21), while the
       logo's circle hits the SVG edge flush, so without correction
       the burger's visual stroke sat 3 px further from the viewport
       edge than the logo's circle did. Pull the burger out by
       margin-right:-3 px so the right-edge breathing room matches
       the logo's left-edge breathing room exactly. */
    .header-actions {
        gap: 6px;
    }
    /* Burger sits flush against the right viewport edge so its visual
       stroke aligns with the logo's circle on the left. The button has
       padding:4 from base + the SVG itself has 3 px of internal stroke
       padding (lines run x1=3..x2=21 inside a 24×24 box) — so we zero
       the button's right-padding and add a small negative margin to
       compensate for the SVG-internal padding that doesn't move. */
    .mobile-menu-toggle {
        padding: 4px 0 4px 4px;
        margin-right: -7px;
    }
    /* Burger menu drops a 1 px gap between the header bottom edge and
       the open submenu — caused by the .site-header's border-bottom +
       the absolute-positioned nav anchored at top:var(--header-height)
       (which sits below the border). Pull the nav up by 1 px so it
       butts up against the header without a transparent slit. */
    .header-nav.open {
        top: calc(var(--header-height) - 1px);
    }

    /* Belt-and-suspenders against horizontal overflow on phones —
       any single oversized element (a stretched grid cell, a long
       inline code block, a Pagefind result with a wide URL) used to
       widen the body and produce a dark gutter on the right edge,
       which made the entire layout look shifted left and the burger
       look 'centred' relative to the visible area. Clamp body
       overflow-x so a runaway child can't push siblings off-screen. */
    html, body {
        overflow-x: hidden;
    }

    .feature-grid {
        grid-template-columns: 1fr;
    }

    .protocol-grid {
        grid-template-columns: 1fr;
    }

    .screenshot-grid {
        grid-template-columns: 1fr;
    }

    .use-case-grid {
        grid-template-columns: 1fr;
    }

    .cta-snippets {
        grid-template-columns: 1fr;
    }

    .comparison-table th,
    .comparison-table td {
        padding: 10px 12px;
        font-size: 0.8125rem;
    }

    /* Mobile comparison table — only two data columns fit on a phone
       (Bowire + one competitor). A JS-injected select above the
       table lets the reader page through Postman / Scalar /
       Swashbuckle / Insomnia / Bruno as the right-hand column. With
       only three columns rendered (feature + Bowire + active tool)
       there's no horizontal scrolling, so we don't need sticky or
       fixed table-layout — the three columns just share the full
       width of the wrap and content sizes itself naturally.

       Column order in the markup:
         1 = feature name      4 = Scalar       7 = Bruno
         2 = Bowire            5 = Swashbuckle
         3 = Postman           6 = Insomnia
    */
    .comparison-table-wrap {
        overflow: hidden;
    }
    .comparison-table th.comparison-feature-col,
    .comparison-table td.comparison-feature {
        max-width: 40vw;
        word-break: normal;
        overflow-wrap: break-word;
    }
    /* Hide every non-active competitor column. The data-comparison-tool
       attribute on <html> is set by JS (default 'postman') and switched
       by the dropdown above the table. */
    .comparison-table th:nth-child(n+3),
    .comparison-table td:nth-child(n+3) {
        display: none;
    }
    [data-comparison-tool="postman"]    .comparison-table th:nth-child(3),
    [data-comparison-tool="postman"]    .comparison-table td:nth-child(3),
    [data-comparison-tool="scalar"]     .comparison-table th:nth-child(4),
    [data-comparison-tool="scalar"]     .comparison-table td:nth-child(4),
    [data-comparison-tool="swashbuckle"] .comparison-table th:nth-child(5),
    [data-comparison-tool="swashbuckle"] .comparison-table td:nth-child(5),
    [data-comparison-tool="insomnia"]   .comparison-table th:nth-child(6),
    [data-comparison-tool="insomnia"]   .comparison-table td:nth-child(6),
    [data-comparison-tool="bruno"]      .comparison-table th:nth-child(7),
    [data-comparison-tool="bruno"]      .comparison-table td:nth-child(7) {
        display: table-cell;
    }
    /* The dropdown is appended by main.js as .comparison-tool-picker;
       label + select sit above the table on a flush bar. */
    .comparison-tool-picker {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 10px 12px;
        background: var(--bg-elevated);
        border-bottom: 1px solid var(--border);
        font-size: 0.8125rem;
        color: var(--text-secondary);
    }
    .comparison-tool-picker label {
        font-weight: 600;
        color: var(--text);
        flex-shrink: 0;
    }
    .comparison-tool-picker select {
        flex: 1 1 auto;
        background: var(--bg);
        color: var(--text);
        border: 1px solid var(--border);
        border-radius: 6px;
        padding: 6px 28px 6px 10px;
        font-size: 0.9rem;
        font-family: inherit;
        cursor: pointer;
        appearance: none;
        -webkit-appearance: none;
        background-image: linear-gradient(45deg, transparent 50%, var(--text-secondary) 50%),
                          linear-gradient(135deg, var(--text-secondary) 50%, transparent 50%);
        background-position: calc(100% - 14px) 50%, calc(100% - 9px) 50%;
        background-size: 5px 5px;
        background-repeat: no-repeat;
    }
    /* Small "Bowire vs." prefix in the picker label so it's obvious
       the selected dropdown value is what Bowire is being compared
       against — independent of the table header itself. */

    /* Quickstart launch stepper: stack the three steps vertically on
       narrow viewports so step-1's "Pick your boat" label and step-3's
       "Run" both stay fully visible (otherwise they got clipped at the
       viewport edges). Connectors flip from horizontal to vertical
       bars between the rows. */
    .launch-steps {
        flex-direction: column;
        align-items: stretch;
        gap: 0;
    }
    .launch-step {
        justify-content: flex-start;
        padding: 10px 12px;
    }
    .launch-step-connector {
        flex: 0 0 24px;
        width: 2px;
        height: 24px;
        align-self: center;
        margin: 0;
    }

    .hero-actions {
        flex-direction: column;
        align-items: center;
    }

    .btn {
        width: 100%;
        max-width: 280px;
        justify-content: center;
    }

    .hero-terminal {
        font-size: 0.78rem;
        margin-top: 28px;
    }
    .hero-terminal-body {
        padding: 14px 14px 16px;
        min-height: 0;
    }

    .cta-actions {
        flex-direction: column;
        align-items: center;
    }

    .footer-inner {
        flex-direction: column;
        text-align: center;
    }

    .features,
    .protocols,
    .install,
    .cta {
        padding: 72px 0;
    }
}

@media (max-width: 480px) {
    .hero-logo {
        /* Proportional bump down for the horizontal logo on phones. */
        width: 120px;
        margin-bottom: 20px;
    }

    .hero-title {
        font-size: 2.5rem;
    }

    .container {
        padding: 0 16px;
    }

    .protocol-card {
        flex-direction: column;
        gap: 16px;
    }
}

/* ===== Downloads page ===== */
.downloads-hero {
    padding: 104px 0 40px;
    text-align: center;
}
.downloads-hero h1 {
    font-size: clamp(2.25rem, 5vw, 3.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.downloads-quick-picker {
    max-width: 720px;
    margin: 32px auto 0;
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    justify-content: center;
}
.downloads-quick-picker-label {
    font-size: 0.9375rem;
    color: var(--text-secondary);
    font-weight: 500;
}

/* Split-button shell: primary action (Download) + select bound as one
   unit with a shared border and a 1px divider between the two halves. */
.downloads-quick-picker-group {
    display: inline-flex;
    align-items: stretch;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    /* Intentionally NOT overflow:hidden — that would clip the absolute
       popover menu. Rounded corners are applied to each half instead. */
    transition: border-color 0.15s;
    background: var(--bg-elevated);
}
.downloads-quick-picker-group:hover,
.downloads-quick-picker-group:focus-within {
    border-color: var(--accent);
}
.downloads-quick-picker-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 18px;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text);
    background: transparent;
    border: none;
    border-right: 1px solid var(--border);
    border-radius: calc(var(--radius) - 1px) 0 0 calc(var(--radius) - 1px);
    white-space: nowrap;
    text-decoration: none;
    transition: background 0.15s, color 0.15s;
}
.downloads-quick-picker-btn:hover {
    background: rgba(99, 102, 241, 0.08);
    color: var(--accent);
}
.downloads-quick-picker-toggle {
    border-radius: 0 calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0;
}
/* Custom pop-over menu — gives full control over colours, padding, and
   hover state, instead of leaving the dropdown to OS rendering. */
.downloads-quick-picker-pop {
    position: relative;
    display: flex;
    align-items: stretch;
}
.downloads-quick-picker-toggle {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    min-width: 300px;
    font-family: inherit;
    font-size: 0.9375rem;
    background: transparent;
    border: none;
    color: var(--text);
    cursor: pointer;
    text-align: left;
}
.downloads-quick-picker-toggle:hover,
.downloads-quick-picker-toggle:focus {
    outline: none;
    background: rgba(99, 102, 241, 0.05);
}
.downloads-quick-picker-current {
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    /* Force left alignment inside the 300px-wide toggle — the label
       otherwise centres via inherited rules when the text is shorter
       than the toggle's min-width. */
    text-align: left;
    display: block;
}
.downloads-quick-picker-chevron {
    color: var(--text-secondary);
    flex-shrink: 0;
    transition: transform 0.15s;
}
.downloads-quick-picker-toggle[aria-expanded="true"] .downloads-quick-picker-chevron {
    transform: rotate(180deg);
}

.downloads-quick-picker-menu[hidden] {
    display: none;
}
.downloads-quick-picker-menu {
    /* Force left alignment — .downloads-hero has text-align: center and
       the inherited rule would otherwise centre every list item. */
    text-align: left;
    list-style: none;
    padding: 6px;
    margin: 6px 0 0;
    position: absolute;
    top: 100%;
    right: 0;
    min-width: 100%;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: 0 10px 32px -8px rgba(0, 0, 0, 0.35);
    z-index: 20;
    max-height: 60vh;
    overflow-y: auto;
}
.downloads-quick-picker-menu li {
    padding: 10px 14px;
    border-radius: calc(var(--radius) - 2px);
    font-size: 0.9375rem;
    color: var(--text);
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.1s, color 0.1s;
}
.downloads-quick-picker-menu li:hover,
.downloads-quick-picker-menu li:focus {
    background: rgba(99, 102, 241, 0.1);
    color: var(--accent);
    outline: none;
}
.downloads-quick-picker-menu li[aria-selected="true"] {
    background: rgba(99, 102, 241, 0.12);
    color: var(--accent);
    font-weight: 600;
}
@media (max-width: 560px) {
    .downloads-quick-picker-group {
        width: 100%;
        flex-direction: column;
        align-items: stretch;
    }
    .downloads-quick-picker-btn {
        border-right: none;
        border-bottom: 1px solid var(--border);
        border-radius: calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0;
        justify-content: center;
    }
    .downloads-quick-picker-toggle {
        border-radius: 0 0 calc(var(--radius) - 1px) calc(var(--radius) - 1px);
    }
    .downloads-quick-picker-toggle {
        min-width: 0;
        width: 100%;
    }
}

.downloads-hero-tagline {
    font-size: 1.125rem;
    color: var(--text-secondary);
    margin: 0 auto;
    max-width: 600px;
}

/* ===== Downloads page: grouped sections ===== */
.downloads-group {
    padding: 40px 0 48px;
    position: relative;
}
.downloads-group-alt {
    background: var(--bg-elevated);
    box-shadow: 0 0 0 100vmax var(--bg-elevated);
    clip-path: inset(0 -100vmax);
}
.downloads-group-header {
    text-align: center;
    max-width: 960px;
    margin: 0 auto 8px;
    padding: 24px 16px 0;
}
.downloads-group-title {
    font-size: clamp(1.75rem, 3.5vw, 2.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.downloads-group-lede {
    font-size: 1.0625rem;
    color: var(--text-secondary);
    line-height: 1.55;
    margin: 0;
}

.downloads-section {
    padding: 40px 0;
    border-top: 1px solid var(--border);
}
.downloads-group .downloads-section:first-of-type {
    border-top: none;
}
.downloads-section h2,
.downloads-section h3 {
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin: 0 0 10px;
    color: var(--text);
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}
.downloads-section-desc {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
    margin: 0 0 20px;
    max-width: none;
}
.downloads-sub,
h4.downloads-sub {
    font-size: 0.78rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--text-secondary);
    margin: 24px 0 10px;
}
.downloads-status-planned {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--warning);
    background: rgba(251, 191, 36, 0.14);
    border: 1px solid rgba(251, 191, 36, 0.35);
    padding: 3px 9px;
    border-radius: 999px;
}

/* Package list */
.downloads-pkgs {
    list-style: none;
    padding: 0;
    margin: 0 0 20px;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 10px;
}
.downloads-pkgs li {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 12px 14px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    transition: border-color 0.15s;
}
.downloads-pkg-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
}
.downloads-pkg-copy {
    padding: 2px;
    margin: -2px 0;
}

/* Protocol-plugin list variant: brand icon as visual anchor on the left. */
.downloads-pkgs-icons li {
    display: grid;
    grid-template-columns: 36px 1fr;
    gap: 14px;
    align-items: start;
}
.downloads-pkg-icon {
    width: 32px;
    height: 32px;
    display: flex;
    align-items: flex-start;
    justify-content: center;
}
.downloads-pkgs-icons .downloads-pkg-head {
    /* Collapse the text line-height so the package-name cap-top aligns
       with the icon's visible top edge instead of sitting ~5px below it. */
    line-height: 1;
}
.downloads-pkgs-icons .downloads-pkg-body {
    gap: 8px;
}
.downloads-pkg-icon svg {
    width: 100%;
    height: 100%;
}
.downloads-pkg-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.downloads-pkgs li:hover {
    border-color: rgba(99, 102, 241, 0.4);
}
.downloads-pkgs code {
    font-size: 0.82rem;
    color: var(--accent);
    background: transparent;
    padding: 0;
}
.downloads-pkg-desc {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    line-height: 1.5;
}
.downloads-pkg-desc code {
    font-size: 0.85em;
}

/* Terminal-style install command (same look as protocol-install). */
.downloads-command {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 10px 14px;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    color: var(--text);
    max-width: 620px;
    margin-bottom: 10px;
}
.downloads-command code {
    flex: 1 1 auto;
    overflow-x: auto;
    white-space: nowrap;
    background: transparent;
    padding: 0;
    color: var(--text);
    scrollbar-width: none;
}
.downloads-command code::-webkit-scrollbar { display: none; }
.downloads-prompt {
    color: var(--accent);
    font-weight: 700;
    margin-right: 6px;
    user-select: none;
}
.downloads-copy {
    flex-shrink: 0;
    background: transparent;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 4px;
    border-radius: 4px;
    display: inline-flex;
    align-items: center;
    transition: color 0.15s, background 0.15s;
}
.downloads-copy:hover {
    color: var(--accent);
    background: rgba(99, 102, 241, 0.1);
}
.downloads-copy.copied {
    color: var(--success);
}

.downloads-roadmap-link {
    display: inline-block;
    margin-top: 4px;
    font-size: 0.9375rem;
    color: var(--accent);
    font-weight: 600;
}
.downloads-roadmap-link:hover {
    color: var(--accent-hover);
}

/* Smaller footnote paragraph that sits under a roadmap/release link. */
.downloads-section-note {
    margin-top: 8px;
    font-size: 0.82rem;
}
/* Neutral pill next to a section title — "offline-ready", "single file",
   etc. Same shape as .downloads-status-planned but in accent instead of
   warning so it reads as an info tag, not a caveat. */
.downloads-section-version {
    font-size: 0.7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--accent);
    background: rgba(99, 102, 241, 0.12);
    border: 1px solid rgba(99, 102, 241, 0.35);
    padding: 3px 9px;
    border-radius: 999px;
    vertical-align: middle;
}

.page-content {
    padding: 0;
    padding-bottom: 80px;
}
/* When the page ends on an elevated-bg section (downloads.html ends
   with .downloads-group-alt; quickstart.html ends with the elevated
   "From here" CTA), drop the trailing 80px of base-bg padding —
   otherwise the gap between the elevated section and the footer
   reads as a leftover empty colour band. The section's own bottom
   padding keeps a comfortable visual breath before the footer band
   kicks in.

   Note: the elevated section sits inside `.container` which sits
   inside `.page-content`, so we match on any descendant rather than
   the `>` direct child variant. */
.page-content:has(.downloads-group-alt:last-child),
.page-content:has(.features-page-cta-elevated:last-child) {
    padding-bottom: 0;
}

/* ===== Legal / Privacy pages ===== */
.legal-hero {
    padding: 104px 0 32px;
    text-align: center;
}
.legal-hero h1 {
    font-size: clamp(2rem, 4vw, 2.75rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 12px;
    color: var(--text);
}
.legal-hero-tagline {
    font-size: 0.9375rem;
    color: var(--text-secondary);
    margin: 0 auto;
    max-width: 560px;
}
.legal-section {
    max-width: 720px;
    margin: 0 auto;
    /* Match the landing page's section padding pattern (slightly smaller
       than about/landing since legal sections are short). */
    padding: 64px 0;
}
/* Alternate bg to match about / landing sections — full-viewport bg via
   box-shadow + clip-path trick while the content stays at 720px. */
.legal-section-alt {
    background: var(--bg-elevated);
    box-shadow: 0 0 0 100vmax var(--bg-elevated);
    clip-path: inset(0 -100vmax);
}
.legal-section h2 {
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin: 0 0 10px;
    color: var(--text);
}
.legal-section p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.7;
    margin: 0 0 12px;
}
.legal-section p:last-child {
    margin-bottom: 0;
}
.legal-section p em {
    /* Placeholder text that the site owner needs to fill in — dimmed so
       it's visually obvious as a todo. */
    color: var(--text-secondary);
    opacity: 0.65;
    font-style: italic;
}
.legal-list {
    list-style: none;
    padding: 0;
    margin: 0;
}
.legal-list li {
    padding: 6px 0;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.65;
}
.legal-list li strong {
    color: var(--text);
    font-weight: 600;
    margin-right: 4px;
}
.legal-footnote {
    max-width: 720px;
    margin: 32px auto 0;
    padding: 20px 0 0;
    border-top: 1px solid var(--border);
    text-align: center;
    font-size: 0.875rem;
    color: var(--text-secondary);
}

/* ===== About page ===== */
.about-hero {
    /* Header height (64px) + 40px breathing room — matches the footer
       bottom spacing above the copyright divider. */
    padding: 104px 0 40px;
    text-align: center;
}
.about-hero h1 {
    font-size: clamp(2.25rem, 5vw, 3.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.about-hero-tagline {
    font-size: 1.125rem;
    color: var(--text-secondary);
    margin: 0 auto;
    max-width: 620px;
}
.about-section {
    max-width: 720px;
    margin: 0 auto;
    /* Match the landing page's 100px section padding so headlines don't
       hug the sticky header when scrolled to. */
    padding: 100px 0;
}
/* Alternate section background across the full viewport width. The section
   itself stays at 720px max (content width); the box-shadow + clip-path
   trick paints the elevated bg to both edges horizontally without affecting
   layout. Mirrors the landing page's section rhythm instead of the old
   thin divider lines. */
.about-section-alt {
    background: var(--bg-elevated);
    box-shadow: 0 0 0 100vmax var(--bg-elevated);
    clip-path: inset(0 -100vmax);
}
.about-section h2 {
    /* Match landing page section-titles — centred, larger, gradient text. */
    font-size: clamp(1.75rem, 3.5vw, 2.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    text-align: center;
    margin: 0 0 20px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.about-section p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.7;
    margin: 0 0 14px;
}
.about-section p:last-child {
    margin-bottom: 0;
}
.about-links {
    list-style: none;
    padding: 0;
    margin: 0;
}
.about-links li {
    padding: 8px 0;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
}
.about-links strong {
    color: var(--text);
    font-weight: 600;
    margin-right: 4px;
}

/* ===== Features page =====
   Alternating-side feature blocks (text-left / image-right, then swap).
   Linked from the screenshot carousel cards — softens the handoff from
   marketing page to technical docs by keeping the marketing voice and
   screenshot-hero flow for one more step. */
/* CTA link at the end of the feature-groups grid in the landing page's
   "Built for modern APIs" block — same subtle style as the "see the
   comparison table" link further up, not a prominent button. */
.features-detail-cta {
    text-align: center;
    margin: 28px 0 0;
    font-size: 0.875rem;
    color: var(--text-secondary);
}
.features-detail-cta a {
    color: var(--accent-light);
    text-decoration: underline;
    text-underline-offset: 3px;
    font-weight: 600;
}
.features-detail-cta a:hover {
    color: var(--text);
    text-decoration-color: var(--accent-light);
}

/* Inline links inside body paragraphs — WCAG 1.4.1 (Use of Color)
   says links inside text blocks must have a non-colour cue. Underline
   covers both the cue requirement and the colour-contrast bump
   (--accent-light hits AA against base + elevated bg). Scoped to <p>
   so nav buttons, hero CTAs, badge tags etc. stay link-styled by
   their own component rules. */
p a:not([class]),
.comparison-footnote a,
.roadmap-footnote a,
.cta-tagline a {
    color: var(--accent-light);
    text-decoration: underline;
    text-underline-offset: 2px;
    text-decoration-thickness: 1px;
}
p a:not([class]):hover,
.comparison-footnote a:hover,
.roadmap-footnote a:hover,
.cta-tagline a:hover {
    color: var(--text);
    text-decoration-thickness: 2px;
}

/* Soft CTAs at the end of sections — point readers to the "Join the crew"
   CTA if what they've seen doesn't fit their case. Use-cases + protocols
   share the same style. */
.use-cases-cta,
.protocols-cta {
    text-align: center;
    margin: 48px 0 0;
    font-size: 0.875rem;
    color: var(--text-secondary);
}
.use-cases-cta a,
.protocols-cta a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 8px;
    color: var(--accent);
    font-weight: 600;
}
.use-cases-cta a:hover,
.protocols-cta a:hover {
    color: var(--accent-hover);
}
.use-cases-cta a:hover svg,
.protocols-cta a:hover svg {
    transform: translateY(2px);
}
.use-cases-cta a svg,
.protocols-cta a svg {
    transition: transform 0.2s;
}

.features-page-hero {
    padding: 104px 0 40px;
    text-align: center;
}
.features-page-hero h1 {
    font-size: clamp(2.25rem, 5vw, 3.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.features-page-tagline {
    font-size: 1.125rem;
    color: var(--text-secondary);
    margin: 0 auto;
    max-width: 680px;
}
.features-page-note {
    font-size: 0.8125rem;
    color: var(--text-secondary);
    opacity: 0.75;
    margin: 18px auto 0;
    max-width: 520px;
}

/* ===== Features page: grouped sections ===== */
.features-group {
    padding: 40px 0 60px;
    position: relative;
}
.features-group-alt {
    background: var(--bg-elevated);
    box-shadow: 0 0 0 100vmax var(--bg-elevated);
    clip-path: inset(0 -100vmax);
}
.features-group-header {
    text-align: center;
    max-width: 720px;
    margin: 0 auto 8px;
    padding: 24px 16px 0;
}
.features-group-eyebrow {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--accent);
    margin: 0 0 10px;
}
.features-group-title {
    font-size: clamp(1.75rem, 3.5vw, 2.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.features-group-lede {
    font-size: 1.0625rem;
    color: var(--text-secondary);
    line-height: 1.55;
    margin: 0;
}

.features-block {
    padding: 60px 0;
    display: grid;
    grid-template-columns: 1fr 1.15fr;
    gap: 48px;
    align-items: center;
    border-top: 1px solid var(--border);
}
.features-group .features-block:first-of-type {
    border-top: none;
}
.features-block-reverse {
    grid-template-columns: 1.15fr 1fr;
}
.features-block-reverse .features-block-text {
    order: 2;
}
.features-block-reverse .features-block-screenshot {
    order: 1;
}


.features-block-text h2,
.features-block-text h3 {
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: -0.015em;
    margin: 0 0 12px;
    color: var(--text);
}
.features-block-lead {
    font-size: 1.0625rem;
    color: var(--text);
    line-height: 1.55;
    margin: 0 0 14px;
    font-weight: 500;
}
.features-block-text p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.65;
    margin: 0 0 14px;
}
.features-block-text p:last-of-type {
    margin-bottom: 18px;
}
.features-block-text code {
    font-size: 0.85em;
}
.features-block-docs-link {
    display: inline-block;
    color: var(--accent);
    font-weight: 600;
    font-size: 0.9375rem;
}
.features-block-docs-link:hover {
    color: var(--accent-hover);
}

.features-block-screenshot img {
    width: 100%;
    height: auto;
    border-radius: var(--radius-lg);
    border: 1px solid var(--border);
    box-shadow: 0 20px 48px rgba(0, 0, 0, 0.25);
    display: block;
    cursor: zoom-in;
    transition: transform 0.2s, border-color 0.2s;
}

/* USP detail-modal media block: a hero video on top (like the
   "See it in action" video on the home page) and a small 3-up
   gallery of supporting screenshots below it. Authored as
   `<div class="features-block-media">` inside the feature-card
   template; the modal then renders the entire block at full width
   above the text. */
.features-block-media {
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.features-block-media-video {
    aspect-ratio: 16 / 10;
    border-radius: var(--radius-lg);
    overflow: hidden;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    box-shadow: 0 20px 48px rgba(0, 0, 0, 0.25);
}
.features-block-media-video video {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
}
.features-block-media-gallery {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
}
.features-block-media-gallery img {
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    border-radius: var(--radius-md);
    border: 1px solid var(--border);
    transition: transform 0.2s, border-color 0.2s;
    cursor: zoom-in;
}
.features-block-media-gallery img:hover {
    border-color: var(--accent);
    transform: scale(1.02);
}
@media (max-width: 720px) {
    .features-block-media-gallery {
        grid-template-columns: repeat(2, 1fr);
    }
}
/* When the screenshot slot holds an illustrative code-snippet instead
   of an image, bump the radius to match the <img> siblings (the base
   shadow is already applied at the .code-block level). */
.features-block-screenshot .code-block {
    border-radius: var(--radius-lg);
}
.features-block-screenshot .code-block pre {
    font-size: 0.8125rem;
}
.features-block-screenshot .code-block .check-pass {
    color: var(--success);
    font-weight: 700;
}
.features-block-screenshot img:hover {
    transform: translateY(-2px);
    border-color: rgba(99, 102, 241, 0.5);
}

/* 2×2 grid for empty-states — four variations of the landing screen
   shown together so the "smart empty states" story reads at a glance. */
.features-block-screenshot-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.features-block-screenshot-grid img {
    border-radius: var(--radius);
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.25);
}

.features-page-cta {
    padding: 72px 0 80px;
    margin-top: 0;
    text-align: center;
    border-top: none;
}
/* The closing CTA paints its own elevated band to lift off the
   preceding feature-group strip — without it the block reads as
   one long flat region with the page body and the title gradient
   has nothing to sit on. Visual order from the bottom of the
   feature list down: page bg → elevated CTA → footer band. */
.features-page-cta-alt {
    background: var(--bg-elevated);
}
.features-page-cta-inner {
    max-width: 720px;
    margin: 0 auto;
    padding: 0 16px;
}
.features-page-cta-title {
    font-size: clamp(1.75rem, 3.5vw, 2.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.features-page-cta-lede {
    color: var(--text-secondary);
    font-size: 1rem;
    line-height: 1.65;
    margin: 0 0 24px;
}
.features-page-cta-buttons {
    display: flex;
    gap: 12px;
    justify-content: center;
    flex-wrap: wrap;
}
.features-page-cta-btn {
    min-width: 220px;
    justify-content: center;
}
/* "Read it. Sail it." finale — mirrors the .cta-finale on the
   landing-page Join-the-crew block, but quieter (this is the docs CTA,
   the loud one is on the homepage). Phrase + arrow link to community. */
.features-page-cta-finale {
    margin: 28px 0 0;
    font-size: 1rem;
    color: var(--text-secondary);
    text-align: center;
}

/* ============================================================
   Quickstart page — top-of-page path fork. SVG draws a "Y" rail:
   a single line from the hero descends, splits, and feeds into the
   two path-picker buttons (Standalone vs Embedded). Visually marks
   the decision as a track switch rather than a generic toggle.
   ============================================================ */
.quickstart-path-fork {
    max-width: 520px;
    margin: 8px auto 0;
    color: var(--border);
}
.quickstart-path-fork svg {
    width: 100%;
    height: 80px;
    display: block;
}

/* Path picker — two cards side by side, each anchored under one
   leg of the Y fork above. Toggle drives which stepper below is
   visible. */
.quickstart-path-picker {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
    max-width: 880px;
    margin: 0 auto 48px;
    padding: 0 16px;
}
.quickstart-path-btn {
    display: flex;
    gap: 16px;
    align-items: flex-start;
    padding: 18px 20px;
    background: var(--bg-elevated);
    border: 1.5px solid var(--border);
    border-radius: 12px;
    color: var(--text);
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    transition: border-color 0.18s, background 0.18s, transform 0.18s;
}
.quickstart-path-btn:hover {
    border-color: var(--text-secondary);
    transform: translateY(-1px);
}
.quickstart-path-btn[aria-selected="true"] {
    border-color: var(--accent);
    background: rgba(99, 102, 241, 0.08);
}
.quickstart-path-btn:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.quickstart-path-btn-icon {
    flex: 0 0 auto;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 10px;
    background: rgba(99, 102, 241, 0.10);
    color: var(--accent);
}
.quickstart-path-btn-body {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}
.quickstart-path-btn-title {
    font-weight: 700;
    font-size: 1.0625rem;
    color: var(--text);
}
.quickstart-path-btn-desc {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.45;
}
.quickstart-path-btn-desc code {
    font-size: 0.85em;
}

[data-path-content][hidden] {
    display: none !important;
}

/* On narrow viewports the fork + picker stack vertically — the SVG
   would look odd with two parallel tracks crossing, so we hide it
   and let the buttons read as a plain stack. */
@media (max-width: 640px) {
    .quickstart-path-fork {
        display: none;
    }
    .quickstart-path-picker {
        grid-template-columns: 1fr;
        gap: 12px;
        margin-bottom: 24px;
    }
}

/* ============================================================
   Quickstart page — vertical numbered stepper for /quickstart.html.
   Each step gets a big circled number on the left and the heading +
   content on the right, with a connector line drawn between
   consecutive numbers so the eye flows top-down. The horizontal
   ".launch-step" stepper on the home page (under "Straight into the
   water") is the visual cousin — same number-bubble idea, this one
   just stacks vertically and headings stay full-size.
   ============================================================ */
.quickstart-page-steps {
    max-width: 880px;
    margin: 48px auto 0;
    padding: 0 16px;
}
.quickstart-page-step {
    display: flex;
    gap: 28px;
    align-items: flex-start;
    position: relative;
    padding: 24px 0 56px;
}
.quickstart-page-step:last-child {
    padding-bottom: 0;
}
/* Connector line that runs from one bubble to the next. The
   bottom: -24px overshoot bridges the next step's padding-top so
   the rails meet seamlessly when articles are stacked back-to-back.
   Hidden articles (display:none) take 0 height, so the connector
   visually skips them and goes directly to the next visible step. */
.quickstart-page-step:has(~ .quickstart-page-step:not([hidden]))::before {
    content: '';
    position: absolute;
    left: 31px; /* = (64px bubble width / 2) - (2px line width / 2) */
    top: 88px;  /* below the 64px bubble + 24px top padding */
    bottom: -24px;
    width: 2px;
    background: var(--border);
}
/* Hidden articles must not contribute a connector either — they
   render at 0 height but the ::before would still draw to its
   bottom: -24px target, leaving a stray rail segment. */
.quickstart-page-step[hidden] {
    display: none !important;
}
.quickstart-page-step-num {
    flex: 0 0 auto;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: var(--bg-elevated);
    border: 2px solid var(--accent);
    color: var(--accent);
    font-size: 1.75rem;
    font-weight: 800;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative; /* sit above the connector line */
    z-index: 1;
}
.quickstart-page-step-optional .quickstart-page-step-num {
    /* Optional steps muted — same shape but secondary colour scheme so
       the eye reads "you can stop after step 3 if you want". */
    border-color: var(--border-strong, var(--border));
    color: var(--text-secondary);
}

/* Code-copy button — top-right of every <pre> on the quickstart
   page. Hidden until the snippet is hovered (or focused via
   keyboard) so the button doesn't compete with the code itself.
   "Copied" state flashes the accent colour for ~1.5s after a
   successful clipboard write. */
.quickstart-page-step pre.has-code-copy {
    position: relative;
}
.code-copy {
    position: absolute;
    top: 8px;
    right: 8px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 0.75rem;
    line-height: 1.2;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s, color 0.15s, border-color 0.15s, background 0.15s;
}
.quickstart-page-step pre.has-code-copy:hover .code-copy,
.quickstart-page-step pre.has-code-copy:focus-within .code-copy,
.code-copy:focus-visible {
    opacity: 1;
}
.code-copy:hover {
    color: var(--accent);
    border-color: var(--accent);
}
.code-copy.is-copied {
    color: #16a34a;
    border-color: #16a34a;
    opacity: 1;
}
.code-copy-icon {
    flex: 0 0 auto;
}

/* Pending placeholder shown before the user picks a path. The "?"
   in a dashed bubble + the dashed connector leading INTO it tell
   the reader "the next step is conditional on your choice above".
   JS hides this article once a path is selected, the real numbered
   step takes over with a solid bubble + solid connector. */
.quickstart-page-step-pending {
    /* Single-line placeholder body — vertically center the body
       against the 64px bubble instead of using the regular
       flex-start + padding-top alignment that assumes an h2 heading
       above the lead text. */
    align-items: center;
}
.quickstart-page-step-pending .quickstart-page-step-num {
    border-style: dashed;
    color: var(--text-secondary);
    background: var(--bg);
    font-weight: 600;
}
.quickstart-page-step-pending .quickstart-page-step-body {
    color: var(--text-secondary);
    font-style: italic;
    padding-top: 0;
}
/* Connector running INTO the pending step is dashed too. We pick
   it out by checking whether the next visible sibling is the
   pending placeholder. Border-left replaces the solid background
   bar so we can use border-style: dashed without painting two
   parallel rails. */
.quickstart-page-step:has(+ .quickstart-page-step-pending:not([hidden]))::before {
    background: transparent !important;
    border-left: 2px dashed var(--border);
    width: 0;
}

/* Decision step (step 1 — pick the path) starts in a "done" look
   because the picker has a default selected; switching paths just
   updates which downstream steps are visible, never invalidates the
   decision. The green tone signals to the reader that step 1 is the
   gate they've already cleared. */
.quickstart-page-step-decision.is-done .quickstart-page-step-num {
    border-color: #22c55e;
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
}

/* Finish step uses a flag bubble (SVG inside the .num element) and
   green styling — the reader has reached the destination. Connector
   line above terminates here naturally because the article is
   :last-child of the visible run. */
.quickstart-page-step-finish .quickstart-page-step-num {
    border-color: #22c55e;
    background: rgba(34, 197, 94, 0.12);
    color: #22c55e;
}
.quickstart-page-step-finish .quickstart-page-step-body h2 {
    color: #16a34a;
}
.quickstart-page-step-screenshot {
    width: 100%;
    height: auto;
    margin-top: 18px;
    border-radius: 10px;
    border: 1px solid var(--border);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);
    display: block;
}

/* Doc-link row: two follow-up links side by side, wraps cleanly on
   narrow viewports. */
.quickstart-page-step-links {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    margin: 12px 0 0;
}

/* CTA elevated variant: bg-elevated with a full-bleed shadow so the
   "From here" closer reads as its own band rather than blending into
   the previous step. Pair with `.features-page-cta` for spacing. */
.features-page-cta.features-page-cta-elevated {
    background: var(--bg-elevated);
    box-shadow: 0 0 0 100vmax var(--bg-elevated);
    clip-path: inset(0 -100vmax);
    margin-top: 64px;
}
.quickstart-page-step-body {
    flex: 1 1 auto;
    min-width: 0;
    /* Align the heading's first-line visual centre with the bubble
       centre. Bubble is 64px high; h2 line-height 38.4px (1.5rem
       font * 1.6) — so the offset to push the body text down is
       (64 - 38.4) / 2 ≈ 13px. */
    padding-top: 13px;
}
.quickstart-page-step-body h2 {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0 0 12px;
    letter-spacing: -0.01em;
    color: var(--text);
}
.quickstart-page-step-tag {
    display: inline-block;
    margin-left: 10px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    vertical-align: middle;
}
.quickstart-page-step-body .features-block-lead {
    margin-top: 0;
}

/* Mobile: bubble shrinks + the layout collapses to bubble-on-top
   instead of side-by-side so there's room for actual content. */
@media (max-width: 640px) {
    .quickstart-page-step {
        flex-direction: column;
        gap: 12px;
    }
    .quickstart-page-step:not(:last-child)::before {
        display: none;
    }
    .quickstart-page-step-num {
        width: 48px;
        height: 48px;
        font-size: 1.4rem;
    }
    .quickstart-page-step-body {
        padding-top: 0;
    }
}

/* ============================================================
   Quickstart install tabs — tabbed code blocks for the per-platform
   install path on the standalone /quickstart.html page. JS handler
   (bottom of main.js) picks the right tab on load via UA sniffing.
   ============================================================ */
.qs-install-tabs {
    margin: 1.25rem 0 0.5rem;
}
/* Chip-row sits above the snippet box. `width: fit-content` keeps
   the row only as wide as the chips themselves — without it the row
   stretches out across the step body when the active panel's code
   block (e.g. the long Docker snippet) widens its parent, and the
   gaps between chips visually grow with it. `max-width: 100%` keeps
   the row inside the available container so wrapping still kicks in
   on narrow viewports. */
.qs-install-tabs-list {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 12px;
    width: fit-content;
    max-width: 100%;
}
.qs-install-tab {
    padding: 5px 14px;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 999px;
    color: var(--text-secondary);
    cursor: pointer;
    font-family: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 1.4;
    transition: color 0.15s, border-color 0.15s, background 0.15s;
}
.qs-install-tab:hover {
    color: var(--text);
    border-color: var(--text-secondary);
}
.qs-install-tab[aria-selected="true"] {
    color: var(--accent);
    border-color: var(--accent);
    background: rgba(99, 102, 241, 0.10);
}
.qs-install-tab:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
/* Panel is unboxed — the inner `.code-block` (auto-wrapped by JS
   around the <pre>) is the single visual frame, matching the other
   quickstart snippets. The chip row stays above as a separate
   selector strip. */
.qs-install-tab-panel {
    background: transparent;
    border: 0;
    padding: 0;
}
.qs-install-tab-panel[hidden] {
    display: none !important;
}
.qs-install-tab-note {
    margin: 10px 0 0;
    font-size: 0.875rem;
    color: var(--text-secondary);
}
.features-page-cta-finale a {
    color: var(--accent);
    font-weight: 600;
    text-decoration: none;
    margin-left: 4px;
}
.features-page-cta-finale a:hover {
    text-decoration: underline;
}

@media (max-width: 860px) {
    .features-block {
        grid-template-columns: 1fr;
        gap: 28px;
        padding: 40px 0;
    }
    .features-block-reverse {
        grid-template-columns: 1fr;
    }
    .features-block-reverse .features-block-text,
    .features-block-reverse .features-block-screenshot {
        order: initial;
    }
}

/* ===== Screenshot lightbox overlay =====
   Shared by the features-page screenshots. Full-viewport dimmer with
   the image centred, click-to-close on the backdrop, Esc to dismiss. */
.lightbox {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.9);
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px;
    cursor: zoom-out;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}
.lightbox.is-open {
    opacity: 1;
    pointer-events: auto;
}
.lightbox-img {
    max-width: 100%;
    max-height: 100%;
    border-radius: var(--radius-lg);
    border: 1px solid rgba(255, 255, 255, 0.08);
    box-shadow: 0 32px 80px rgba(0, 0, 0, 0.6);
    cursor: default;
    display: block;
}
.lightbox-close {
    position: absolute;
    top: 18px;
    right: 18px;
    width: 40px;
    height: 40px;
    /* Rounded square — consistent with the other close buttons on the
       site (feature-modal, Pagefind clear-×). */
    border-radius: 8px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    background: rgba(15, 15, 23, 0.55);
    color: #fff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, border-color 0.15s;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}
.lightbox-close:hover {
    background: rgba(30, 30, 46, 0.8);
    border-color: rgba(255, 255, 255, 0.35);
}
.lightbox-close:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 3px;
}

/* ===== Rouge Syntax Highlighting (Dark) ===== */
.highlight .c,
.highlight .cm,
.highlight .c1,
.highlight .cs { color: var(--text-secondary); }
.highlight .k,
.highlight .kd,
.highlight .kn,
.highlight .kp,
.highlight .kr,
.highlight .kt { color: var(--accent-hover); }
.highlight .s,
.highlight .s1,
.highlight .s2,
.highlight .sb,
.highlight .sc,
.highlight .sd,
.highlight .se,
.highlight .sh,
.highlight .sx { color: var(--success); }
.highlight .na,
.highlight .nb,
.highlight .nc,
.highlight .nd,
.highlight .ne,
.highlight .nf { color: #a78bfa; }
.highlight .mi,
.highlight .mf,
.highlight .mh,
.highlight .mo { color: var(--warning); }
.highlight .o,
.highlight .ow { color: var(--text); }
.highlight .p { color: var(--text); }
.highlight .n,
.highlight .ni,
.highlight .nl,
.highlight .nn,
.highlight .no,
.highlight .nv { color: var(--text); }

/* ===== Theme Toggle Button =====
 * 32×32 ghost button next to the GitHub icon in the header. Cycles
 * light → dark → auto on click. The icon swap is driven by main.js
 * which sets the inner SVG based on the current state. The same
 * `theme` localStorage key is read by the docfx site so the choice
 * persists across the marketing → docs jump.
 */
.theme-toggle {
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.2s, border-color 0.2s, background 0.2s;
}
.theme-toggle:hover {
    color: var(--accent);
}
.theme-toggle:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Search icon trigger in the header — matches .nav-home / .theme-toggle
   siblings (32×32, transparent, accent on hover). Opens the Pagefind
   overlay defined in _layouts/default.html. */
.bowire-search-trigger {
    width: 32px;
    height: 32px;
    padding: 0;
    background: transparent;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: color 0.2s;
}
.bowire-search-trigger:hover {
    color: var(--accent);
}
.bowire-search-trigger[disabled],
.bowire-search-trigger[aria-disabled="true"] {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
}
.bowire-search-trigger:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Pagefind overlay — dimmed backdrop, centred panel containing the
   PagefindUI widget. Shared visual between marketing site and docs. */
.bowire-search-overlay {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: min(12vh, 120px);
    background: rgba(15, 15, 23, 0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
}
:root[data-theme-resolved="light"] .bowire-search-overlay,
:root[data-theme="light"] .bowire-search-overlay {
    background: rgba(200, 200, 220, 0.55);
}
.bowire-search-overlay.is-open {
    opacity: 1;
    pointer-events: auto;
}
.bowire-search-overlay-panel {
    width: min(680px, calc(100% - 48px));
    max-height: 80vh;
    /* Flex column so <form> and hint stay fixed while only the results
       drawer scrolls — the scroll thumb then tracks the results
       length, not the (form + count + drawer + hint) total. */
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg, 12px);
    padding: 0;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
    transform: translateY(-8px);
    transition: transform 0.2s ease;
}
.bowire-search-overlay.is-open .bowire-search-overlay-panel {
    transform: translateY(0);
}

/* Theme the Pagefind UI widget to the Bowire palette via its
   documented CSS custom properties. Bound to both dark and light theme
   attributes so the widget switches synchronously with the rest of the
   site when the user toggles the theme. Attribute selectors (0,2,0)
   beat Pagefind's default :root (0,1,0). Shared values live in a
   single rule so the two modes stay in lock-step. */
html[data-theme-resolved="dark"],
html[data-theme="dark"],
html[data-theme-resolved="light"],
html[data-theme="light"] {
    --pagefind-ui-scale: 1;
    --pagefind-ui-primary: var(--accent);
    --pagefind-ui-text: var(--text);
    --pagefind-ui-background: var(--bg-elevated);
    --pagefind-ui-border: var(--border);
    --pagefind-ui-tag: var(--surface);
    --pagefind-ui-border-width: 1px;
    --pagefind-ui-border-radius: 10px;
    --pagefind-ui-image-border-radius: 6px;
    --pagefind-ui-image-box-ratio: 3 / 2;
    --pagefind-ui-font: inherit;
}

/* Extra inner spacing + top-bar backdrop for the widget so it sits
   cleanly inside the overlay panel at both themes. */
.pagefind-ui {
    padding-top: 0 !important;
}
.pagefind-ui__drawer {
    gap: 24px !important;
}
.pagefind-ui__results-area {
    margin-top: 8px !important;
}
/* Result count — relocated by JS from inside the drawer to between
   the search input and the drawer (still inside the form so it
   inherits the tertiary "header" bg). Smaller font than the previous
   in-drawer placement so it reads as a sub-line of the input area
   rather than a result row. */
.pagefind-ui__message {
    color: var(--text-secondary) !important;
    font-size: 0.75rem !important;
    font-weight: 500 !important;
    padding: 8px 0 0 !important;
    margin: 0 !important;
    height: auto !important;
}
.pagefind-ui__result {
    /* Pagefind's Svelte build uses flex (not grid) and reserves a
       30 %-wide thumbnail column on every result via .pagefind-ui__
       result-thumb. Bowire results never carry images, so the column
       just leaves a phantom indent that pushed the title + excerpt
       right by ~30 % on phones. Hide the thumb and let .result-inner
       take the full row. */
    padding: 18px 0 20px !important;
    border-top: 1px solid var(--border) !important;
    cursor: pointer;
}
.pagefind-ui__result .pagefind-ui__result-thumb {
    display: none !important;
}
.pagefind-ui__result .pagefind-ui__result-inner {
    flex: 1 !important;
    margin-top: 0 !important;
    width: 100% !important;
}
/* The drawer already carries a border-top above the first result —
   skip the per-result rule for the first item to avoid the
   double-line stack. */
.pagefind-ui__result:first-child {
    border-top: none !important;
    padding-top: 0 !important;
}
.pagefind-ui__result-title {
    font-size: 1.0625rem !important;
    font-weight: 600 !important;
    line-height: 1.35 !important;
    margin-bottom: 4px !important;
}
.pagefind-ui__result-excerpt {
    font-size: 0.9375rem !important;
    color: var(--text-secondary) !important;
    line-height: 1.55 !important;
}
.pagefind-ui__result-tags {
    margin-top: 10px !important;
}
.pagefind-ui__result-tag {
    font-size: 0.75rem !important;
    padding: 3px 8px !important;
    color: var(--text-secondary) !important;
}

/* ==========================================================
   Feature detail modal — opened by click on a .feature-card
   that ships a <template class="feature-card-detail">. Uses
   the same visual language as the marketing site's sections
   (features-block style, accent lift, 12 px radius).
   ========================================================== */
.feature-card[data-feature-modal] {
    cursor: pointer;
}

.bowire-feature-modal {
    position: fixed;
    inset: 0;
    z-index: 2100;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: min(10vh, 96px);
    background: rgba(15, 15, 23, 0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
}
:root[data-theme-resolved="light"] .bowire-feature-modal,
:root[data-theme="light"] .bowire-feature-modal {
    background: rgba(200, 200, 220, 0.55);
}
.bowire-feature-modal.is-open {
    opacity: 1;
    pointer-events: auto;
}
.bowire-feature-modal-panel {
    position: relative;
    width: min(980px, calc(100% - 48px));
    max-height: 85vh;
    overflow: auto;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg, 12px);
    padding: 32px 36px 36px;
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.35);
    transform: translateY(-8px);
    transition: transform 0.2s ease;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.bowire-feature-modal.is-open .bowire-feature-modal-panel {
    transform: translateY(0);
}
.bowire-feature-modal-panel::-webkit-scrollbar { width: 10px; height: 10px; }
.bowire-feature-modal-panel::-webkit-scrollbar-track { background: transparent; }
.bowire-feature-modal-panel::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
.bowire-feature-modal-panel::-webkit-scrollbar-thumb:hover {
    background: var(--text-secondary);
    background-clip: padding-box;
}

/* Circular close-× matching the Pagefind clear button. */
.bowire-feature-modal-close {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 32px;
    height: 32px;
    padding: 0;
    /* Rounded square to match the Pagefind clear-× + the system's
       button radii — circular 50 % looked off against the 12 px modal
       border-radius. */
    border-radius: 8px;
    background: var(--border);
    color: var(--text);
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, color 0.15s, transform 0.15s;
    z-index: 1;
}
.bowire-feature-modal-close:hover {
    background: var(--accent);
    color: #fff;
    transform: scale(1.05);
}
.bowire-feature-modal-close:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* Inside the modal, reuse the existing .features-block styling so the
   detail view matches the standalone features.html layout pixel-for-
   pixel. features.html already owns the .features-block cascade — we
   only tune spacing here so it sits comfortably inside the modal. */
.bowire-feature-modal-body .features-block {
    padding: 0;
    margin: 0;
    gap: 32px;
    grid-template-columns: 1fr 1fr;
    /* Only one block per modal — drop the between-blocks divider
       .features-block inherits from the standalone features.html. */
    border-top: none;
}
.bowire-feature-modal-body .features-block h3 {
    margin-top: 0;
}
.bowire-feature-modal-body .features-block-screenshot img {
    border-radius: var(--radius-lg, 12px);
    border: 1px solid var(--border);
    box-shadow: 0 12px 32px rgba(0, 0, 0, 0.2);
    width: 100%;
    height: auto;
    display: block;
}
.bowire-feature-modal-body .features-block-docs-link {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    color: var(--accent);
    text-decoration: none;
    font-weight: 600;
    margin-top: 8px;
}
.bowire-feature-modal-body .features-block-docs-link:hover {
    text-decoration: underline;
}
/* Two-link footer in feature-card modals: "See the full tour" jumps
   to the marketing-prose anchor on /features.html, "Straight to the
   docs" goes to the same feature's full reference page under /docs/.
   Wrapper carries the top margin once so both links sit on a single
   baseline. */
.bowire-feature-modal-body .features-block-docs-links {
    display: flex;
    flex-wrap: wrap;
    gap: 18px;
    margin-top: 8px;
}
.bowire-feature-modal-body .features-block-docs-links .features-block-docs-link {
    margin-top: 0;
}

/* Capability tags inside the protocol-card modals. Each <li> is
   one capability and renders as a rounded pill so the spec line
   reads like a row of chips instead of a bullet list. The track
   wraps onto multiple rows on narrow modals. */
.features-block-capabilities {
    list-style: none;
    padding-left: 0;
    margin: 0 0 20px;
    display: flex;
    flex-wrap: wrap;
    gap: 6px 8px;
}
.features-block-capabilities li {
    display: inline-flex;
    align-items: center;
    padding: 4px 10px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--bg);
    color: var(--text-secondary);
    font-size: 0.8125rem;
    line-height: 1.35;
    white-space: nowrap;
}
.features-block-capabilities li code {
    background: transparent;
    padding: 0;
    font-size: 0.95em;
    color: var(--text);
}
:root[data-theme-resolved="light"] .features-block-capabilities li,
:root[data-theme="light"] .features-block-capabilities li {
    background: var(--bg-elevated);
}

/* Image lightbox — full-bleed zoom for screenshots inside the
   feature-modal popup. z-index sits above the feature-modal so it
   covers it; closing the lightbox reveals the modal again. */
.bowire-image-lightbox {
    position: fixed;
    inset: 0;
    z-index: 3000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(8, 8, 14, 0.92);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    padding: 48px;
    cursor: zoom-out;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s ease;
}
.bowire-image-lightbox.is-open {
    opacity: 1;
    pointer-events: auto;
}
.bowire-image-lightbox img {
    max-width: 100%;
    max-height: 100%;
    width: auto;
    height: auto;
    object-fit: contain;
    border-radius: var(--radius-lg, 12px);
    box-shadow: 0 24px 64px rgba(0, 0, 0, 0.55);
    cursor: default;
}
.bowire-image-lightbox-close {
    position: absolute;
    top: 20px;
    right: 24px;
    width: 40px;
    height: 40px;
    padding: 0;
    border: none;
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, transform 0.15s;
}
.bowire-image-lightbox-close:hover {
    background: rgba(255, 255, 255, 0.22);
    transform: scale(1.05);
}
.bowire-image-lightbox-close:focus-visible {
    outline: 2px solid #fff;
    outline-offset: 2px;
}
/* Hint that screenshots inside the popup are zoomable. */
.bowire-feature-modal-body .features-block-screenshot img {
    cursor: zoom-in;
    transition: transform 0.2s ease;
}
.bowire-feature-modal-body .features-block-screenshot img:hover {
    transform: translateY(-2px);
}

/* Text-only variant for feature blocks that don't ship a screenshot —
   collapse the 2-column grid to a single centered column with a
   comfortable reading width instead of leaving a blank right-hand
   cell. Applies both inside the popup modal and on the regular pages
   (workflows/backend.html, why-bowire.html, …) where some blocks are
   prose-only. */
.features-block-text-only {
    grid-template-columns: 1fr;
    max-width: 720px;
    margin: 0 auto;
}

@media (max-width: 768px) {
    .bowire-feature-modal-panel {
        padding: 24px 20px 28px;
        width: calc(100% - 32px);
    }
    .bowire-feature-modal-body .features-block {
        grid-template-columns: 1fr;
    }
}

/* Dedicated /search.html page — hero-style header + PagefindUI widget
   rendered inline (not in the overlay popout). Accessed via Enter in
   the search input or a direct link to /search.html?q=…. */
/* Workflow detail pages (/workflows/*.html) — persona tagline above
   the H1 so the reader sees immediately which path they're on. */
.workflow-hero-eyebrow {
    margin: 0 0 8px;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent);
}

.search-page {
    padding-top: 48px;
    padding-bottom: 64px;
    /* The input + results sit better at a reading width than spanning
       the full 1120 px container — mirror the docs article column. */
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
}
/* Dedicated search page nests its PagefindUI in #search-page-results.
   Recompute the clear-button position: no form padding-top + 52 px
   input (see `.pagefind-ui__search-input` override). Centre the 28 px
   button at (52-28)/2 = 12 px. */
#search-page-results .pagefind-ui__search-clear {
    top: 12px !important;
    right: 16px !important;
}
.search-page-title {
    font-size: 2.5rem;
    font-weight: 800;
    margin: 0 0 8px;
    color: var(--text);
    background: linear-gradient(135deg, var(--text) 0%, var(--accent) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.search-page-subtitle {
    color: var(--text-secondary);
    font-size: 1.0625rem;
    margin: 0 0 32px;
}

/* Pagefind-UI-specific selector overrides for cases where the
   --pagefind-ui-* vars don't reach (form border focus, button hover,
   highlight mark chip). Keep these aligned to the Bowire accent. */
.pagefind-ui__search-input {
    color: var(--text) !important;
    /* Pagefind ships the input at font-weight: 700 which reads as bold
       search results rather than a typed query. Drop to medium so the
       user's text sits in-rhythm with the excerpt typography below. */
    font-weight: 500 !important;
    font-size: 0.9375rem !important;
    /* Match the asymmetric icon/clear-button gutters: 44 px on the left
       for the magnifier glyph, 52 px on the right for the × button, so
       the query text is visually centred between them. */
    padding: 0 52px 0 44px !important;
    height: 52px !important;
    /* Pagefind renders the input with display: flex so the caret hugs
       the top edge when the field is empty. Restore vertical centring. */
    display: inline-flex !important;
    align-items: center !important;
    line-height: 1 !important;
}
/* Pagefind draws the magnifier as a ::before mask on the <form>. The
   exact centring depends on the form's padding + input height, which
   differ between the overlay (20 px padding, 52 px input) and the
   dedicated search page (no padding, 64 px input). Scope each. */
.bowire-search-overlay .pagefind-ui__form::before {
    top: 38px !important;
    left: 34px !important;
    width: 16px !important;
    height: 16px !important;
}
#search-page-results .pagefind-ui__form::before {
    /* 52 px input, no form padding: icon centred at y = 26, top = 18. */
    top: 18px !important;
    left: 20px !important;
    width: 16px !important;
    height: 16px !important;
}
.pagefind-ui__search-input::placeholder {
    color: var(--text-secondary) !important;
    opacity: 0.6 !important;
    font-weight: 400 !important;
}
.pagefind-ui__search-input:focus-visible {
    outline: none !important;
    border-color: var(--accent) !important;
    box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15) !important;
}
/* Theme the scrollbar of the search overlay panel so the track + thumb
   stay inside the palette — default browser scrollbars blow bright
   white on dark mode. */
.bowire-search-overlay-panel {
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.bowire-search-overlay-panel::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
.bowire-search-overlay-panel::-webkit-scrollbar-track {
    background: transparent;
}
.bowire-search-overlay-panel::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: padding-box;
}
.bowire-search-overlay-panel::-webkit-scrollbar-thumb:hover {
    background: var(--text-secondary);
    background-clip: padding-box;
}
.pagefind-ui__result-link {
    color: var(--text) !important;
}
.pagefind-ui__result-link:hover {
    color: var(--accent) !important;
}
.pagefind-ui mark {
    color: var(--accent);
    background: rgba(99, 102, 241, 0.14);
    padding: 0 2px;
    border-radius: 3px;
}

/* Arrow-key / hover highlight on the currently selected result.
   Background tint + accent text colour only — no left-stripe, since
   it would curve with the border-radius and read as comma-shaped. */
.pagefind-ui__result.is-highlighted {
    background: rgba(99, 102, 241, 0.08);
    border-radius: 8px;
    padding-left: 12px !important;
    padding-right: 12px !important;
    margin-left: -12px;
    margin-right: -12px;
}
.pagefind-ui__result.is-highlighted .pagefind-ui__result-link {
    color: var(--accent) !important;
}

/* Keyboard-shortcut hint at the bottom of the overlay panel — sits
   outside the scrollable drawer so it stays visible as the results
   scroll. */
.bowire-search-hint {
    flex: 0 0 auto;
    padding: 14px 20px;
    border-top: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-secondary);
    font-size: 0.75rem;
    text-align: center;
}
.bowire-search-hint kbd {
    display: inline-block;
    min-width: 20px;
    padding: 1px 5px;
    margin: 0 2px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-bottom-width: 2px;
    border-radius: 4px;
    font-family: var(--font-sans);
    font-size: 0.6875rem;
    color: var(--text);
    line-height: 1.4;
}

/* Pagefind's <form> wraps everything (input + button + drawer), so the
   form itself becomes a flex column. Input stays at the top, drawer
   grows and scrolls, hint outside the form as the panel footer. */
.bowire-search-overlay #search {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
.bowire-search-overlay .pagefind-ui {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
.bowire-search-overlay .pagefind-ui__form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    /* Symmetric 20 px padding around the content so the hint footer
       never hugs the input — matters most in the empty state when the
       drawer collapses to zero height. */
    padding: 20px;
    background: var(--bg-elevated);
}
.bowire-search-overlay .pagefind-ui__search-input {
    flex: 0 0 auto;
}
.bowire-search-overlay .pagefind-ui__drawer {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* Drawer bleeds to the form edges horizontally so the scrollbar
       aligns with the panel edge. Vertical gap above/below is provided
       by the surrounding form padding instead. */
    margin: 12px -20px -20px;
    padding: 0 20px 20px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}
.bowire-search-overlay .pagefind-ui__drawer::-webkit-scrollbar { width: 10px; }
.bowire-search-overlay .pagefind-ui__drawer::-webkit-scrollbar-track { background: transparent; }
.bowire-search-overlay .pagefind-ui__drawer::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: padding-box;
}

/* Overlay is a Suggest popup, capped at 5 results — Enter routes to
   the full /search.html page. No Load-More here. */
.bowire-search-overlay .pagefind-ui__button {
    display: none !important;
}

.pagefind-ui__button {
    background: var(--surface) !important;
    color: var(--text) !important;
    border: 1px solid var(--border) !important;
    border-radius: var(--radius, 8px) !important;
    font-weight: 600 !important;
    transition: background 0.2s, border-color 0.2s, color 0.2s, transform 0.2s !important;
    cursor: pointer !important;
}
.pagefind-ui__button:hover {
    background: var(--bg-elevated) !important;
    border-color: var(--accent) !important;
    color: var(--accent) !important;
    transform: translateY(-1px);
}
.pagefind-ui__button:focus-visible {
    outline: 2px solid var(--accent) !important;
    outline-offset: 2px;
}

/* Clear-query button — circular 28×28 × icon. Pagefind wraps the whole
   results area inside .pagefind-ui__form, so `top: 50%` would land us
   in the middle of the results list. Instead we pin the clear button
   next to the input using explicit pixel offsets that track both the
   sticky padding (16 px) and the input height (64 px). */
.pagefind-ui__search-clear {
    position: absolute !important;
    width: 28px !important;
    height: 28px !important;
    padding: 0 !important;
    /* 20 px form padding-top + (52 px input - 28 px button) / 2 = 32 px */
    top: 32px !important;
    /* Button sits INSIDE the input's right edge: form padding-right is
       20 px + input sits flush to that, so 28 px from form-right leaves
       an 8-px gap between button and input-right-border. */
    right: 28px !important;
    transform: none !important;
    /* Rounded square (8 px) matches the input's 10 px border + the rest
       of the site's button system — circular 50 % looked orphaned
       against the rounded-rect input around it. */
    border-radius: 8px !important;
    background: var(--border) !important;
    color: transparent !important;
    border: none !important;
    font-size: 0 !important;
    line-height: 0 !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    cursor: pointer !important;
    transition: background 0.15s, color 0.15s, transform 0.15s;
}
.pagefind-ui__search-clear::before {
    content: "";
    display: block;
    width: 10px;
    height: 10px;
    background-color: var(--text);
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><path stroke='black' stroke-width='1.6' stroke-linecap='round' d='M1 1l8 8M9 1l-8 8'/></svg>");
    mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><path stroke='black' stroke-width='1.6' stroke-linecap='round' d='M1 1l8 8M9 1l-8 8'/></svg>");
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: contain;
    mask-size: contain;
    transition: background-color 0.15s;
}
.pagefind-ui__search-clear:hover {
    background: var(--accent) !important;
    transform: scale(1.05) !important;
}
.pagefind-ui__search-clear:hover::before {
    background-color: #fff;
}
.pagefind-ui__search-clear:focus-visible {
    outline: 2px solid var(--accent) !important;
    outline-offset: 2px;
}
.theme-toggle svg {
    width: 16px;
    height: 16px;
}

/* ===== Community page =====
   Mirrors the About page's hero + alternating-section rhythm so /community
   reads as a sibling to /about, /downloads, /features — and reuses the card
   chrome from the landing-page "Join the crew" snippets for channel blocks. */
.community-hero {
    padding: 104px 0 40px;
    text-align: center;
}
.community-hero h1 {
    font-size: clamp(2.25rem, 5vw, 3.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 14px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.community-hero-tagline {
    font-size: 1.0625rem;
    color: var(--text-secondary);
    margin: 0 auto;
    max-width: 720px;
    line-height: 1.6;
}
.community-hero-tagline a {
    color: var(--accent);
    text-decoration: none;
}
.community-hero-tagline a:hover {
    color: var(--accent-hover);
}

/* 'Why it's worth being on deck' — first content section after the hero.
   Three concrete value-prop items, laid out as a clean 3-up grid with
   a subtle left accent stripe on each card to echo the callout style
   used elsewhere without shouting. */
.community-perks {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
}
.community-perk {
    padding: 20px 22px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-left: 3px solid var(--accent);
    border-radius: var(--radius);
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.community-section-alt .community-perk {
    background: var(--bg);
}
.community-perk-title {
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
}
.community-perk-desc {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--text-secondary);
}
@media (max-width: 860px) {
    .community-perks {
        grid-template-columns: 1fr;
    }
}
.community-section {
    max-width: 960px;
    margin: 0 auto;
    padding: 80px 24px;
}
.community-section-alt {
    background: var(--bg-elevated);
    box-shadow: 0 0 0 100vmax var(--bg-elevated);
    clip-path: inset(0 -100vmax);
}
.community-section-header {
    max-width: 720px;
    margin: 0 auto 36px;
    text-align: center;
}
.community-section-header h2 {
    font-size: clamp(1.75rem, 3.5vw, 2.25rem);
    font-weight: 800;
    letter-spacing: -0.02em;
    margin: 0 0 12px;
    background: linear-gradient(135deg, var(--text) 0%, var(--accent-hover) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}
.community-section-lede {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
    margin: 0;
}

/* 2×2 channel-card grid — Contribute / Stay in the loop / Discord / Ask.
   Collapses to a single column on narrow viewports. */
.community-channels {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
}
.community-channel {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 22px 22px 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.community-section-alt .community-channel {
    /* When the section itself already has the elevated bg, lift the card
       back to the base bg so it pops against the alt stripe. */
    background: var(--bg);
}
.community-channel-label {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-family: var(--font-sans);
    display: flex;
    align-items: center;
    gap: 8px;
}
.community-channel-icon {
    width: 16px;
    height: 16px;
    color: var(--accent);
    flex-shrink: 0;
}
.community-channel-desc {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.55;
    margin: 0;
}
.community-channel-links {
    list-style: none;
    padding: 0;
    margin: auto 0 0;
}
.community-channel-links li + li {
    margin-top: 6px;
}
.community-channel-links a {
    display: inline-block;
    font-size: 0.9rem;
    color: var(--text);
    text-decoration: none;
    transition: color 0.15s, transform 0.15s;
}
.community-channel-links a:hover {
    color: var(--accent);
    transform: translateX(2px);
}
.community-channel-links code {
    font-size: 0.8125rem;
    padding: 1px 5px;
    background: var(--bg-elevated);
    border-radius: 4px;
    color: var(--text);
}
@media (max-width: 860px) {
    .community-channels {
        grid-template-columns: 1fr;
    }
}

/* Get-in-touch split: info column + contact form. Cards stretch to match
   heights so the two halves read as a matched pair. */
.community-contact {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 32px;
    align-items: stretch;
}
.community-contact h3 {
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin: 0 0 12px;
    color: var(--text);
}
.community-contact-info {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 24px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.community-section-alt .community-contact-info {
    background: var(--bg);
}
.community-contact-info h3 {
    margin-bottom: 0;
}
.community-contact-info p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.65;
    margin: 0;
}
.community-contact-info a {
    color: var(--accent);
    text-decoration: none;
}
.community-contact-info a:hover {
    color: var(--accent-hover);
}
.community-contact-channels {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.community-contact-channels li {
    display: flex;
    align-items: baseline;
    gap: 12px;
    font-size: 0.9375rem;
}
.community-contact-channel-label {
    flex: 0 0 56px;
    color: var(--text-secondary);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
}

.community-contact-form {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 24px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.community-section-alt .community-contact-form {
    background: var(--bg);
}
.community-contact-form-lede {
    color: var(--text-secondary);
    font-size: 0.875rem;
    line-height: 1.55;
    margin: 0 0 4px;
}
.community-contact-form-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.community-contact-form-label {
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.community-contact-form input,
.community-contact-form select,
.community-contact-form textarea {
    width: 100%;
    padding: 10px 12px;
    font: inherit;
    font-size: 0.9375rem;
    color: var(--text);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 6px;
    transition: border-color 0.15s, box-shadow 0.15s;
}
.community-contact-form textarea {
    resize: vertical;
    min-height: 96px;
    font-family: var(--font-sans);
}
.community-contact-form input:focus,
.community-contact-form select:focus,
.community-contact-form textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 25%, transparent);
}
.community-contact-form-submit {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 4px;
    padding: 10px 16px;
    font: inherit;
    font-size: 0.9375rem;
    font-weight: 600;
    color: #fff;
    background: var(--accent);
    border: 1px solid var(--accent);
    border-radius: 6px;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
}
.community-contact-form-submit:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    transform: translateY(-1px);
}
.community-contact-form-hint {
    margin: 4px 0 0;
    font-size: 0.8125rem;
    color: var(--text-secondary);
}
.community-contact-form-hint a {
    color: var(--accent);
    text-decoration: none;
}
.community-contact-form-hint a:hover {
    color: var(--accent-hover);
}
@media (max-width: 760px) {
    .community-contact {
        grid-template-columns: 1fr;
    }
}

/* Share your voyage — 2-up story cards + a centred GitHub-stars rating
   strip below. Rating strip is a distinct full-width panel so the live
   star count reads as social proof, not another card. */
.community-voyage {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
    margin-bottom: 32px;
}
.community-voyage-card {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 24px;
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.community-section-alt .community-voyage-card {
    background: var(--bg);
}
.community-voyage-card-icon {
    width: 32px;
    height: 32px;
    color: var(--accent);
    margin-bottom: 4px;
}
.community-voyage-card-icon svg {
    width: 100%;
    height: 100%;
}
.community-voyage-card h3 {
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
    margin: 0;
}
.community-voyage-card p {
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--text-secondary);
    margin: 0;
}
.community-voyage-card-link {
    margin-top: auto;
    padding-top: 8px;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--accent);
    text-decoration: none;
    align-self: flex-start;
    transition: color 0.15s, transform 0.15s;
}
.community-voyage-card-link:hover {
    color: var(--accent-hover);
    transform: translateX(2px);
}

/* GitHub-stars rating strip */
.community-voyage-stars {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    padding: 28px 24px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    text-align: center;
}
.community-section-alt .community-voyage-stars {
    background: var(--bg);
}
.community-voyage-stars-display {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
    font-family: var(--font-sans);
}
.community-voyage-stars-icon {
    width: 32px;
    height: 32px;
    color: var(--warning);
    align-self: center;
}
.community-voyage-stars-count {
    font-size: 2.5rem;
    font-weight: 800;
    letter-spacing: -0.02em;
    color: var(--text);
    font-variant-numeric: tabular-nums;
    line-height: 1;
}
.community-voyage-stars-label {
    font-size: 0.9375rem;
    color: var(--text-secondary);
    font-weight: 500;
}
.community-voyage-stars-prompt {
    max-width: 520px;
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--text-secondary);
    /* Balance line lengths so the rhythmic triad 'Adds up / weight /
       yours' doesn't land at an awkward break point. The nbsp inside
       each 'Adds X' phrase keeps those two-word units together too. */
    text-wrap: balance;
}
.community-voyage-stars-btn {
    margin-top: 4px;
}
@media (max-width: 760px) {
    .community-voyage {
        grid-template-columns: 1fr;
    }
    .community-voyage-stars-display {
        flex-wrap: wrap;
        justify-content: center;
    }
}

/* ------------------------------------------------------------------
   View-transition theme toggle
   ------------------------------------------------------------------
   Chromium's View Transitions API lets us animate the whole document
   as a cross-fade between the "before" and "after" snapshots. We
   customise the new snapshot so it wipes in as an expanding circle
   anchored at --theme-transition-x/y (set by main.js to the theme
   button's centre), the canonical modern theme-switch look used by
   deepwiki and vercel.com. The old snapshot stays visible underneath
   until the wipe is complete so there's no flash of un-themed content.
   Browsers without the API fall back to an instant swap (no opt-in
   CSS fires on them).
-------------------------------------------------------------------*/
::view-transition-old(root),
::view-transition-new(root) {
    /* Neutralise the default cross-fade — we replace it with a clip
       animation below on the incoming snapshot only. */
    animation: none;
    mix-blend-mode: normal;
}

::view-transition-old(root) {
    /* The outgoing snapshot stays put. The incoming one reveals on
       top of it via clip-path, so the transition looks like the new
       theme "painting over" the old one from the click point. */
    z-index: 0;
}

::view-transition-new(root) {
    z-index: 1;
    /* 900 ms is long enough that the circular wipe is visible on
       desktop monitors (550 ms felt "did something happen?"-fast
       on wider screens), still under a second so the page never
       feels held up. */
    animation: bowire-theme-reveal 900ms cubic-bezier(0.22, 0.61, 0.36, 1);
}

@keyframes bowire-theme-reveal {
    from {
        clip-path: circle(0% at var(--theme-transition-x, 50%) var(--theme-transition-y, 0%));
    }
    to {
        /* 150vmax reaches every corner on every aspect ratio — any
           smaller and landscape monitors show a visible trailing
           edge before the animation finishes. */
        clip-path: circle(150vmax at var(--theme-transition-x, 50%) var(--theme-transition-y, 0%));
    }
}

/* Motion-sensitive users get an instant swap instead of the reveal. */
@media (prefers-reduced-motion: reduce) {
    ::view-transition-new(root) {
        animation: none;
    }
}

/* ============================================================
   Quickstart stepper — "Straight into the water"
   Three-step interactive launch path. Step 1 picks the persona
   ("boat"), step 2 shows the install command, step 3 the run
   command (with optional URL substitution).
   ============================================================ */

.launch {
    /* Matches the 100px top padding every other landing-page section
       uses (.usp, .protocols, .use-cases, …) so the sticky header
       doesn't sit closer to "Straight into the water" than to its
       siblings when a nav-anchor click scrolls here. */
    padding: 100px 0 48px;
    background: var(--bg);
}

.launch .section-title {
    text-align: center;
}

.launch .section-subtitle {
    text-align: center;
    margin-bottom: 36px;
}

.launch-stepper {
    max-width: 880px;
    margin: 0 auto;
}

/* Step indicators row — three numbered circles + connectors. */
.launch-steps {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0;
    margin-bottom: 32px;
}

.launch-step {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    background: transparent;
    border: none;
    cursor: pointer;
    font-family: inherit;
    color: var(--text-muted, #8a8aa0);
    transition: color 0.18s ease;
}

.launch-step[aria-disabled="true"] {
    cursor: not-allowed;
    opacity: 0.55;
}

.launch-step:not([aria-disabled="true"]):hover {
    color: var(--text, #e8e8f0);
}

.launch-step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--bg-elevated);
    border: 1.5px solid var(--border, #2a2a3a);
    font-weight: 600;
    font-size: 14px;
    transition: all 0.18s ease;
}

.launch-step.active .launch-step-num {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.18);
}

.launch-step.completed .launch-step-num {
    background: #10b981; /* green-500 — clearly distinct from the active accent */
    border-color: #10b981;
    color: #fff;
}

/* Replace the digit with a checkmark on completed steps. The digit
   sits in a nested span we can hide; the parent's ::after carries
   the check so it inherits colour + size from the circle. */
.launch-step.completed .launch-step-num-digit {
    display: none;
}

.launch-step.completed .launch-step-num::after {
    content: "✓";
    font-size: 16px;
    line-height: 1;
}

.launch-step.completed .launch-step-label {
    color: #10b981;
}

.launch-step-connector.completed {
    background: #10b981;
}

.launch-step-label {
    font-size: 14px;
    font-weight: 500;
}

.launch-step.active .launch-step-label {
    color: var(--text, #e8e8f0);
}

.launch-step-connector {
    flex: 0 0 60px;
    height: 2px;
    background: var(--border, #2a2a3a);
    margin: 0 4px;
    transition: background 0.18s ease;
}

/* Panel slots — only the active panel is rendered visually. */
.launch-panel {
    display: none;
    animation: launch-fade-in 0.22s ease;
}

.launch-panel.active {
    display: block;
}

@keyframes launch-fade-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0); }
}

.launch-prompt {
    text-align: center;
    color: var(--text-muted, #8a8aa0);
    margin-bottom: 24px;
    font-size: 15px;
}

/* Boat picker — 4 cards in a 2x2 / 4x1 grid. */
.launch-boats {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 14px;
}

@media (min-width: 760px) {
    .launch-boats {
        grid-template-columns: repeat(4, 1fr);
    }
}

.launch-boat {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    padding: 18px 16px;
    background: var(--bg-elevated);
    border: 1.5px solid var(--border, #2a2a3a);
    border-radius: 10px;
    cursor: pointer;
    text-align: left;
    transition: all 0.18s ease;
    color: inherit;
    font-family: inherit;
}

.launch-boat:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(99, 102, 241, 0.12);
}

.launch-boat.selected {
    border-color: var(--accent);
    background: linear-gradient(135deg, var(--bg-elevated), rgba(99, 102, 241, 0.08));
    box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.25);
}

.launch-boat-icon {
    color: var(--accent);
    line-height: 0;
}

.launch-boat-mode {
    margin: 0;
    font-size: 15px;
    font-weight: 600;
    color: var(--text, #e8e8f0);
    line-height: 1.3;
}

.launch-boat-title {
    margin: 0;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    /* --accent (#6366f1) on the launch-boat tile bg falls a hair below
       the WCAG AA contrast threshold for small text. --accent-light
       is the same hue, lifted just enough to pass both light and dark
       mode against the surrounding tile chrome. */
    color: var(--accent-light);
    font-weight: 600;
}

.launch-boat-desc {
    margin: 0;
    font-size: 13px;
    line-height: 1.45;
    color: var(--text-muted, #8a8aa0);
}

/* Protocol picker on step 2 — only shown when the boat needs the
   user to add protocol plugins separately (backend embedded mode).
   Each checked box adds one line to the install snippet below. */
.launch-protocols {
    margin: 0 0 18px;
    padding: 14px 16px;
    background: var(--bg-elevated);
    border: 1px solid var(--border, #2a2a3a);
    border-radius: 8px;
}

.launch-protocols-label {
    margin: 0 0 10px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted, #8a8aa0);
    font-weight: 600;
}

.launch-protocols-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 6px 14px;
}

.launch-protocol {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    font-size: 13px;
    color: var(--text, #e8e8f0);
    user-select: none;
}

.launch-protocol input[type="checkbox"] {
    width: 14px;
    height: 14px;
    accent-color: var(--accent);
    cursor: pointer;
}

.launch-protocol:hover {
    color: var(--accent);
}

.launch-protocol-hint {
    color: var(--text-muted, #8a8aa0);
    font-size: 11px;
    margin-left: 4px;
}

/* Search-combobox host — single-line input, selected protocols
   render as removable tags inside, suggestions drop down below. */
.launch-combobox-host {
    position: relative;
}

.launch-combobox {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    align-items: center;
    padding: 8px 10px;
    background: var(--bg);
    border: 1.5px solid var(--border, #2a2a3a);
    border-radius: 8px;
    cursor: text;
    transition: border-color 0.18s ease;
}

.launch-combobox.focused {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
}

.launch-combobox-tag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 4px 3px 10px;
    background: var(--accent);
    color: #fff;
    border-radius: 14px;
    font-size: 12px;
    font-weight: 500;
}

.launch-combobox-tag-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.18);
    color: #fff;
    cursor: pointer;
    font-size: 13px;
    line-height: 1;
    padding: 0;
}

.launch-combobox-tag-remove:hover {
    background: rgba(255, 255, 255, 0.32);
}

.launch-combobox-input {
    flex: 1 1 120px;
    min-width: 80px;
    border: none;
    outline: none;
    background: transparent;
    color: var(--text, #e8e8f0);
    font-family: inherit;
    font-size: 13px;
    padding: 4px 0;
}

.launch-combobox-input::placeholder {
    color: var(--text-muted, #8a8aa0);
}

.launch-combobox-suggestions {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    margin: 0;
    padding: 4px;
    list-style: none;
    background: var(--bg-elevated);
    border: 1px solid var(--border, #2a2a3a);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
    max-height: 280px;
    overflow-y: auto;
    z-index: 30;
    /* Theme the scrollbar so dark mode doesn't show a Windows-default
       light-grey track. Firefox honours scrollbar-color directly;
       WebKit/Blink need the explicit pseudo-element rules below. */
    scrollbar-width: thin;
    scrollbar-color: var(--border, #2a2a3a) transparent;
}

.launch-combobox-suggestions::-webkit-scrollbar {
    width: 8px;
}

.launch-combobox-suggestions::-webkit-scrollbar-track {
    background: transparent;
}

.launch-combobox-suggestions::-webkit-scrollbar-thumb {
    background: var(--border, #2a2a3a);
    border-radius: 4px;
}

.launch-combobox-suggestions::-webkit-scrollbar-thumb:hover {
    background: var(--text-muted, #8a8aa0);
}

.launch-combobox-suggestion {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 8px 12px;
    cursor: pointer;
    border-radius: 5px;
    transition: background 0.12s ease;
}

.launch-combobox-suggestion:hover,
.launch-combobox-suggestion.active {
    background: rgba(99, 102, 241, 0.14);
}

.launch-combobox-suggestion-name {
    font-size: 13px;
    font-weight: 600;
    color: var(--text, #e8e8f0);
}

.launch-combobox-suggestion-hint {
    font-size: 11px;
    color: var(--text-muted, #8a8aa0);
    line-height: 1.4;
}

.launch-combobox-empty {
    padding: 10px 12px;
    font-size: 12px;
    color: var(--text-muted, #8a8aa0);
    text-align: center;
}

/* Step 3 setup notes — per-protocol "you also need to wire this up"
   bullet list. Backend boat only; CLI boats hide it. */
.launch-setup-notes {
    margin: 0 0 18px;
    padding: 14px 16px;
    background: var(--bg-elevated);
    border-left: 3px solid var(--accent);
    border-radius: 4px;
}

.launch-setup-notes-label {
    margin: 0 0 8px;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted, #8a8aa0);
    font-weight: 600;
}

.launch-setup-notes-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.launch-setup-notes-list li {
    font-size: 13px;
    line-height: 1.5;
    color: var(--text, #e8e8f0);
}

.launch-setup-notes-list li strong {
    color: var(--accent);
    font-weight: 600;
}

.launch-setup-notes-list code {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 12px;
    background: rgba(99, 102, 241, 0.12);
    padding: 1px 6px;
    border-radius: 3px;
}

.launch-setup-notes-list a {
    color: var(--accent);
    margin-left: 6px;
    font-size: 12px;
    text-decoration: none;
}

.launch-setup-notes-list a:hover {
    text-decoration: underline;
}

/* Recipe code-blocks reuse the existing .code-block styling — only
   the per-step margin/width tweak is local. */
.launch-recipe {
    margin: 0 0 18px;
}

/* Optional URL input above the run command. */
.launch-url-row {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 14px;
}

.launch-url-label {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted, #8a8aa0);
    font-weight: 600;
}

.launch-url-input {
    padding: 10px 12px;
    background: var(--bg-elevated);
    border: 1.5px solid var(--border, #2a2a3a);
    border-radius: 8px;
    color: var(--text, #e8e8f0);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 13px;
    transition: border-color 0.18s ease;
}

.launch-url-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.15);
}

.launch-then {
    margin: 12px 0 18px;
    padding: 10px 14px;
    background: var(--bg-elevated);
    border-left: 3px solid var(--accent);
    border-radius: 4px;
    font-size: 13px;
    color: var(--text-muted, #8a8aa0);
}

.launch-then a {
    color: var(--accent);
}

.launch-then code {
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 12px;
    background: rgba(99, 102, 241, 0.12);
    padding: 1px 6px;
    border-radius: 3px;
    color: var(--text, #e8e8f0);
}

/* Back / Next / Restart row at the bottom of steps 2 + 3. */
.launch-nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 8px;
}

.launch-nav-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 8px 16px;
    background: var(--bg-elevated);
    border: 1.5px solid var(--border, #2a2a3a);
    border-radius: 8px;
    cursor: pointer;
    font-family: inherit;
    font-size: 14px;
    color: var(--text, #e8e8f0);
    transition: all 0.18s ease;
}

.launch-nav-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.launch-nav-next {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.launch-nav-next:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: #fff;
}

.launch-nav-next:disabled,
.launch-nav-next[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
}

@media (prefers-reduced-motion: reduce) {
    .launch-panel,
    .launch-boat,
    .launch-step,
    .launch-nav-btn,
    .launch-step-num,
    .launch-url-input {
        animation: none !important;
        transition: none !important;
    }
}

/* ==========================================================
   Theme-aware screenshots — paired <img>/<video> elements,
   one for dark and one for light. The site theme attribute
   on <html> hides the wrong one. Using `display:none` keeps
   layout calc cheap; modern browsers also skip fetching the
   hidden <img> when `loading="lazy"` is set.
   ========================================================== */
:root[data-theme="dark"] .theme-img-light,
:root[data-theme="dark"] .theme-video-light {
    display: none !important;
}
:root[data-theme="light"] .theme-img-dark,
:root[data-theme="light"] .theme-video-dark {
    display: none !important;
}
@media (prefers-color-scheme: dark) {
    :root[data-theme="auto"] .theme-img-light,
    :root[data-theme="auto"] .theme-video-light,
    :root:not([data-theme]) .theme-img-light,
    :root:not([data-theme]) .theme-video-light {
        display: none !important;
    }
}
@media (prefers-color-scheme: light) {
    :root[data-theme="auto"] .theme-img-dark,
    :root[data-theme="auto"] .theme-video-dark,
    :root:not([data-theme]) .theme-img-dark,
    :root:not([data-theme]) .theme-video-dark {
        display: none !important;
    }
}
