/* OpenSolo marketing page — modern indie macOS aesthetic with subtle Aqua
   nods (gel pulse-dot, glassy tooltip, one highlight on the primary button).
   Light + dark via prefers-color-scheme. The feature visuals carry the
   `.is-playing` class straight from the server-rendered HTML; that's what
   gates every keyframe. JS only removes/re-adds the class for the replay
   button — animations don't depend on JS to play in the first place. */

:root {
    color-scheme: light dark;

    /* Surfaces */
    --os-bg: #fdfdfd;
    --os-surface: #ffffff;
    --os-surface-sunken: #f5f5f7;
    --os-border: rgba(0, 0, 0, 0.08);
    --os-border-strong: rgba(0, 0, 0, 0.14);
    --os-shadow-soft: 0 1px 2px rgba(0, 0, 0, 0.04), 0 8px 24px rgba(0, 0, 0, 0.06);
    --os-shadow-card: 0 1px 2px rgba(0, 0, 0, 0.06), 0 1px 1px rgba(0, 0, 0, 0.04);

    /* Type */
    --os-text: #1d1d1f;
    --os-text-soft: #515156;
    --os-text-faint: #86868b;

    /* Accent — purple matches the brtdv.com signature, green is the
       live/running dot we use throughout the OpenSolo sidebar. */
    --os-accent: #5a3aee;
    --os-accent-strong: #4226d9;
    --os-live: #34c759;
    --os-warn: #ff9f0a;

    /* Flat status dot — matches how OpenSolo itself renders pane status. The
       sonar halo (animated box-shadow) does the "live" signalling, not a
       glossy fill. */
}

@media (prefers-color-scheme: dark) {
    :root {
        --os-bg: #0a0a0c;
        --os-surface: #16161a;
        --os-surface-sunken: #0e0e10;
        --os-border: rgba(255, 255, 255, 0.08);
        --os-border-strong: rgba(255, 255, 255, 0.14);
        --os-shadow-soft: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 32px rgba(0, 0, 0, 0.5);
        --os-shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4), 0 0 0 0.5px rgba(255, 255, 255, 0.05);

        --os-text: #f5f5f7;
        --os-text-soft: #c7c7cc;
        --os-text-faint: #8e8e93;

        --os-accent: #8b6dff;
        --os-accent-strong: #a48cff;
    }
}

/* Container + general typography for the OpenSolo page. Wider than the
   default brtdv.com 640px so the side-by-side feature rows have room. */
.os-page {
    background: var(--os-bg);
    color: var(--os-text);
    padding-bottom: 96px;
    /* SF Pro stack — falls through to the local system font on every Apple
       platform, then to good cross-platform substitutes. */
    font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro",
        "Helvetica Neue", Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
}

.os-container {
    max-width: 960px;
    margin: 0 auto;
    padding: 0 24px;
}

/* Hero ---------------------------------------------------------------- */

.os-hero {
    padding: 64px 0 48px;
    text-align: center;
}

.os-hero h1 {
    font-size: 42px;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 24px 0 8px;
    color: var(--os-text);
}

.os-hero p.tagline {
    font-size: 17px;
    color: var(--os-text-soft);
    max-width: 460px;
    margin: 0 auto;
    line-height: 1.5;
}

.os-hero img.icon {
    /* The app-icon PNG already carries its own squircle mask and integrated
       shadow, so we render it bare — no extra rounding, no extra shadow.
       Larger than the original 128px since it's the hero element. Block +
       auto margins centres it horizontally even when text-align on a
       parent isn't enough (e.g. nested flex layouts). */
    display: block;
    margin: 0 auto;
    width: 192px;
    height: 192px;
}

.os-cta {
    margin-top: 28px;
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
}

/* Hero dock — a pill-shaped row that groups one or more icon buttons next
   to the primary CTA. Background sits on a vibrancy-like surface; each
   inner element keeps its own subtle border so the dividing lines read
   like macOS toolbar segments. */
.os-dock {
    margin: 28px auto 0;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px;
    background: rgba(255, 255, 255, 0.7);
    backdrop-filter: blur(20px) saturate(160%);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    border: 1px solid var(--os-border);
    border-radius: 999px;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.04),
        0 8px 24px rgba(0, 0, 0, 0.06);
}

@media (prefers-color-scheme: dark) {
    .os-dock {
        background: rgba(36, 36, 40, 0.7);
        border-color: rgba(255, 255, 255, 0.08);
        box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px rgba(0, 0, 0, 0.4);
    }
}

.os-dock-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border-radius: 999px;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    color: var(--os-text-soft);
    text-decoration: none;
    transition: background 0.12s ease, color 0.12s ease, transform 0.12s ease;
}

.os-dock-icon:hover {
    color: var(--os-accent);
    background: var(--os-surface);
    transform: translateY(-1px);
}

.os-dock-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 16px;
    height: 38px;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 999px;
    color: var(--os-accent);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
    transition: background 0.12s ease, transform 0.12s ease;
}

.os-dock-cta:hover {
    background: rgba(90, 58, 238, 0.06);
    transform: translateY(-1px);
}

.os-dock-cta:active {
    transform: translateY(0);
}

/* Inline keyboard key — same accent as the CTA text, filled chip so it
   reads as a key cap. Subtle inset top-highlight (the one nod) signals
   "press me". */
.os-dock-cta kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 5px;
    background: var(--os-accent);
    color: #fff;
    border-radius: 5px;
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.18);
}

.os-dock-meta {
    display: block;
    margin: 12px auto 0;
    color: var(--os-text-faint);
    font-size: 13px;
}

/* App preview -------------------------------------------------------- */

/* Full-width window mockup that shows OpenSolo as the user would actually
   launch it: project list on the left with the active project expanded,
   a Claude pane running on the right. Sits between the hero and the
   feature deep-dives so the reader gets a "what is this thing" snapshot
   before we zoom into individual surfaces. */
.os-preview {
    padding: 16px 0 112px;
    border-bottom: 1px solid var(--os-border);
    margin-bottom: 112px;
}

.os-app {
    border-radius: 14px;
    overflow: hidden;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.05),
        0 24px 56px -16px rgba(0, 0, 0, 0.18),
        0 8px 24px -8px rgba(0, 0, 0, 0.08);
}

/* Split titlebar — the left column lines up with the sidebar (traffic
   lights + small toolbar buttons), the right column carries the active
   pane title and stats. A vertical divider sits at the column boundary
   so it reads like a real macOS unified titlebar / source-list pairing. */
.os-app-titlebar {
    display: grid;
    grid-template-columns: 331px 1fr;
    height: 40px;
    background: linear-gradient(to bottom, #f7f7f9, #efeff2);
    border-bottom: 1px solid var(--os-border);
}

@media (prefers-color-scheme: dark) {
    .os-app-titlebar {
        background: linear-gradient(to bottom, #2a2a2e, #232327);
        border-bottom-color: rgba(255, 255, 255, 0.06);
    }
}

.os-app-tb-left {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 0 14px;
    border-right: 1px solid var(--os-border);
}

.os-app-tb-right {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 0 14px;
    min-width: 0;
}

.os-app-tb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: var(--os-text-faint);
    cursor: default;
    transition: background 0.1s ease, color 0.1s ease;
}

.os-app-tb-btn:hover {
    background: rgba(0, 0, 0, 0.06);
    color: var(--os-text);
}

@media (prefers-color-scheme: dark) {
    .os-app-tb-btn:hover { background: rgba(255, 255, 255, 0.06); }
}

.os-app-dots {
    display: inline-flex;
    gap: 8px;
    margin-right: 4px;
}

.os-app-dot {
    width: 12px;
    height: 12px;
    border-radius: 999px;
    background: var(--os-border-strong);
}

.os-app-dot.is-close { background: #ff5f57; }
.os-app-dot.is-min   { background: #febc2e; }
.os-app-dot.is-max   { background: #28c840; }

.os-app-title {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    font-weight: 500;
    color: var(--os-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.os-app-stats {
    color: var(--os-text-faint);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.os-app-body {
    display: grid;
    grid-template-columns: 331px 1fr;
    min-height: 560px;
}

@media (max-width: 720px) {
    .os-app-body { grid-template-columns: 1fr; }
    .os-app-pane { border-top: 1px solid var(--os-border); }
}

/* Sidebar column ----------------------------------------------------- */

.os-app-sidebar {
    /* Slightly warmer than --os-surface-sunken to match the macOS sidebar
       vibrancy tone (which sits between window-content and full vibrancy). */
    background: #ebebed;
    border-right: 1px solid var(--os-border);
    padding: 6px 0 14px;
    font-size: 13px;
    color: var(--os-text);
    /* Bound the sidebar so reveals during the hero timeline scroll inside it
       instead of growing the mockup and shoving the page down. */
    max-height: 560px;
    overflow-y: auto;
    min-height: 0;
}

@media (prefers-color-scheme: dark) {
    .os-app-sidebar { background: #1c1c1f; }
}

/* Native NSSearchField look: rounded rect, vibrancy-tinted fill, faint
   border, magnifier on the left, and a section-filter button on the
   right (mirrors OpenSolo's sidebar filter affordance). */
/* Row that holds the search box + filter button as separate units.
   Real macOS source-list filter places the chip button OUTSIDE the
   search field so the two read as siblings, not one composite. */
.os-app-search-row {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: 8px 12px 12px;
}

.os-app-search {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 1px 10px;
    background: rgba(0, 0, 0, 0.04);
    border: 0.5px solid rgba(0, 0, 0, 0.1);
    border-radius: 7px;
    color: var(--os-text-faint);
    font-size: 13px;
}

@media (prefers-color-scheme: dark) {
    .os-app-search {
        background: rgba(255, 255, 255, 0.06);
        border-color: rgba(255, 255, 255, 0.08);
    }
}

.os-app-search-icon { flex-shrink: 0; }
.os-app-search-placeholder { flex: 1; }

/* Standalone filter button — sibling of the search field, not inside
   it. Sized roughly square (~28px) so it visually balances the height
   of the search input next to it. */
.os-app-filter-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    border-radius: 5px;
    background: transparent;
    color: var(--os-text-faint);
    cursor: default;
}

.os-app-filter-btn:hover {
    background: rgba(0, 0, 0, 0.06);
    color: var(--os-text);
}

.os-app-project {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 4px 12px;
    color: var(--os-text);
    font-weight: 700;
    font-size: 13px;
    height: 26px;
}

.os-app-twist {
    color: var(--os-text-faint);
    font-size: 8px;
    width: 8px;
    text-align: center;
    flex-shrink: 0;
    opacity: 0.7;
}

/* macOS Finder folder icon — one continuous shape (the tab slopes
   smoothly into the body, not two stacked rectangles). The shape comes
   from an SVG mask; the gradient lives on `background` so per-project
   tints just change the fill. `drop-shadow` respects the mask outline
   so the shadow follows the folder contour. */
/* Native Finder folder: tab takes ~60% of the folder width, slopes
   smoothly down on its right edge to meet the body's top. Single
   continuous SVG path; the gradient lives on `background` so per-project
   tints just swap the fill. */
.os-app-folder {
    display: inline-block;
    width: 16px;
    height: 13px;
    flex-shrink: 0;
    background: linear-gradient(to bottom, #8cc3f7 0%, #4596ed 100%);
    -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 13'><path d='M1.2 0H7.6Q8.6 0 9.1 0.8L9.6 1.6H14.8Q16 1.6 16 2.8V11.8Q16 13 14.8 13H1.2Q0 13 0 11.8V1.2Q0 0 1.2 0Z'/></svg>") no-repeat center / contain;
            mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 13'><path d='M1.2 0H7.6Q8.6 0 9.1 0.8L9.6 1.6H14.8Q16 1.6 16 2.8V11.8Q16 13 14.8 13H1.2Q0 13 0 11.8V1.2Q0 0 1.2 0Z'/></svg>") no-repeat center / contain;
    filter: drop-shadow(0 0.5px 0.5px rgba(0, 0, 0, 0.2));
}

/* Per-project tint — only when the project has a custom Finder folder
   colour. Default stays macOS-standard blue. */
.os-app-folder.is-web   { background: linear-gradient(to bottom, #8acaff, #4aa0ef); }
.os-app-folder.is-tools { background: linear-gradient(to bottom, #b8aaf0, #8770d8); }
.os-app-folder.is-brtdv { background: linear-gradient(to bottom, #f5a8bb, #e07c95); }

.os-app-project-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Section header — chevron + bold uppercase label + count. Indented
   under the project; mirrors OpenSolo's three-tier hierarchy. Tighter
   typography to match native NSOutlineView group rows. */
.os-app-section {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 12px 2px 22px;
    height: 22px;
    color: var(--os-text-faint);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

/* Sections beyond the first one in a project get a small top gap so the
   COMMANDS / TERMINALS labels visually break from the previous Add row. */
.os-app-add + .os-app-section { margin-top: 4px; }

.os-app-section-label { flex: 1; }
.os-app-count { font-variant-numeric: tabular-nums; font-weight: 500; }

/* Pane row — selected state mirrors a focused macOS source-list row:
   solid system-blue fill, white text, white-ish secondary text. macOS
   default accent is blue regardless of the user's chosen app accent, so
   this stays true to native even though OpenSolo's brand accent is purple. */
.os-app-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 10px 0 32px;
    margin: 0 6px;
    border-radius: 5px;
    color: var(--os-text);
    font-size: 13px;
    height: 24px;
}

/* Solid macOS system-accent fill for the focused source-list row, with
   white text. The exact hue is the default macOS accent ("Blue"); the
   user's chosen system accent would tint differently in the real app. */
.os-app-row.is-selected {
    background: #007aff;
    color: #fff;
}

.os-app-row.is-selected .os-app-mem { color: rgba(255, 255, 255, 0.78); }

.os-app-row.is-sub {
    padding-left: 50px;
    color: var(--os-text-soft);
    position: relative;
}

/* `is-sub` declares its own dim color, which would otherwise beat the
   selected-row white because both selectors have equal specificity and
   is-sub comes later in source order. Reassert white for sub rows that
   are themselves selected (the active task-spawned run, for example). */
.os-app-row.is-sub.is-selected { color: #fff; }

/* Second-level indent — ticket sub-panes spawned by a task run.
   Multiple siblings read as a connected tree (one continuous vertical
   line with horizontal arms branching to each row), not as floating
   L's. ::before is the vertical guide (full row height so siblings
   stack into one line), ::after is the horizontal arm at row centre.
   Selectors include `.is-sub.is-sub-2` (3 classes) so they outweigh
   the generic `.os-app-row.is-sub::before` rule defined later in
   this file — without that, the older L-elbow leaks through. */
.os-app-row.is-sub-2 { padding-left: 68px; }

.os-app-row.is-sub.is-sub-2::before {
    content: "";
    position: absolute;
    /* Aligned under the parent run's pulse-dot centre (dot starts at
       padding-left:50, width 9 → centre ≈ 54). */
    left: 54px;
    top: 0;
    width: 1px;
    height: 100%;
    background: var(--os-border-strong);
    border: none;
    border-radius: 0;
}

.os-app-row.is-sub.is-sub-2::after {
    content: "";
    position: absolute;
    left: 54px;
    top: 50%;
    /* Reach close to the child's own pulse-dot at left:68 so the arm
       visually docks instead of dangling in mid-air. */
    width: 10px;
    height: 1px;
    background: var(--os-border-strong);
}

/* Last sibling — cap the vertical at row centre with a curve so the
   tree branch doesn't dangle past the group into the Add task row. */
.os-app-row.is-sub.is-sub-2:has(+ :not(.os-app-row.is-sub-2))::before {
    height: 50%;
    width: 10px;
    background: transparent;
    border-left: 1px solid var(--os-border-strong);
    border-bottom: 1px solid var(--os-border-strong);
    border-bottom-left-radius: 4px;
}

.os-app-row.is-sub.is-sub-2:has(+ :not(.os-app-row.is-sub-2))::after {
    display: none;
}

/* Rows that descend from a scheduled task (the active run + the sub-
   panes it spawned) read in blue to signal "this lineage was triggered
   by automation, not by you". Selected state still wins (white on
   blue). #2a5db0 matches the existing `.path` token in the terminal,
   so the two surfaces share a colour for machine-driven things. */
.os-app-row.is-task-child:not(.is-selected) {
    color: #2a5db0;
}
@media (prefers-color-scheme: dark) {
    .os-app-row.is-task-child:not(.is-selected) {
        color: #6cb3ff;
    }
}

.os-app-row.is-sub::before {
    content: "";
    position: absolute;
    left: 38px;
    top: 2px;
    width: 8px;
    height: 12px;
    border-left: 1px solid var(--os-border-strong);
    border-bottom: 1px solid var(--os-border-strong);
    border-bottom-left-radius: 4px;
}

.os-app-row-title {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.os-app-mem {
    color: var(--os-text-faint);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.os-app-row .os-spark {
    color: var(--os-accent);
    font-size: 11px;
}

/* Calendar glyph for scheduled-task rows — replaces the pulse-dot slot.
   Dim by default so the row reads as "configured" rather than "live". */
.os-app-task-icon {
    color: var(--os-text-faint);
    flex-shrink: 0;
}

.os-app-row.is-selected .os-app-task-icon { color: rgba(255, 255, 255, 0.9); }

.os-app-row.is-selected .os-spark { color: rgba(255, 255, 255, 0.92); }

/* Add row — circle-plus + dim label. Same indent as pane rows so it
   reads as a placeholder slot inside the section. */
.os-app-add {
    display: flex;
    align-items: center;
    gap: 7px;
    padding: 0 10px 0 32px;
    margin: 0 6px;
    color: var(--os-text-faint);
    font-size: 13px;
    height: 24px;
}

.os-app-add svg { flex-shrink: 0; opacity: 0.6; }

/* Terminal pane ------------------------------------------------------ */

.os-app-pane {
    background: var(--os-surface);
    color: var(--os-text);
    padding: 16px 20px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    line-height: 1.7;
    overflow: hidden;
    /* Pane has its own toolbar in the top-right corner (action icons +
       pid/mem/cpu readout). Positioning it absolutely keeps the term
       output at its full width without an extra header row pushing
       lines down. */
    position: relative;
}

/* Per-pane action icons (restart/stop/Reveal/Terminal/editor) — sit
   at the far right of the global titlebar, after the title + stats.
   They reuse `.os-app-tb-btn` for the chrome look. The wrapper just
   provides margin-left:auto behaviour via the parent grid. */
.os-pane-toolbar-actions {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    margin-left: auto;
}

.os-pane-stats {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: var(--os-text-faint);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.os-app-term { display: flex; flex-direction: column; }

.os-app-term-line {
    opacity: 0;
    transform: translateY(2px);
}

.os-app.is-playing .os-app-term-line {
    animation: os-line-in 0.3s ease forwards;
}

.os-app.is-playing .os-app-term-line.t1 { animation-delay: 0.10s; }
.os-app.is-playing .os-app-term-line.t2 { animation-delay: 0.40s; }
.os-app.is-playing .os-app-term-line.t3 { animation-delay: 0.70s; }
.os-app.is-playing .os-app-term-line.t4 { animation-delay: 0.80s; }
.os-app.is-playing .os-app-term-line.t5 { animation-delay: 1.10s; }
.os-app.is-playing .os-app-term-line.t6 { animation-delay: 1.20s; }
.os-app.is-playing .os-app-term-line.t7 { animation-delay: 1.60s; }
.os-app.is-playing .os-app-term-line.t8 { animation-delay: 2.00s; }
.os-app.is-playing .os-app-term-line.t9 { animation-delay: 2.40s; }

.os-app-term-line .dim    { color: var(--os-text-faint); }
.os-app-term-line .accent { color: var(--os-accent); }
.os-app-term-line .green  { color: #1f7a35; }
.os-app-term-line .kw     { color: var(--os-accent); }
.os-app-term-line .path   { color: #2a5db0; }

@media (prefers-color-scheme: dark) {
    .os-app-term-line .green { color: #5fd97c; }
    .os-app-term-line .path  { color: #6cb3ff; }
}

/* Light-mode caret needs a dark fill — the dark-pane caret default is too
   bright on this background. */
.os-app-pane .os-caret {
    background: var(--os-text-soft);
}

.os-app .os-pulse-dot.is-live {
    animation: os-pulse 2.4s ease-out infinite;
}

/* Pulse dots inside the preview sidebar sit alongside 13px text — bump
   them up from the default 8px so they read at the same weight as the
   native OpenSolo source-list status indicators. */
.os-app-sidebar .os-pulse-dot {
    width: 9px;
    height: 9px;
}

.os-app-row.is-selected .os-pulse-dot {
    /* `outline` instead of `box-shadow` so the live-pulse halo animation
       can still apply its own box-shadow keyframes underneath. */
    outline: 1px solid rgba(255, 255, 255, 0.85);
}

/* ---- Hero timeline player ------------------------------------------ */

/* Rows that the JS scene player reveals later start fully collapsed
   so the sidebar's initial frame still shows the OpenSolo Website /
   Sparkle Appcast / Mobile Companion / Design System projects below.
   The sidebar itself is bounded (`max-height` + `overflow-y: auto`),
   so revealing rows expands the source list inside its own scroll
   area without growing the mockup or shifting the page below. */
.os-app-row.is-hidden {
    height: 0;
    min-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    margin: 0;
    opacity: 0;
    overflow: hidden;
    pointer-events: none;
}

.os-app-row.is-revealing {
    animation: os-row-in 0.45s cubic-bezier(0.2, 0.7, 0.2, 1) both;
}

@keyframes os-row-in {
    0%   { opacity: 0; transform: translateX(-6px); }
    60%  { opacity: 1; }
    100% { opacity: 1; transform: translateX(0); }
}

/* Quick highlight flash when a brand-new row appears, so the reader's
   eye lands on the right place in the sidebar. */
.os-app-row.is-flashing {
    animation: os-row-flash 1.4s ease-out;
}

@keyframes os-row-flash {
    0%   { background: rgba(106, 153, 255, 0.0); }
    20%  { background: rgba(106, 153, 255, 0.32); }
    100% { background: rgba(106, 153, 255, 0.0); }
}

@media (prefers-color-scheme: dark) {
    @keyframes os-row-flash {
        0%   { background: rgba(108, 179, 255, 0.0); }
        20%  { background: rgba(108, 179, 255, 0.28); }
        100% { background: rgba(108, 179, 255, 0.0); }
    }
}

/* Three pulsing dots after "Thinking" — mimics the in-app reasoning
   indicator without spinning, which would be noisier than the rest of
   the mockup. */
.os-thinking-dots {
    display: inline-flex;
    gap: 3px;
    margin-left: 4px;
    vertical-align: 1px;
}

.os-thinking-dots span {
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: var(--os-text-soft);
    animation: os-think 1.2s infinite ease-in-out;
}
.os-thinking-dots span:nth-child(2) { animation-delay: 0.15s; }
.os-thinking-dots span:nth-child(3) { animation-delay: 0.30s; }

@keyframes os-think {
    0%, 80%, 100% { opacity: 0.25; transform: scale(0.85); }
    40%           { opacity: 1;    transform: scale(1.1); }
}

/* Titlebar text crossfade when the timeline jumps from "now" to the
   scheduled run; visually sells the time-skip without a hard cut. */
.os-app-title.is-warping,
.os-app-stats.is-warping,
.os-pane-stats.is-warping {
    animation: os-title-warp 0.7s ease both;
}

@keyframes os-title-warp {
    0%   { opacity: 1; filter: blur(0); }
    50%  { opacity: 0; filter: blur(2px); }
    100% { opacity: 1; filter: blur(0); }
}

/* The whole mockup dims briefly between loop cycles so the reset doesn't
   feel like a glitch. */
.os-app.is-fading {
    animation: os-app-fade 1.0s ease both;
}

@keyframes os-app-fade {
    0%   { opacity: 1; }
    50%  { opacity: 0.55; }
    100% { opacity: 1; }
}

/* Inline string-literal colour for MCP arg lines like `"Support triage"`. */
.os-app-term-line .str {
    color: #2a7a3a;
}
@media (prefers-color-scheme: dark) {
    .os-app-term-line .str { color: #7ed492; }
}

/* Feature rows -------------------------------------------------------- */

.os-features {
    padding: 32px 0 64px;
    display: flex;
    flex-direction: column;
    gap: 96px;
}

.os-feature {
    display: grid;
    grid-template-columns: 1fr;
    gap: 32px;
    align-items: start;
}

@media (min-width: 768px) {
    .os-feature {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
        gap: 56px;
    }
    .os-feature.is-reversed > .os-feature-text {
        order: 2;
    }
    .os-feature.is-reversed > .os-feature-visual {
        order: 1;
    }
}

.os-feature-text h2 {
    font-size: 26px;
    font-weight: 700;
    letter-spacing: -0.015em;
    margin: 0 0 12px;
    color: var(--os-text);
}

.os-feature-text p {
    font-size: 16px;
    line-height: 1.55;
    color: var(--os-text-soft);
    margin: 0 0 12px;
}

.os-feature-text p:last-child {
    margin-bottom: 0;
}

.os-feature-text .os-eyebrow {
    display: inline-block;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--os-accent);
    margin: 0 0 12px;
}

/* Feature visual frame ------------------------------------------------- */

.os-feature-visual {
    /* Just a positioning context for the replay button — each inner mockup
       (sidebar, window, inspector, tree) carries its own card chrome, so
       wrapping that in a second framed surface gave every visual a double
       border. */
    position: relative;
}

.os-feature-visual .os-replay {
    position: absolute;
    top: 12px;
    right: 12px;
    width: 28px;
    height: 28px;
    border-radius: 999px;
    border: 1px solid var(--os-border);
    background: var(--os-surface);
    color: var(--os-text-soft);
    font-size: 13px;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.15s ease;
    z-index: 2;
}

.os-feature-visual:hover .os-replay,
.os-feature-visual:focus-within .os-replay {
    opacity: 1;
}

.os-feature-visual .os-replay:hover {
    color: var(--os-accent);
    border-color: var(--os-accent);
}

/* Generic "mac window" chrome used in three of the four visuals. The dots
   are flat circles, not gel buttons — the Aqua nod stays in the pulse dot
   and the tooltip, not the window chrome. */
.os-window {
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 10px;
    overflow: hidden;
    font-size: 13px;
    line-height: 1.4;
}

.os-window-titlebar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--os-border);
    background: var(--os-surface-sunken);
}

.os-window-dots {
    display: inline-flex;
    gap: 6px;
}

.os-window-dot {
    width: 11px;
    height: 11px;
    border-radius: 999px;
    background: var(--os-border-strong);
}

.os-window-title {
    flex: 1;
    text-align: center;
    color: var(--os-text-faint);
    font-size: 12px;
    /* Pull title back to the centre by accounting for the dots width on the
       left. Without the offset the title looks left-leaning. */
    margin-right: 51px;
}

/* Flat status dot — matches how OpenSolo itself renders pane status. The
   sonar halo (animated box-shadow on the live variant) does the live signal,
   not a glossy fill. */
.os-pulse-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 999px;
    background: var(--os-text-faint);
    flex-shrink: 0;
}

.os-pulse-dot.is-live { background: var(--os-live); }
.os-pulse-dot.is-warn { background: var(--os-warn); }
.os-pulse-dot.is-idle { background: var(--os-border-strong); }

.is-playing .os-pulse-dot.is-live {
    animation: os-pulse 2.4s ease-out infinite;
}

@keyframes os-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(52, 199, 89, 0.35); }
    70%  { box-shadow: 0 0 0 6px rgba(52, 199, 89, 0); }
    100% { box-shadow: 0 0 0 0 rgba(52, 199, 89, 0); }
}

/* Visual 1 — Sidebar ------------------------------------------------- */

.v-sidebar .os-sidebar {
    background: var(--os-surface-sunken);
    border: 1px solid var(--os-border);
    border-radius: 12px;
    padding: 8px 0;
    font-size: 13px;
    overflow: hidden;
}

.v-sidebar .os-project-row {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    font-weight: 600;
    color: var(--os-text);
}

.v-sidebar .os-section-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 12px;
    color: var(--os-text-faint);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.v-sidebar .os-pane-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 12px 6px 26px;
    margin: 1px 6px;
    border-radius: 6px;
    color: var(--os-text);
    opacity: 0;
    transform: translateX(-4px);
}

/* Source-list selection chip — translucent accent fill on the active row,
   matching the macOS Finder/Mail sidebar look. */
.v-sidebar .os-pane-row.is-selected {
    background: rgba(90, 58, 238, 0.10);
    color: var(--os-text);
}

@media (prefers-color-scheme: dark) {
    .v-sidebar .os-pane-row.is-selected {
        background: rgba(139, 109, 255, 0.16);
    }
}

/* Animation runs as soon as `.is-playing` is on the parent visual. Since the
   class is set in the HTML by default, the keyframe fires on first paint;
   `forwards` pins the final state so nothing flips back when it ends. */
.v-sidebar.is-playing .os-pane-row {
    animation: os-row-in 0.35s ease forwards;
}

@keyframes os-row-in {
    from { opacity: 0; transform: translateX(-4px); }
    to   { opacity: 1; transform: translateX(0); }
}

/* Stagger via explicit r1..r5 classes — `:nth-of-type` would count every
   `<div>` sibling (section headers, project row) and skip past the actual
   pane rows. */
.v-sidebar.is-playing .os-pane-row.r1 { animation-delay: 0.10s; }
.v-sidebar.is-playing .os-pane-row.r2 { animation-delay: 0.20s; }
.v-sidebar.is-playing .os-pane-row.r3 { animation-delay: 1.20s; } /* sub-pane spawns later */
.v-sidebar.is-playing .os-pane-row.r4 { animation-delay: 0.30s; }
.v-sidebar.is-playing .os-pane-row.r5 { animation-delay: 0.40s; }
.v-sidebar.is-playing .os-pane-row.r6 { animation-delay: 0.50s; }

.v-sidebar .os-pane-row .os-pane-title {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.v-sidebar .os-pane-row .os-pane-mem {
    color: var(--os-text-faint);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

/* Task row — a definition, not a live pane. A calendar glyph takes the
   pulse-dot's slot and the cron schedule takes the memory readout's, so the
   row stays aligned with the pane rows above and below it. */
.v-sidebar .os-pane-row.is-task .os-task-glyph {
    color: var(--os-text-faint);
    flex-shrink: 0;
}

.v-sidebar .os-pane-row.is-task .os-pane-cron {
    color: var(--os-text-faint);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.v-sidebar .os-pane-row.is-sub {
    padding-left: 42px;
    color: var(--os-text-soft);
    position: relative;
}

/* Thin connector line — visually ties the sub-pane (spawned by its parent
   agent) back to the row above it. Sits in the gap left by the extra
   padding-left so it doesn't collide with the pulse dot. */
.v-sidebar .os-pane-row.is-sub::before {
    content: "";
    position: absolute;
    left: 30px;
    top: -1px;
    width: 8px;
    height: 50%;
    border-left: 1px solid var(--os-border-strong);
    border-bottom: 1px solid var(--os-border-strong);
    border-bottom-left-radius: 4px;
}

.v-sidebar .os-pane-row.is-sub .os-spark {
    color: var(--os-accent);
    font-size: 11px;
}

/* Visual 2 — Claude wired-up ---------------------------------------- */

/* Layered composition: the terminal window sits back, the MCP tools card
   pops forward from the bottom-right corner. Extra bottom padding gives
   the overlapping card room to breathe without clipping. */
.v-claude {
    position: relative;
    padding-bottom: 40px;
    padding-right: 16px;
    /* 3D context for the turntable loop. The two cards sit at fixed,
       opposite depths (window pushed back, tooltip pulled forward) and
       only the parent scene rotates around Y. Locking the depths means
       the cards never cross the same Z plane, so their overlapping 2D
       bounding boxes never clip into each other. */
    perspective: 1600px;
    transform-style: preserve-3d;
}

.v-claude.is-playing {
    animation: os-scene-turn 9s ease-in-out infinite;
    transform-origin: 50% 60%;
}

/* Gentle wobble of the whole scene. Each card sits at a different
   translateZ inside this container, so the rotation reveals real depth —
   the front card swings further than the back card and the gap between
   them never closes. */
@keyframes os-scene-turn {
    0%, 100% { transform: rotateY(-6deg) rotateX(1deg); }
    50%      { transform: rotateY(6deg)  rotateX(-1deg); }
}

@media (min-width: 768px) {
    .v-claude {
        padding-bottom: 60px;
        padding-right: 28px;
    }
}

.v-claude .os-window {
    position: relative;
    z-index: 1;
    /* Static tilt on `rotate`, depth lock on `transform`. Pushed back so
       the tooltip can sit forward in 3D space without ever colliding. */
    rotate: -0.6deg;
    transform: translateZ(-50px);
    transform-style: preserve-3d;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.06),
        0 12px 32px rgba(0, 0, 0, 0.08);
}

.v-claude .os-pane-mock {
    margin: 0;
    border-radius: 0 0 12px 12px;
    background: #0c0c0e;
    color: #d4d4d8;
    padding: 14px 16px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    line-height: 1.6;
    min-height: 150px;
    border: 1px solid var(--os-border);
}

.v-claude .os-pane-mock .line {
    opacity: 0;
    transform: translateY(2px);
}

.v-claude.is-playing .os-pane-mock .line {
    animation: os-line-in 0.3s ease forwards;
}

@keyframes os-line-in {
    from { opacity: 0; transform: translateY(2px); }
    to   { opacity: 1; transform: translateY(0); }
}

.v-claude.is-playing .os-pane-mock .line.l1 { animation-delay: 0.10s; }
.v-claude.is-playing .os-pane-mock .line.l2 { animation-delay: 0.50s; }
.v-claude.is-playing .os-pane-mock .line.l3 { animation-delay: 1.00s; }
.v-claude.is-playing .os-pane-mock .line.l4 { animation-delay: 1.40s; }

.v-claude .os-pane-mock .dim {
    color: #6e6e76;
}

.v-claude .os-pane-mock .accent {
    color: #a48cff;
}

.v-claude .os-pane-mock .green {
    color: #34c759;
}

/* Block caret at the end of the last line — same animation pattern as a
   real terminal cursor. Steps(2) makes it discrete on/off instead of
   fading, which is what Ghostty / Terminal.app render. */
.v-claude .os-caret {
    display: inline-block;
    width: 7px;
    height: 1em;
    margin-left: 3px;
    vertical-align: -2px;
    background: #d4d4d8;
    animation: os-caret-blink 1s steps(2, end) infinite;
}

@keyframes os-caret-blink {
    50% { opacity: 0; }
}

.v-claude .os-tooltip {
    /* Floating callout that overlaps the terminal from the bottom-right.
       Vibrancy + a stronger shadow lift it visually off the window behind.
       The slight rotation and offset is what makes the composition read as
       layered rather than stacked. */
    position: relative;
    z-index: 2;
    margin: -36px 0 0 auto;
    width: min(86%, 360px);
    padding: 14px 16px;
    background: rgba(245, 245, 247, 0.82);
    backdrop-filter: blur(20px) saturate(160%);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    border: 0.5px solid var(--os-border);
    border-radius: 12px;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.06),
        0 18px 40px rgba(0, 0, 0, 0.14);
    font-size: 12px;
    color: var(--os-text);
    opacity: 0;
    translate: 8px 12px;
    rotate: 1.2deg;
    transform-origin: top left;
}

@media (min-width: 768px) {
    .v-claude .os-tooltip {
        margin-top: -56px;
        translate: 16px 18px;
    }
}

@media (prefers-color-scheme: dark) {
    .v-claude .os-tooltip {
        background: rgba(36, 36, 40, 0.78);
        border-color: rgba(255, 255, 255, 0.08);
        box-shadow:
            0 1px 2px rgba(0, 0, 0, 0.5),
            0 18px 40px rgba(0, 0, 0, 0.55);
    }
}

.v-claude.is-playing .os-tooltip {
    animation: os-tooltip-in 0.5s cubic-bezier(0.2, 0.8, 0.2, 1) 1.8s forwards;
}

/* The tooltip is locked at +50px translateZ so it always sits in front
   of the window (which is at -50px). The lift-in animates `scale` only,
   leaving `transform` free to hold this static depth offset. */
.v-claude .os-tooltip {
    transform: translateZ(50px);
    transform-style: preserve-3d;
}

/* Using `scale` here (not `transform: scale`) so it composes with the
   static `translate` + `rotate` CSS properties instead of overriding them.
   That keeps the layered offset/rotation per breakpoint and only the
   tooltip's lift-in is animated. */
@keyframes os-tooltip-in {
    from { opacity: 0; scale: 0.97; }
    to   { opacity: 1; scale: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .v-claude.is-playing {
        animation: none;
    }
}

.v-claude .os-tooltip strong {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--os-text-faint);
    margin-bottom: 6px;
    font-weight: 600;
}

.v-claude .os-tooltip ul {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px 16px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: var(--os-text-soft);
}

.v-claude .os-tooltip ul li {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* The pulse-dot inside the tooltip needs to render smaller than in the
   sidebar — 11px monospace text looks oversized next to an 8px dot. */
.v-claude .os-tooltip .os-pulse-dot {
    width: 6px;
    height: 6px;
}

/* Visual 3 — Git inspector ------------------------------------------ */

.v-git .os-inspector {
    display: grid;
    grid-template-columns: 180px 1fr;
    height: 240px;
    background: var(--os-surface-sunken);
    border-radius: 12px;
    overflow: hidden;
    border: 1px solid var(--os-border);
    font-size: 12px;
}

.v-git .os-inspector .file-list {
    background: var(--os-surface);
    border-right: 1px solid var(--os-border);
    padding: 6px 0;
}

/* Match the row's 6px side inset with the same gap above the first row, so
   the selection chip floats symmetrically inside the file-list column
   instead of butting against the commit-head's border. */
.v-git .os-inspector .commit-head + .file-row {
    margin-top: 6px;
}

.v-git .os-inspector .file-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px 6px 12px;
    margin: 1px 6px;
    border-radius: 6px;
    color: var(--os-text);
    opacity: 0;
    transform: translateX(-4px);
    position: relative;
    white-space: nowrap;
}

.v-git.is-playing .file-row {
    animation: os-row-in 0.3s ease forwards;
}

.v-git.is-playing .file-row.r1 { animation-delay: 0.10s; }
.v-git.is-playing .file-row.r2 { animation-delay: 0.20s; }
.v-git.is-playing .file-row.r3 { animation-delay: 0.30s; }
.v-git.is-playing .file-row.r4 { animation-delay: 0.40s; }

/* Source-list selection chip plus Xcode-style left accent stripe. */
.v-git .file-row.selected {
    background: rgba(90, 58, 238, 0.10);
    color: var(--os-text);
}

.v-git .file-row.selected::before {
    content: "";
    position: absolute;
    left: -6px;
    top: 4px;
    bottom: 4px;
    width: 2px;
    border-radius: 1px;
    background: var(--os-accent);
}

@media (prefers-color-scheme: dark) {
    .v-git .file-row.selected {
        background: rgba(139, 109, 255, 0.16);
    }
}

/* File-status chip — small rounded badge with a colour matching the kind
   of change. M (modified) is a soft amber; future A/D/R would slot in
   alongside. */
.v-git .file-row .marker {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: 4px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 10px;
    font-weight: 600;
    flex-shrink: 0;
}

.v-git .file-row .marker.is-modified {
    background: rgba(255, 159, 10, 0.15);
    color: #b06200;
}

@media (prefers-color-scheme: dark) {
    .v-git .file-row .marker.is-modified { color: #ffb454; }
}

.v-git .file-row .name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    font-size: 12px;
}

.v-git .file-row .diff-counts {
    display: inline-flex;
    gap: 6px;
    font-size: 10px;
    color: var(--os-text-faint);
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

.v-git .file-row .diff-counts .plus { color: #34c759; font-weight: 600; }
.v-git .file-row .diff-counts .minus { color: #ff453a; font-weight: 600; }

.v-git .os-inspector .diff-pane {
    padding: 8px 0;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    line-height: 1.65;
    overflow: hidden;
    background: var(--os-surface);
}

.v-git .diff-line {
    display: grid;
    grid-template-columns: 32px 16px 1fr;
    align-items: baseline;
    column-gap: 6px;
    padding: 0 12px 0 0;
    opacity: 0;
    transform: translateY(2px);
}

.v-git .diff-line .ln {
    text-align: right;
    color: var(--os-text-faint);
    font-size: 10px;
    user-select: none;
}

.v-git .diff-line .sign {
    text-align: center;
    color: var(--os-text-faint);
    font-weight: 600;
}

.v-git .diff-line .code {
    white-space: pre;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Lightweight syntax tokens — purple keyword, blue type, dim argument
   label, orange number. Mirrors the Xcode "Default (Light)" theme. */
.v-git .diff-line .kw  { color: #8b3eaa; }
.v-git .diff-line .ty  { color: #2a5db0; }
.v-git .diff-line .arg { color: var(--os-text-soft); }
.v-git .diff-line .num { color: #c27300; }

@media (prefers-color-scheme: dark) {
    .v-git .diff-line .kw  { color: #d18ce2; }
    .v-git .diff-line .ty  { color: #6cb1ff; }
    .v-git .diff-line .num { color: #ffb454; }
}

.v-git.is-playing .diff-line {
    animation: os-line-in 0.3s ease forwards;
}

.v-git.is-playing .diff-line.d1 { animation-delay: 0.6s; }
.v-git.is-playing .diff-line.d2 { animation-delay: 0.8s; }
.v-git.is-playing .diff-line.d3 { animation-delay: 1.0s; }
.v-git.is-playing .diff-line.d4 { animation-delay: 1.2s; }
.v-git.is-playing .diff-line.d5 { animation-delay: 1.4s; }
.v-git.is-playing .diff-line.d6 { animation-delay: 1.6s; }

.v-git .diff-line.add {
    background: rgba(52, 199, 89, 0.10);
    color: #1f7a35;
}

@media (prefers-color-scheme: dark) {
    .v-git .diff-line.add { color: #5fd97c; }
    .v-git .diff-line.del { color: #ff7064; }
}

.v-git .diff-line.del {
    background: rgba(255, 69, 58, 0.10);
    color: #c1352a;
}

.v-git .diff-line.ctx {
    color: var(--os-text-soft);
}

.v-git .commit-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--os-border);
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    background: var(--os-surface);
}

.v-git .commit-head .hash {
    color: var(--os-text-faint);
}

.v-git .commit-head .age {
    margin-left: auto;
    color: var(--os-text-faint);
}

/* Visual 4 — Process tree cleanup ----------------------------------- */

.v-tree .tree {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 18px;
}

.v-tree .proc {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 8px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
}

.v-tree .proc .cmd {
    flex: 1;
    color: var(--os-text);
}

.v-tree .proc .pid {
    color: var(--os-text-faint);
}

.v-tree .proc .indent {
    width: 12px;
    height: 1px;
    background: var(--os-border-strong);
    flex-shrink: 0;
}

.v-tree .proc.depth-1 { margin-left: 18px; }
.v-tree .proc.depth-2 { margin-left: 36px; }
.v-tree .proc.depth-3 { margin-left: 54px; }

/* Continuous loop: alive → killed (staggered by depth) → restored. Keeps
   the visual full of content instead of fading to a single zsh row at the
   end. Each depth-class shifts the same keyframe by 5% — leaves go first,
   roots follow. */
.v-tree.is-playing .proc.is-dying {
    animation: os-proc-cycle 6s ease-in-out infinite;
}

@keyframes os-proc-cycle {
    0%, 35%   { opacity: 1; transform: translateX(0);  filter: blur(0); }
    50%       { opacity: 0; transform: translateX(8px); filter: blur(1px); }
    85%       { opacity: 0; transform: translateX(8px); filter: blur(1px); }
    100%      { opacity: 1; transform: translateX(0);  filter: blur(0); }
}

.v-tree.is-playing .proc.is-dying.d1 { animation-delay: 0s; }
.v-tree.is-playing .proc.is-dying.d2 { animation-delay: 0.15s; }
.v-tree.is-playing .proc.is-dying.d3 { animation-delay: 0.30s; }
.v-tree.is-playing .proc.is-dying.d4 { animation-delay: 0.45s; }

.v-tree .stop-banner {
    margin-top: 14px;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: 999px;
    background: rgba(255, 69, 58, 0.10);
    color: #c1352a;
    font-size: 12px;
    font-weight: 500;
    opacity: 0;
    transform: scale(0.96);
}

@media (prefers-color-scheme: dark) {
    .v-tree .stop-banner { color: #ff7064; }
}

.v-tree.is-playing .stop-banner {
    animation: os-banner-cycle 6s ease-in-out infinite;
}

/* Banner rides the same 6s loop as the procs: appears just before the kill,
   fades back out as everything restarts. */
@keyframes os-banner-cycle {
    0%, 20%   { opacity: 0; transform: scale(0.96); }
    30%, 75%  { opacity: 1; transform: scale(1); }
    90%, 100% { opacity: 0; transform: scale(0.96); }
}

/* Visual 5 — GitHub Projects board ---------------------------------- */

.v-board .os-board {
    background: var(--os-surface-sunken);
    border: 1px solid var(--os-border);
    border-radius: 12px;
    overflow: hidden;
    /* Positioning context for the label-picker popover, which sits over the
       In Progress column. */
    position: relative;
}

.v-board .os-board-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 9px 12px;
    border-bottom: 1px solid var(--os-border);
    background: var(--os-surface);
}

.v-board .os-board-name {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: 13px;
    font-weight: 600;
    color: var(--os-text);
}

.v-board .os-board-name svg { color: var(--os-text-faint); }

.v-board .os-board-filter {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 3px 9px;
    border: 1px solid var(--os-border);
    border-radius: 999px;
    background: var(--os-surface);
    color: var(--os-text-soft);
    font-size: 11px;
    cursor: default;
}

.v-board .os-board-cols {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    padding: 12px;
}

.v-board .os-board-col {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.v-board .os-board-col-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 2px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--os-text-faint);
}

.v-board .os-board-count { font-variant-numeric: tabular-nums; opacity: 0.8; }

.v-board .os-card {
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 8px;
    padding: 9px 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
    /* Cards start hidden and animate in; the reduced-motion block at the
       end of the file restores them for users who opt out. */
    opacity: 0;
    transform: translateY(4px);
}

.v-board.is-playing .os-card {
    animation: os-card-in 0.32s ease forwards;
}

.v-board.is-playing .os-card.k1 { animation-delay: 0.10s; }
.v-board.is-playing .os-card.k2 { animation-delay: 0.18s; }
.v-board.is-playing .os-card.k3 { animation-delay: 0.26s; }
.v-board.is-playing .os-card.k4 { animation-delay: 0.34s; }
.v-board.is-playing .os-card.k5 { animation-delay: 0.42s; }

@keyframes os-card-in {
    to { opacity: 1; transform: translateY(0); }
}

.v-board .os-card-title {
    margin: 0;
    font-size: 12px;
    line-height: 1.35;
    color: var(--os-text);
}

.v-board .os-card-meta {
    display: flex;
    align-items: center;
    gap: 6px;
}

.v-board .os-card-grow { flex: 1; }

/* GitHub-style label pills — translucent fill, saturated text, matching
   border, one hue per label kind. */
.v-board .os-label {
    font-size: 10px;
    font-weight: 600;
    padding: 1px 7px;
    border-radius: 999px;
    border: 1px solid transparent;
    white-space: nowrap;
}

.v-board .os-label.is-bug     { background: rgba(215, 58, 73, 0.12);  color: #c1352a; border-color: rgba(215, 58, 73, 0.3); }
.v-board .os-label.is-enh     { background: rgba(10, 126, 164, 0.12); color: #0a6c8e; border-color: rgba(10, 126, 164, 0.3); }
.v-board .os-label.is-feature { background: rgba(137, 87, 229, 0.14); color: #7b46d6; border-color: rgba(137, 87, 229, 0.32); }
.v-board .os-label.is-done    { background: rgba(31, 122, 53, 0.12);  color: #1f7a35; border-color: rgba(31, 122, 53, 0.3); }

@media (prefers-color-scheme: dark) {
    .v-board .os-label.is-bug     { color: #ff8077; }
    .v-board .os-label.is-enh     { color: #5cc2e8; }
    .v-board .os-label.is-feature { color: #b794ff; }
    .v-board .os-label.is-done    { color: #5fd97c; }
}

.v-board .os-card-comments {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 10px;
    color: var(--os-text-faint);
    font-variant-numeric: tabular-nums;
}

.v-board .os-avatar {
    width: 18px;
    height: 18px;
    border-radius: 999px;
    background: var(--av, var(--os-text-faint));
    color: #fff;
    font-size: 8px;
    font-weight: 700;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Ring in the card colour so overlapping avatars stay separable. */
    border: 1.5px solid var(--os-surface);
    flex-shrink: 0;
}

/* Overlap stacked avatars the way GitHub does. */
.v-board .os-avatar + .os-avatar { margin-left: -7px; }

/* Focused card — the keyboard-selection ring, mirroring the board's own
   focus state. */
.v-board .os-card.is-focused {
    border-color: var(--os-accent);
    box-shadow: 0 0 0 2px rgba(90, 58, 238, 0.18);
}

@media (prefers-color-scheme: dark) {
    .v-board .os-card.is-focused {
        box-shadow: 0 0 0 2px rgba(139, 109, 255, 0.28);
    }
}

/* Dragging card — lifts, tilts and settles on a loop to read as a card
   being moved between columns (the move GitHub then records). The keyframe
   overrides the entry transform, so it owns opacity once it takes over. */
.v-board.is-playing .os-card.is-dragging {
    position: relative;
    z-index: 3;
    animation: os-card-drag 5s ease-in-out 0.6s infinite;
}

@keyframes os-card-drag {
    0%, 12%   { opacity: 1; transform: translate(0, 0) rotate(0); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); }
    28%, 60%  { opacity: 1; transform: translate(0, -6px) rotate(-2deg); box-shadow: 0 12px 24px -8px rgba(0, 0, 0, 0.25); }
    80%, 100% { opacity: 1; transform: translate(0, 0) rotate(0); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); }
}

/* Label picker — glassy card like the Claude MCP tooltip, anchored over the
   In Progress column and slid in after the cards land. */
.v-board .os-board-pop {
    position: absolute;
    right: 14px;
    bottom: 14px;
    width: 170px;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 10px;
    padding: 10px 11px;
    box-shadow: 0 16px 40px -12px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transform: translateY(6px) scale(0.98);
    /* The picker is the surface that opens "on top" — it must clear the
       dragging card, which lifts itself to z-index 3. Without this the card
       being dragged paints over the popover and the L menu reads as broken. */
    z-index: 4;
}

.v-board.is-playing .os-board-pop {
    animation: os-board-pop-in 0.4s ease 0.8s forwards;
}

@keyframes os-board-pop-in {
    to { opacity: 1; transform: translateY(0) scale(1); }
}

.v-board .os-board-pop strong {
    display: block;
    margin-bottom: 7px;
    font-size: 10px;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--os-text-faint);
}

.v-board .os-board-pop ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 5px;
}

.v-board .os-board-pop li {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 11px;
    color: var(--os-text-soft);
}

.v-board .os-board-pop li.is-on { color: var(--os-text); font-weight: 500; }

.v-board .os-label-dot {
    width: 9px;
    height: 9px;
    border-radius: 999px;
    background: var(--av, var(--os-text-faint));
    flex-shrink: 0;
}

.v-board .os-pop-check {
    margin-left: auto;
    color: var(--os-accent);
    font-size: 11px;
}

/* Bento section ----------------------------------------------------- */

/* "Pop the hood" — 10 cards in a 3-column varied-span grid. Breaks the
   feature-row rhythm by putting many smaller, self-contained surfaces
   side by side. */
.os-bento {
    /* Breaks out of the 960px .os-container — the 4-column grid needs more
       horizontal room than the feature-row rhythm so cards aren't squeezed
       to ~210px each. Centred via the half/half/translate trick. */
    position: relative;
    left: 50%;
    transform: translateX(-50%);
    width: min(calc(100vw - 48px), 1280px);
    padding: 192px 0 96px;
}

.os-bento-head {
    text-align: center;
    max-width: 600px;
    margin: 0 auto 64px;
}

.os-bento-head h2 {
    font-size: 32px;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 8px 0 12px;
    color: var(--os-text);
}

.os-bento-head p {
    font-size: 16px;
    line-height: 1.5;
    color: var(--os-text-soft);
    margin: 0;
}

/* 4-column grid with deliberately uneven spans — wide-and-short (scripts,
   dock), narrow-and-tall (menus, todo, sparkle, kbd), big square (tasks),
   wide-portrait (palette), and a small square (drag) all share the surface.
   The point is to break the feature-row rhythm visually. */
.os-bento-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    /* Alternation pattern — the wide block flips between left and right
       per pair of rows so the bento doesn't read as one rigid column. */
    grid-template-areas:
        "palette    palette    menus"
        "palette    palette    menus"
        "todo       tasks      tasks"
        "todo       tasks      tasks"
        "scripts    scripts    dock"
        "scripts    scripts    drag"
        "autostart  autostart  kbd"
        "autostart  autostart  kbd"
        "sparkle    sparkle    sparkle";
    grid-template-rows: 230px 230px 220px 220px 280px 280px 230px 230px 200px;
    gap: 16px;
}

.b-palette   { grid-area: palette; }
.b-menus     { grid-area: menus; }
.b-tasks     { grid-area: tasks; }
.b-todo      { grid-area: todo; }
.b-scripts   { grid-area: scripts; }
.b-autostart { grid-area: autostart; }
.b-sparkle   { grid-area: sparkle; }
.b-drag      { grid-area: drag; }
.b-dock      { grid-area: dock; }
.b-kbd       { grid-area: kbd; }

/* Drop from 4 → 2 columns well before cards start squeezing. The wider
   ones (palette, tasks, scripts, dock) span the full 2 columns so the
   asymmetric rhythm survives. */
@media (max-width: 1100px) {
    .os-bento-grid {
        grid-template-columns: 1fr 1fr;
        grid-template-areas: none;
        grid-template-rows: none;
        grid-auto-rows: auto;
    }
    .os-bento-grid > .bento-card {
        grid-area: auto;
        grid-column: auto;
        aspect-ratio: 1 / 1;
    }
    .b-palette, .b-tasks, .b-scripts, .b-autostart {
        grid-column: span 2;
        aspect-ratio: 2 / 1;
    }
}

@media (max-width: 700px) {
    .os-bento-grid {
        grid-template-columns: 1fr;
    }
    .os-bento-grid > .bento-card,
    .b-palette, .b-tasks, .b-scripts, .b-autostart {
        grid-column: auto;
        min-height: 260px;
    }
}

.bento-card {
    position: relative;
    --bento-card-bg: var(--os-surface);
    background: var(--bento-card-bg);
    border: 1px solid var(--os-border);
    border-radius: 14px;
    padding: 22px 22px 18px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    overflow: hidden;
    box-shadow:
        0 1px 2px rgba(0, 0, 0, 0.03),
        0 6px 16px -8px rgba(0, 0, 0, 0.06);
}

.bento-card > header { display: flex; flex-direction: column; gap: 6px; }

.bento-card h3 {
    font-size: 19px;
    font-weight: 700;
    letter-spacing: -0.012em;
    margin: 0;
    color: var(--os-text);
}

.bento-card .bento-body {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

/* Foot text floats over the bottom of the visual: the mockups above are
   free to overflow into this zone, while a top-fading translucent layer
   keeps the copy legible. */
.bento-card .bento-foot {
    position: relative;
    z-index: 10;
    margin: -56px -22px -18px;
    padding: 60px 22px 18px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--os-text-soft);
    background: linear-gradient(
        to bottom,
        rgba(0, 0, 0, 0) 0,
        var(--bento-card-bg) 35%,
        var(--bento-card-bg) 100%
    );
}

.bento-card .bento-foot code {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    padding: 1px 4px;
    background: var(--os-surface-sunken);
    border-radius: 3px;
}

/* 1 — Action palette mockup ----------------------------------------- */

.b-palette { --bento-card-bg: var(--os-surface-sunken); }

.palette-mock {
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 10px;
    overflow: hidden;
    box-shadow: 0 8px 24px -12px rgba(0, 0, 0, 0.18);
    flex: 1;
    display: flex;
    flex-direction: column;
}

.palette-search {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 9px 12px;
    border-bottom: 1px solid var(--os-border);
    color: var(--os-text-faint);
}

.palette-q {
    font-size: 13px;
    color: var(--os-text);
    font-family: -apple-system, BlinkMacSystemFont, sans-serif;
}

.palette-caret {
    display: inline-block;
    width: 1px;
    height: 13px;
    background: var(--os-text);
    margin-left: 2px;
    vertical-align: -2px;
    animation: os-caret-blink 1s steps(2, end) infinite;
}

.palette-items {
    list-style: none;
    margin: 0;
    padding: 4px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    flex: 1;
    overflow: hidden;
}

.palette-item {
    display: grid;
    grid-template-columns: 18px 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: 13px;
    color: var(--os-text);
}

.palette-item.is-selected { background: #007aff; color: #fff; }
.palette-item.is-selected .palette-meta { color: rgba(255, 255, 255, 0.78); }
.palette-item.is-selected mark { color: #fff; background: transparent; font-weight: 600; }

.palette-item mark { background: transparent; color: var(--os-accent); font-weight: 600; }

.palette-icon { text-align: center; color: var(--os-text-faint); font-size: 12px; }
.palette-item.is-selected .palette-icon { color: rgba(255, 255, 255, 0.85); }
.palette-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.palette-meta {
    font-size: 11px;
    color: var(--os-text-faint);
    font-variant-numeric: tabular-nums;
}

/* 2 — Hook signals list --------------------------------------------- */

.hook-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex: 1;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
}

.hook-list li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 3px 0;
}

.hook-name { color: var(--os-text-soft); }

.hook-state {
    font-family: -apple-system, sans-serif;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 2px 7px;
    border-radius: 999px;
    flex-shrink: 0;
}

.hook-state.s-work { background: rgba(52, 199, 89, 0.14);  color: #1f7a35; }
.hook-state.s-wait { background: rgba(255, 159, 10, 0.16); color: #b06200; }
.hook-state.s-idle { background: rgba(0, 0, 0, 0.06);      color: var(--os-text-faint); }

@media (prefers-color-scheme: dark) {
    .hook-state.s-work { color: #5fd97c; }
    .hook-state.s-wait { color: #ffb454; }
    .hook-state.s-idle { background: rgba(255, 255, 255, 0.08); }
}

/* 3 — MCP tools grid ------------------------------------------------ */

.mcp-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 12px 24px;
    flex: 1;
    align-content: start;
}

.mcp-title {
    margin: 0 0 4px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--os-text-faint);
}

.mcp-group ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.mcp-group li {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    color: var(--os-text);
}

.mcp-group li .os-pulse-dot { width: 6px; height: 6px; }

/* 4 — Context menus -------------------------------------------------- */

.menu-stack {
    position: relative;
    flex: 1;
    min-height: 0;
    /* Fixed-width frame the absolute mocks position against. Auto margins
       centre it inside whatever card width we end up at, so the cascade is
       balanced at any breakpoint without per-mock percentage juggling. */
    width: 300px;
    max-width: 100%;
    margin: 0 auto;
}

.menu-mock {
    position: absolute;
    background: rgba(245, 245, 247, 0.92);
    backdrop-filter: blur(20px) saturate(160%);
    -webkit-backdrop-filter: blur(20px) saturate(160%);
    border: 0.5px solid rgba(0, 0, 0, 0.12);
    border-radius: 8px;
    padding: 4px;
    font-size: 12px;
    box-shadow: 0 12px 32px -8px rgba(0, 0, 0, 0.18), 0 1px 2px rgba(0, 0, 0, 0.06);
    min-width: 140px;
}

@media (prefers-color-scheme: dark) {
    .menu-mock {
        background: rgba(40, 40, 44, 0.92);
        border-color: rgba(255, 255, 255, 0.1);
    }
}

/* Three menus form a left-to-right cascade. Positioning the trio from the
   left edge keeps the stack inside the card at every column width — the old
   right-anchored cascade flew off-screen on the narrow 3-col layout. */
.menu-mock.m-pane     { top: 0;   left: 0;    z-index: 1; transform: rotate(-1.5deg); }
.menu-mock.m-project  { top: 24px; left: 28px; z-index: 2; }
.menu-mock.m-cascade  { top: 64px; left: 110px; z-index: 3; transform: rotate(1deg); }


.menu-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 10px 3px 8px;
    border-radius: 4px;
    color: var(--os-text);
    white-space: nowrap;
    font-size: 11.5px;
}

.menu-item.is-active { background: #007aff; color: #fff; }
.menu-item.is-disabled { color: var(--os-text-faint); }
.menu-item.is-destructive { color: #d33a2a; }
.menu-item.is-cascade { justify-content: space-between; padding-right: 6px; }

.menu-item .m-glyph {
    width: 10px;
    text-align: center;
    color: var(--os-text-faint);
    font-size: 9px;
}

.menu-item.is-active .m-glyph { color: rgba(255, 255, 255, 0.85); }
.menu-item.is-active .cascade-arrow { color: #fff; }

.menu-divider {
    height: 1px;
    margin: 4px 6px;
    background: rgba(0, 0, 0, 0.08);
}

.cascade-arrow {
    color: var(--os-text-faint);
    font-size: 14px;
    margin-left: 8px;
}

/* Real editor icons — VS Code + Sublime as SVG (Wikipedia commons +
   simpleicons), Cursor / Xcode / Zed extracted as PNG from the local
   .app bundles via `sips`. Uniform 16×16 inside each menu row. */
.editor-icon {
    width: 16px;
    height: 16px;
    flex-shrink: 0;
    object-fit: contain;
    border-radius: 3px;
}

/* 5 — Keyboard shortcuts -------------------------------------------- */

.kbd-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1;
    justify-content: center;
}

/* Keys + label inline on a single line — narrow 1×1 card has just enough
   room for a tidy left-aligned chord stack. */
.kbd-list li {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
}

.kbd-keys {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.bento-card kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    padding: 0 5px;
    background: var(--os-surface);
    border: 1px solid var(--os-border-strong);
    border-bottom-width: 2px;
    border-radius: 4px;
    font-family: -apple-system, sans-serif;
    font-size: 11px;
    font-weight: 600;
    color: var(--os-text);
}

.kbd-sep { color: var(--os-text-faint); margin: 0 2px; }
.kbd-label { font-size: 13px; color: var(--os-text-soft); }

/* — Scheduled tasks list ------------------------------------------- */

.b-tasks { --bento-card-bg: var(--os-surface-sunken); }

.task-list {
    list-style: none;
    margin: 0;
    padding: 0;
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.task-list li {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 8px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
}

.task-glyph { color: var(--os-text-faint); flex-shrink: 0; }

.task-name { font-size: 13px; color: var(--os-text); font-weight: 500; }

.task-cron {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: var(--os-text-faint);
    padding: 2px 6px;
    background: var(--os-surface-sunken);
    border-radius: 4px;
}

/* — TodoWrite mirror ----------------------------------------------- */

.todo-list {
    list-style: none;
    margin: 0;
    padding: 0;
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 8px;
    font-size: 13px;
}

.todo-list li {
    display: flex;
    align-items: center;
    gap: 10px;
    color: var(--os-text);
}

.t-box {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    border: 1.5px solid var(--os-border-strong);
    border-radius: 3px;
    color: transparent;
    flex-shrink: 0;
}

.todo-list .t-done {
    color: var(--os-text-faint);
    text-decoration: line-through;
    text-decoration-color: rgba(0, 0, 0, 0.18);
}

.todo-list .t-done .t-box {
    background: var(--os-accent);
    border-color: var(--os-accent);
    color: #fff;
}

.todo-list .t-active { font-weight: 500; }

.todo-list .t-active .t-box {
    border-color: var(--os-accent);
    background: rgba(90, 58, 238, 0.10);
}

/* Indeterminate spinner — half-pie that rotates. Indicates the
   in-progress task without a full spinner ring. */
.t-spin {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 999px;
    background: conic-gradient(var(--os-accent) 0% 50%, transparent 50% 100%);
    animation: os-spin 1s linear infinite;
}

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

.todo-list li code {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    padding: 1px 4px;
    background: var(--os-surface-sunken);
    border-radius: 3px;
    white-space: nowrap;
}

/* — Sparkle updates ------------------------------------------------ */

/* EdDSA shield as a corner badge in the card's top-right, so it reads
   like a real "signed" stamp rather than the focal point. */
.b-sparkle { position: relative; }

.sparkle-badge {
    position: absolute;
    top: 18px;
    right: 18px;
    width: 32px;
    height: 32px;
    border-radius: 999px;
    background: rgba(52, 199, 89, 0.14);
    color: #1f7a35;
    display: flex;
    align-items: center;
    justify-content: center;
}

@media (prefers-color-scheme: dark) {
    .sparkle-badge { color: #5fd97c; }
}

.sparkle-version {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
    margin: auto 0;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 14px;
}

.sparkle-from { color: var(--os-text-faint); text-decoration: line-through; text-decoration-color: rgba(0, 0, 0, 0.18); }
.sparkle-arrow { color: var(--os-text-faint); }
.sparkle-to { color: var(--os-text); font-weight: 600; }
.sparkle-delta {
    color: var(--os-accent);
    font-weight: 600;
    padding: 2px 7px;
    background: rgba(90, 58, 238, 0.10);
    border-radius: 4px;
    font-size: 12px;
}

/* — Script auto-detect --------------------------------------------- */

.scripts-mock {
    background: var(--os-surface-sunken);
    border: 1px solid var(--os-border);
    border-radius: 10px;
    overflow: hidden;
    flex: 1;
    display: flex;
    flex-direction: column;
}

.scripts-header {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid var(--os-border);
    background: var(--os-surface);
}

.scripts-pm {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    font-weight: 600;
    color: var(--os-accent);
    padding: 2px 6px;
    background: rgba(90, 58, 238, 0.10);
    border-radius: 4px;
}

.scripts-detect {
    font-size: 12px;
    color: var(--os-text-faint);
}

.scripts-detect code {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
}

.scripts-list {
    list-style: none;
    margin: 0;
    padding: 8px 0;
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.scripts-list li {
    display: flex;
    align-items: baseline;
    gap: 14px;
    padding: 5px 16px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12.5px;
}

.scripts-name {
    color: var(--os-text);
    font-weight: 600;
    min-width: 86px;
}

.scripts-cmd {
    color: var(--os-text-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
}

/* — Drag proxy (compact 1×1 layout) -------------------------------- */

/* Blue radial glow that pulses while the proxy hovers. Origin is biased
   downward to track the proxy's resting position (which sits below the
   card header). z-index sits above `.bento-foot` (z-index: 10) so the
   glow continues into the footer area instead of being clipped by the
   foot's own fade-to-bg gradient; pointer-events: none keeps the footer
   text fully selectable underneath. */
.b-drag::before {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(circle at 50% 58%, rgba(56, 127, 255, 0.55), transparent 78%);
    opacity: 0;
    pointer-events: none;
    z-index: 11;
    animation: os-drag-glow 7s ease-in-out infinite;
}

.drag-stage {
    position: relative;
    /* Sits above the glow (z-index 11 on .b-drag::before) so the proxy and
       its trailing cursor stay visually on top of the radial. The glow
       itself needs to rise above .bento-foot, which forces this. */
    z-index: 12;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    flex: 1;
    min-height: 0;
}

.drag-proxy {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 6px;
    box-shadow: 0 12px 24px -6px rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.1);
    font-size: 13px;
    font-weight: 600;
    color: var(--os-text);
    animation: os-drag-proxy 7s ease-in-out infinite;
    will-change: transform;
}

.drag-proxy .os-app-folder { width: 16px; height: 13px; }

.drag-name { white-space: nowrap; }

.drag-cursor {
    position: absolute;
    bottom: -8px;
    right: -6px;
    pointer-events: none;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.25));
}

/* Arc in from below-left, settle in the centre, arc out to above-right. The
   translateY waypoints draw a shallow U: dipping down into the card on entry
   and lifting out on exit, which reads as natural mouse motion rather than
   a rail-straight slide. */
@keyframes os-drag-proxy {
    0%   { transform: translate(-260%, -30px) rotate(-6deg); }
    10%  { transform: translate(-130%,  20px) rotate(-5deg); }
    20%  { transform: translate(0,       0)   rotate(-3deg); }
    55%  { transform: translate(0,       0)   rotate(-3deg); }
    68%  { transform: translate(130%,   20px) rotate(-1deg); }
    80%  { transform: translate(260%,  -30px) rotate(2deg); opacity: 1; }
    82%  { opacity: 0; }
    100% { transform: translate(-260%, -30px) rotate(-6deg); opacity: 0; }
}

@keyframes os-drag-glow {
    0%, 22%   { opacity: 0; }
    32%, 50%  { opacity: 0.4; }
    62%, 100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .b-drag::before,
    .drag-proxy { animation: none; }
    .drag-proxy { transform: rotate(-3deg); }
    .drag-cursor { display: none; }
}

.drag-anywhere {
    font-size: 12px;
    color: var(--os-text-faint);
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
}

/* tree-kill (removed from grid but CSS kept harmless) ---------------- */

.b-treekill .big-numeral {
    font-size: 56px;
    font-weight: 700;
    letter-spacing: -0.04em;
    line-height: 1;
    color: var(--os-text);
}

.b-treekill .big-numeral span {
    font-size: 24px;
    color: var(--os-text-faint);
    margin-left: 4px;
}

.kill-timeline {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-height: 0;
}

.kill-stamp {
    display: inline-flex;
    align-items: center;
    padding: 4px 8px;
    border-radius: 4px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    flex-shrink: 0;
}

.kill-stamp.s-term { background: rgba(255, 159, 10, 0.16); color: #b06200; }
.kill-stamp.s-kill { background: rgba(255, 69, 58, 0.16); color: #c1352a; }

.kill-line {
    flex: 1;
    height: 2px;
    background: repeating-linear-gradient(to right, var(--os-border-strong) 0 4px, transparent 4px 8px);
}

/* 7 — Dock badge + bounce ------------------------------------------- */

.dock-mock {
    position: relative;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 0;
}

/* Shelf and arc anchor to the vertical centre of dock-mock so they stay
   glued to the tile when the mock area changes height. */
.dock-shelf {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, 34px);
    width: 120px;
    height: 12px;
    border-radius: 8px 8px 4px 4px;
    background: rgba(0, 0, 0, 0.06);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4);
}

.dock-tile {
    position: relative;
    width: 56px;
    height: 56px;
    animation: os-dock-bounce 3.2s ease-in-out infinite;
}

.dock-tile img {
    width: 100%;
    height: 100%;
    display: block;
}

.dock-badge {
    position: absolute;
    top: -2px;
    right: -4px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: #ff3b30;
    color: #fff;
    font-size: 11px;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    box-shadow: 0 0 0 1.5px var(--os-surface), 0 1px 2px rgba(0, 0, 0, 0.2);
    animation: os-dock-badge-in 3.2s ease-in-out infinite;
}

.dock-bounce-arc {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 60px;
    height: 30px;
    border-top: 2px dotted var(--os-border-strong);
    border-radius: 50% 50% 0 0;
    transform: translate(-50%, -56px);
    opacity: 0.5;
}

@keyframes os-dock-bounce {
    0%, 70%, 100% { transform: translateY(0); }
    78%           { transform: translateY(-14px); }
    86%           { transform: translateY(0); }
    92%           { transform: translateY(-4px); }
    97%           { transform: translateY(0); }
}

@keyframes os-dock-badge-in {
    0%, 40%   { opacity: 0; transform: scale(0.6); }
    50%, 100% { opacity: 1; transform: scale(1); }
}

/* Section divider between bento and changelog. The changelog markup
   came from the existing page and stays untouched. Symmetric margins so
   the divider doesn't visually tip toward either section. */
.os-divider {
    height: 1px;
    background: var(--os-border);
    margin: 0 0 96px;
}

/* FAQ ---------------------------------------------------------------- */

.os-faq {
    margin: 0 0 96px;
}

.os-faq-head {
    text-align: center;
    margin-bottom: 40px;
}

.os-faq-head h2 {
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 6px 0 0;
    color: var(--os-text);
}

.os-faq-list {
    max-width: 720px;
    margin: 0 auto;
    border-top: 1px solid var(--os-border);
}

.os-faq-item {
    border-bottom: 1px solid var(--os-border);
}

.os-faq-item > summary {
    list-style: none;
    cursor: pointer;
    padding: 20px 44px 20px 4px;
    position: relative;
    font-size: 16px;
    font-weight: 600;
    color: var(--os-text);
    line-height: 1.45;
}

.os-faq-item > summary::-webkit-details-marker { display: none; }

.os-faq-item > summary::after {
    content: "";
    position: absolute;
    right: 8px;
    top: 50%;
    width: 10px;
    height: 10px;
    border-right: 1.6px solid var(--os-text-faint);
    border-bottom: 1.6px solid var(--os-text-faint);
    transform: translateY(-70%) rotate(45deg);
    transition: transform 0.2s ease;
}

.os-faq-item[open] > summary::after {
    transform: translateY(-30%) rotate(-135deg);
}

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

.os-faq-body {
    padding: 0 44px 20px 4px;
    color: var(--os-text-soft);
    font-size: 15px;
    line-height: 1.6;
}

.os-faq-body p {
    margin: 0;
}

.os-faq-body code {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 13px;
    background: var(--os-surface-sunken);
    padding: 1px 6px;
    border-radius: 4px;
    color: var(--os-text);
}

/* Respect the user's reduced-motion preference — disable all the
   feature animations, but keep the elements visible (no surprise blank
   sections). */
/* — Command auto-start mock ----------------------------------------- */

.b-autostart { --bento-card-bg: var(--os-surface-sunken); }

.autostart-mock {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 14px 16px;
    background: var(--os-surface);
    border: 1px solid var(--os-border);
    border-radius: 10px;
    box-shadow: 0 8px 24px -12px rgba(0, 0, 0, 0.18);
}

.autostart-field-label {
    margin: 0;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--os-text-faint);
}

.autostart-opts {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.autostart-opt {
    display: flex;
    align-items: center;
    gap: 9px;
    font-size: 13px;
    color: var(--os-text-soft);
}

.autostart-radio {
    width: 15px;
    height: 15px;
    border-radius: 999px;
    border: 1.5px solid var(--os-border-strong);
    flex-shrink: 0;
    position: relative;
}

/* The picked option — accent ring with a filled centre, matching the radio
   control in the command form. */
.autostart-opt.is-on { color: var(--os-text); }
.autostart-opt.is-on .autostart-radio { border-color: var(--os-accent); }
.autostart-opt.is-on .autostart-radio::after {
    content: "";
    position: absolute;
    inset: 3px;
    border-radius: 999px;
    background: var(--os-accent);
}

.autostart-opt-label { font-weight: 500; }

.autostart-hint {
    margin-left: auto;
    font-size: 11px;
    color: var(--os-text-faint);
}

@media (prefers-reduced-motion: reduce) {
    .os-feature-visual *,
    .os-feature-visual {
        transition: none !important;
        animation: none !important;
    }
    .os-feature-visual .os-pane-row,
    .os-feature-visual .line,
    .os-feature-visual .file-row,
    .os-feature-visual .diff-line,
    .os-feature-visual .os-tooltip,
    .os-feature-visual .os-card,
    .os-feature-visual .os-board-pop {
        opacity: 1 !important;
        transform: none !important;
    }
}
