@font-face {
    font-family: 'Blanka';
    src: url('../fonts/Blanka-Regular.otf') format('opentype');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

/*
 * WEB-THEME-1 (2026-10-25) — light, dark, or the operating system's choice.
 *
 * ⛔ THREE STATES, NOT TWO. "System" is the default and is a real choice, not
 * the absence of one — the same contract the admin console states in
 * `console/src/app/theme.tsx`. An explicit pick overrides it and persists.
 *
 * ⚠️ DARK IS THE DEFAULT PALETTE HERE, not light. `:root` carries dark so that
 * a visitor whose OS says dark — and anyone whose JS never runs — gets the
 * brand's native ground. `[data-theme="light"]` is the override.
 *
 * The site's palette is the BRAND palette (warm ground, cream ink), which is
 * deliberately not the app's default UI theme — the app ships several
 * user-selectable themes and none of them is the brand. The light values below
 * are the warm counterpart of the dark ones, not a neutral inversion.
 */
:root {
    --bg: #1A1412;
    --bg-secondary: #231C18;
    --surface: #2C231E;
    --accent: #D4956B;
    --text: #E8DDD4;
    --text-secondary: #A89888;
    /* ⚠️ Was #6B5D52 — 2.87:1 on this ground, a WCAG AA failure that
     * predates the theme work and applies to the dark palette the site has
     * always shipped. #938374 is 4.98:1 at the same hue. */
    --text-muted: #938374;
    --border: #3A2F28;

    /* Translucent header ground. ⚠️ Was a hardcoded rgba(26,20,18,.85), which
     * is the dark bg — it would have stayed dark under the light theme. */
    --header-bg: rgba(26, 20, 18, 0.85);
    --shadow: rgba(0, 0, 0, 0.25);
    /* ⚠️ Status colours need DIFFERENT values per theme, not one shared
     * literal: #4CAF50 reads at 2.3:1 on cream and is unreadable there. */
    --ok: #6FCF7F;
    --err: #E57373;

    /*
     * ⛔ THE MARK'S POLARITY FOLLOWS ITS GROUND — the SSOT's rule, verbatim:
     * "the triangle always takes the contrasting token and the circle always
     * takes the ground". Binding these to --bg/--text rather than to literals
     * makes that true in both themes by construction.
     *
     * ⚠️ The circle resolving to exactly --bg is correct, not a bug: the disc
     * is meant to vanish into the page so only the recursion and the hairline
     * ring read. The SSOT says the same of the division bands — "same as the
     * circle, so any overshoot is invisible".
     */
    --mark-ground: var(--bg);
    --mark-ink: var(--text);
    --mark-ring: var(--text-muted);
}

:root[data-theme="light"] {
    --bg: #F5EFE8;
    --bg-secondary: #EDE4DA;
    --surface: #FBF7F2;
    /* ⚠️ NOT #D4956B. That accent is tuned for a dark ground and falls to
     * ~2.1:1 on cream — below AA for text at any size. This is the same hue
     * carried down until it passes. */
    --accent: #A05A2C;
    --text: #1A1412;
    --text-secondary: #5A4A3E;
    /* 3.77:1 at #87776A was large-text only; this is 5.29:1. */
    --text-muted: #6F6054;
    --border: #DED2C5;

    --header-bg: rgba(245, 239, 232, 0.85);
    --shadow: rgba(26, 20, 18, 0.12);
    /* #2E7D32 measured 4.49:1 — AA is 4.5, so it missed by 0.01. */
    --ok: #2A722D;
    --err: #C62828;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

/* Sticky header (WEB-1) */
.site-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: var(--header-bg);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--border);
}

.site-header-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0.9rem 2rem;
    display: flex;
    align-items: center;
    gap: 1.5rem;
    position: relative;
}

.site-header-brand {
    margin-right: auto;
}

.site-header-brand {
    display: flex;
    align-items: baseline;
    gap: 0.6rem;
    color: var(--text);
    text-decoration: none;
    font-family: 'Blanka', -apple-system, sans-serif;
    font-weight: 400;
    font-size: 1.15rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    line-height: 1;
}

.site-header-brand svg {
    width: 24px;
    height: 19px;
    align-self: baseline;
}

.site-nav {
    display: flex;
    align-items: center;
    gap: 1.6rem;
}

.site-nav a {
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.92rem;
    font-weight: 500;
    transition: color 0.15s;
}

.site-nav a:hover { color: var(--text); }
.site-nav a.active { color: var(--accent); }

.nav-cta {
    background: var(--accent);
    color: var(--bg);
    padding: 0.5rem 1.1rem;
    border-radius: 999px;
    font-weight: 600;
    text-decoration: none;
    transition: transform 0.15s, opacity 0.15s;
}

.nav-cta:hover {
    transform: translateY(-1px);
    color: var(--bg);
    opacity: 0.92;
}

.nav-toggle {
    display: none;
    width: 40px;
    height: 40px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 10px;
    cursor: pointer;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 5px;
}

.nav-toggle span {
    display: block;
    width: 18px;
    height: 2px;
    background: var(--text);
    border-radius: 2px;
    transition: transform 0.2s ease, opacity 0.2s ease;
}

.nav-toggle[aria-expanded="true"] span:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] span:nth-child(2) {
    opacity: 0;
}
.nav-toggle[aria-expanded="true"] span:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
}

@media (max-width: 640px) {
    .site-header-inner {
        padding: 0.75rem 1.25rem;
        gap: 0.75rem;
        flex-wrap: wrap;
    }
    .nav-toggle {
        display: flex;
        order: -1;
    }
    .site-nav {
        order: 3;
        flex-basis: 100%;
        justify-content: center;
        gap: 1.25rem;
        max-height: 0;
        padding: 0;
        margin: 0;
        overflow: hidden;
        border-top: 1px solid transparent;
        transition: max-height 0.25s ease, padding 0.25s ease, border-color 0.25s ease;
    }
    .site-nav.open {
        max-height: 80px;
        padding-top: 0.65rem;
        padding-bottom: 0.15rem;
        border-top-color: var(--border);
    }
    .site-nav a {
        font-size: 0.85rem;
    }
}

/*
 * ⛔ WEB-HEADER-FIT-1 — the bar must stay ONE row on a small phone.
 *
 * Measured at a real 360px viewport (not a cropped screenshot — headless
 * Chrome clamps its window to ~500px, so a narrow capture is a CROP of a wide
 * render and reports nothing about media queries):
 *
 *   content box 320px, needed 356px
 *   burger 40 + brand 118 + toggle 36 + CTA 126 + 3 gaps x 12 = 356
 *
 * 36px short, so `flex-wrap` — which exists so the nav can take its own row —
 * dropped the CTA to a second line and made the bar 132px tall instead of 80.
 *
 * ⚠️ Trimmed rather than hidden: the wordmark stays. It is the only place the
 * wordmark appears on a phone now that the hero leads with the proposition,
 * and losing it to save 96px would be the expensive way to buy 36.
 */
@media (max-width: 420px) {
    .site-header-inner {
        padding: 0.7rem 0.75rem;
        gap: 0.4rem;
    }
    .nav-cta {
        padding: 0.5rem 0.85rem;
        font-size: 0.85rem;
        white-space: nowrap;
    }
    .theme-toggle {
        width: 32px;
        height: 32px;
    }
    .site-header-brand svg { width: 20px; height: 20px; }
}



/* Hero
 * ============================================================================
 * ⛔ WEB-HERO-INTENT-1 (2026-10-25) — THE HERO IS A CENTRED, FULL-VIEWPORT
 * COMPOSITION. THIS IS DELIBERATE. DO NOT "FIX" THE WHITESPACE HERE.
 *
 * Two declarations carry that intent and they do DIFFERENT jobs:
 *
 *   min-height: calc(100vh - var(--header-h))
 *       The hero owns the entire first screen. Nothing from the next section
 *       is visible until the visitor scrolls.
 *
 *   justify-content: center
 *       Headline, film and store badges sit as ONE balanced block in the
 *       middle of that screen.
 *
 * ⚠️ HOW THIS WAS BROKEN TWICE IN ONE SESSION, both times by me, both times
 * caught by the owner:
 *
 *   1. Asked "is the space above the tagline too big on mobile?", I dropped
 *      BOTH declarations on phones. That removed the gap AND the design: the
 *      next section's mark and heading began bleeding into the first screen.
 *
 *   2. Told that was wrong, I restored `min-height` but kept
 *      `justify-content: flex-start`. The gap went from 108px above the
 *      headline to 235px BELOW the badges. Alignment cannot remove whitespace;
 *      it can only move it. The hero stopped being balanced and became a block
 *      pinned to the top of a mostly empty screen.
 *
 * ⛔ THE WHITESPACE IS A CONTENT-HEIGHT QUESTION, NOT AN ALIGNMENT ONE.
 * Measured on a phone: ~465px of content inside a 770–860px box, so ~40% of
 * the first screen is air, split evenly. If that must shrink, the ONLY levers
 * that work are making the content taller — widening the film (worth ~18px,
 * not worth the change) or cropping it to a taller aspect ratio on mobile
 * (worth ~62px, at the cost of re-framing a professionally shot film). Both
 * are brand decisions and belong to the owner, not to a CSS tidy-up.
 *
 * Guarded by `scripts/verify-website-hero-intent.sh`.
 * ============================================================================ */
.hero {
    /* Subtract the MEASURED sticky header height — see WEB-HEADER-H-1. A
     * hard-coded 64 against a 71.4px bar made the hero overflow by 7.4px,
     * which is what pushed the store badges below the fold. */
    min-height: calc(100vh - var(--header-h));
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 2rem;
    position: relative;
}

.hero::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 200px;
    background: linear-gradient(to bottom, transparent, var(--bg));
    /* Decoration only: it lies over the bottom of the hero, where the store
       badges sit, and must never take their clicks. */
    pointer-events: none;
}

.symbol {
    width: 120px;
    height: 120px;
    margin-bottom: 2rem;
}

.symbol svg {
    width: 100%;
    height: 100%;
}

.logo-text {
    font-size: 3rem;
    font-weight: 200;
    letter-spacing: 1.2rem;
    margin-bottom: 1rem;
    color: var(--text);
}

.tagline {
    font-size: 1.25rem;
    color: var(--text-secondary);
    font-weight: 300;
    margin-bottom: 0.75rem;
}

.quote {
    font-style: italic;
    color: var(--text-muted);
    font-size: 0.95rem;
    margin-bottom: 2rem;
}

.hero-video {
    width: 100%;
    max-width: 880px;
    margin: 0 auto 2.5rem;
    border-radius: 14px;
    overflow: hidden;
    /* The film's own letterboxing ground — stays the brand dark in BOTH
     * themes on purpose: the video is graded against black, and a cream
     * surround would show as a bright halo around its dark frames. */
    background: #1A1412;
    box-shadow: 0 20px 60px var(--shadow);
}

.hero-video video {
    display: block;
    width: 100%;
    height: auto;
}

.cta-group {
    display: flex;
    gap: 1rem;
    flex-wrap: wrap;
    justify-content: center;
}

.cta {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.875rem 2rem;
    border-radius: 12px;
    font-size: 1rem;
    font-weight: 600;
    text-decoration: none;
    transition: transform 0.2s, opacity 0.2s;
}

.cta:hover { transform: translateY(-2px); }

.cta-primary {
    background: var(--accent);
    color: var(--bg);
}

.cta-secondary {
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
}

/* Sections */
section {
    max-width: 960px;
    margin: 0 auto;
    padding: 6rem 2rem;
}

h2 {
    font-size: 2rem;
    font-weight: 600;
    margin-bottom: 1rem;
    color: var(--text);
}

h2 .accent { color: var(--accent); }

.section-subtitle {
    color: var(--text-secondary);
    font-size: 1.1rem;
    margin-bottom: 3rem;
    max-width: 600px;
}

/* Philosophy */
.philosophy {
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.philosophy p {
    max-width: 640px;
    color: var(--text-secondary);
    font-size: 1.05rem;
    line-height: 1.8;
}

/* Tools Grid */
.tool-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 2rem;
    transition: border-color 0.2s, transform 0.2s;
}

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

.tool-icon {
    width: 52px;
    height: 52px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 14px;
    font-size: 1.5rem;
    margin-bottom: 1rem;
    background: color-mix(in srgb, var(--tool-color, var(--accent)) 18%, transparent);
    border: 1px solid color-mix(in srgb, var(--tool-color, var(--accent)) 32%, transparent);
    color: var(--tool-color, var(--accent));
}

.tool-card h3 {
    font-size: 1.2rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
}

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

.tool-category {
    display: inline-block;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08rem;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 0.75rem;
}

.pillar-group {
    margin-bottom: 2.5rem;
}

.pillar-heading {
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.14rem;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1.25rem;
    text-align: center;
}

.pillar-tools {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.5rem;
}

.pillar-tools .tool-card {
    flex: 1 1 280px;
    max-width: 360px;
}

.libba-featured {
    margin-top: 1rem;
    text-align: center;
    border-color: var(--accent);
    display: flex;
    flex-direction: column;
    align-items: center;
}

.libba-featured .tool-icon {
    width: 64px;
    height: 64px;
    font-size: 2rem;
    margin-bottom: 1rem;
}

.libba-featured .tool-category {
    margin-bottom: 0.75rem;
}

/* Pillars */
.pillars {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.5rem;
    margin-top: 2rem;
}

.pillar {
    text-align: center;
    padding: 2rem 1.5rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
}

.pillar h3 {
    font-size: 1.1rem;
    margin-bottom: 0.5rem;
    color: var(--accent);
}

.pillar p {
    color: var(--text-secondary);
    font-size: 0.9rem;
}

/* Privacy */
.privacy-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1.25rem;
    margin-top: 2rem;
}

.privacy-item {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

.privacy-check {
    color: var(--ok);
    font-size: 1.2rem;
    flex-shrink: 0;
    margin-top: 0.15rem;
}

.privacy-item p {
    color: var(--text-secondary);
    font-size: 0.95rem;
}

/* Pricing */
.pricing-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 1.5rem;
    margin-top: 2rem;
}

.price-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 2.5rem 2rem;
    text-align: center;
    position: relative;
    transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.price-card:hover {
    transform: translateY(-2px);
    border-color: var(--accent);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}

.price-card-link {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    z-index: 1;
    text-indent: -9999px;
    overflow: hidden;
}

.price-card-link:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.price-card.featured {
    border-color: var(--accent);
}

.price-card .badge {
    position: absolute;
    top: -12px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--accent);
    color: var(--bg);
    font-size: 0.75rem;
    font-weight: 700;
    padding: 0.25rem 1rem;
    border-radius: 20px;
}

.price-card h3 {
    font-size: 1.2rem;
    margin-bottom: 1rem;
}

.price {
    font-size: 2.5rem;
    font-weight: 700;
    color: var(--text);
}

.price span {
    font-size: 1rem;
    font-weight: 400;
    color: var(--text-muted);
}

.price-note {
    color: var(--text-muted);
    font-size: 0.85rem;
    margin-top: 0.5rem;
    margin-bottom: 1.5rem;
}

.price-features {
    list-style: none;
    text-align: left;
    margin-bottom: 1.5rem;
}

.price-features li {
    color: var(--text-secondary);
    font-size: 0.9rem;
    padding: 0.4rem 0;
}

.price-features li::before {
    content: "\2713";
    color: var(--accent);
    margin-right: 0.5rem;
    font-weight: 700;
}

/* Footer */
footer {
    border-top: 1px solid var(--border);
    padding: 3rem 2rem;
    text-align: center;
}

.footer-links {
    display: flex;
    gap: 2rem;
    justify-content: center;
    margin-bottom: 1.5rem;
    flex-wrap: wrap;
}

.footer-links a {
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.9rem;
    transition: color 0.2s;
}

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

.copyright {
    color: var(--text-secondary); /* AA contrast: muted was 2.9:1 on the background */
    font-size: 0.8rem;
}

/* Privacy Policy Page (anchor section) */
.policy-content {
    max-width: 720px;
    margin: 0 auto;
}

.policy-content h3 {
    font-size: 1.1rem;
    margin-top: 2rem;
    margin-bottom: 0.75rem;
    color: var(--text);
}

.policy-content p {
    color: var(--text-secondary);
    font-size: 0.95rem;
    margin-bottom: 1rem;
    line-height: 1.7;
}

/* LEGAL-2 — the policy body is generated from shared/legal/privacy-policy.json
   and now uses real lists where it used to use runs of paragraphs. The global
   reset zeroes list margins, so without these the bullets collapse against the
   prose that follows them. */
.policy-content ul {
    color: var(--text-secondary);
    font-size: 0.95rem;
    line-height: 1.7;
    margin: 0 0 1rem 1.25rem;
    padding: 0;
}

.policy-content ul li {
    margin-bottom: 0.4rem;
}

.policy-content ul li:last-child {
    margin-bottom: 0;
}

.policy-content a {
    color: var(--accent);
}

/* Responsive */
@media (max-width: 768px) {
    .logo-text { font-size: 2rem; letter-spacing: 0.6rem; }
    .tagline { font-size: 1rem; }
    .pillars { grid-template-columns: 1fr; }
    section { padding: 4rem 1.5rem; }
    h2 { font-size: 1.6rem; }
}

/* Email Capture */
.email-capture {
    margin-top: 2rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75rem;
    position: relative;
    z-index: 1;
}

.email-capture .label {
    font-size: 0.95rem;
    color: var(--text-secondary);
    font-weight: 400;
}

.email-form {
    display: flex;
    gap: 0.5rem;
    max-width: 440px;
    width: 100%;
}

.email-input {
    flex: 1;
    padding: 0.8rem 1.25rem;
    border-radius: 10px;
    border: 1px solid var(--border);
    background: var(--surface);
    color: var(--text);
    font-size: 0.95rem;
    font-family: inherit;
    outline: none;
    transition: border-color 0.2s;
}

.email-input::placeholder { color: var(--text-muted); }
.email-input:focus { border-color: var(--accent); }

.email-submit {
    padding: 0.8rem 1.5rem;
    border-radius: 10px;
    border: none;
    background: var(--accent);
    color: var(--bg);
    font-size: 0.95rem;
    font-weight: 600;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    transition: opacity 0.2s, transform 0.2s;
}

.email-submit:hover { opacity: 0.9; transform: translateY(-1px); }

.email-note {
    font-size: 0.8rem;
    color: var(--text-muted);
}

.email-feedback {
    font-size: 0.9rem;
    font-weight: 500;
    min-height: 1.4em;
}

.email-feedback.success { color: var(--ok); }
.email-feedback.error { color: var(--err); }

/* App Store Badge cluster — two badges side-by-side on desktop, stacked on mobile.
   Apple's brand guidelines require both badges (App Store + Mac App Store) to be
   shown when the product is available on both platforms; both share the same visual
   styling so neither feels demoted. */
.app-badges {
    /* Above the hero's bottom fade (.hero::after), so the badges are drawn
       at full strength and receive clicks. */
    position: relative;
    z-index: 1;
    display: flex;
    gap: 0.75rem;
    margin-top: 1.5rem;
    flex-wrap: wrap;
    justify-content: center;
}

.app-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    /* Inside the .app-badges cluster the cluster owns the top margin, so reset
       on each badge. Stand-alone usages (none currently, but defensive) inherit
       the original 1.5rem from .app-badges → .app-badge:only-child. */
    margin-top: 0;
    padding: 0.65rem 1.5rem;
    border-radius: 10px;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 0.85rem;
    text-decoration: none;
    position: relative;
    z-index: 1;
    cursor: pointer;
    transition: border-color 0.2s, transform 0.2s;
}

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

.app-badge .apple-icon {
    font-size: 1.4rem;
    line-height: 1;
}

.app-badge .badge-text {
    display: flex;
    flex-direction: column;
    text-align: left;
    line-height: 1.2;
}

.app-badge .badge-text .badge-small {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.04rem;
}

.app-badge .badge-text .badge-large {
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-secondary);
}

/* Screenshots */
.screenshots-section {
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.screenshots-wrap {
    position: relative;
    width: 100%;
}

.screenshots-wrap::after {
    content: '';
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 80px;
    background: linear-gradient(to right, transparent, var(--bg));
    pointer-events: none;
    z-index: 1;
    transition: opacity 0.3s;
}

.screenshots-wrap.at-end::after {
    opacity: 0;
}

.screenshots-wrap::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    width: 80px;
    background: linear-gradient(to left, transparent, var(--bg));
    pointer-events: none;
    z-index: 1;
    opacity: 0;
    transition: opacity 0.3s;
}

.screenshots-wrap.scrolled::before {
    opacity: 1;
}

.scroll-arrow {
    display: none;
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    border-radius: 50%;
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
    font-size: 1.2rem;
    cursor: pointer;
    z-index: 2;
    align-items: center;
    justify-content: center;
    transition: background 0.2s, border-color 0.2s;
}

.scroll-arrow:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--bg);
}

.scroll-arrow-left { left: 12px; }
.scroll-arrow-right { right: 12px; }

.screenshots-wrap:not(.scrolled) .scroll-arrow-left { opacity: 0; pointer-events: none; }
.screenshots-wrap.at-end .scroll-arrow-right { opacity: 0; pointer-events: none; }

@media (min-width: 769px) {
    .screenshots-wrap:hover .scroll-arrow {
        display: flex;
    }
}

.screenshots-scroll {
    display: flex;
    gap: 1.25rem;
    overflow-x: auto;
    padding: 1rem 0 2rem;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
}

.screenshots-scroll::-webkit-scrollbar { display: none; }

.screenshot-frame {
    flex: 0 0 auto;
    width: 220px;
    height: 440px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 20px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.75rem;
    scroll-snap-align: center;
    overflow: hidden;
    position: relative;
}

.screenshot-frame img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 19px;
}

.screenshot-frame .placeholder-icon {
    font-size: 2.5rem;
    opacity: 0.5;
}

.screenshot-frame .placeholder-label {
    font-size: 0.85rem;
    color: var(--text-muted);
    font-weight: 500;
}

/* Responsive additions */
@media (max-width: 768px) {
    .email-form { flex-direction: column; }
    .email-submit { width: 100%; }
    .screenshot-frame { width: 180px; height: 360px; }
}

/* Smooth scroll */
/*
 * ⛔ WEB-HEADER-H-1 — the header's height is MEASURED, not guessed.
 *
 * `scroll-padding-top: 64px` and the hero's `calc(100vh - 64px)` both asserted
 * a 64px header. It is 71.4px, so every anchor landed with 7.4px of its target
 * tucked under the sticky bar and the hero ran 7.4px tall. "Get the App" on
 * desktop scrolls to the store badges, which is exactly where that showed.
 *
 * ⚠️ A magic number repeated in two places cannot survive the header's
 * contents changing — and they did change, when the theme toggle was added.
 * `site.js` measures the real height into `--header-h` and keeps it current
 * with a ResizeObserver; the value here is only the pre-JS fallback.
 *
 * The extra 12px is breathing room, so an anchor target lands BELOW the bar
 * rather than flush against it.
 */
:root { --header-h: 71px; }
html { scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + 12px); }

/* FAQ / details (WEB-2/WEB-3) */
.faq-item {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 0;
    margin-bottom: 0.75rem;
    transition: border-color 0.2s;
}
.faq-item[open] { border-color: var(--accent); }
.faq-item summary {
    padding: 1rem 1.25rem;
    cursor: pointer;
    font-weight: 600;
    color: var(--text);
    list-style: none;
    position: relative;
    padding-right: 2.5rem;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
    content: '+';
    position: absolute;
    right: 1.25rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--accent);
    font-size: 1.25rem;
    font-weight: 400;
    transition: transform 0.2s;
}
.faq-item[open] summary::after {
    content: '\2013';
    transform: translateY(-50%) rotate(180deg);
}
.faq-item p {
    padding: 0 1.25rem 1.1rem 1.25rem;
    margin: 0;
    color: var(--text-secondary);
    font-size: 0.95rem;
    line-height: 1.6;
}

/* Support channels (WEB-2) */
.support-channels {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    margin-top: 1.5rem;
}
@media (max-width: 720px) {
    .support-channels {
        grid-template-columns: 1fr;
    }
}
.channel-icon {
    width: 48px;
    height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 12px;
    font-size: 1.6rem;
    line-height: 1;
    margin-bottom: 0.5rem;
    background: color-mix(in srgb, var(--tool-color, var(--accent)) 18%, transparent);
    border: 1px solid color-mix(in srgb, var(--tool-color, var(--accent)) 32%, transparent);
}
.support-channel {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 1.1rem 1.25rem;
    text-decoration: none;
    transition: border-color 0.2s, transform 0.15s;
}
.support-channel:hover {
    border-color: var(--accent);
    transform: translateY(-2px);
}
.channel-title {
    color: var(--text);
    font-weight: 600;
    font-size: 1rem;
}
.channel-sub {
    color: var(--text-secondary);
    font-size: 0.88rem;
    line-height: 1.5;
}

/* Support page content block */
#support-page {
    max-width: 900px;
    margin: 0 auto;
    padding: 4rem 2rem;
}

/* Official store badges (Apple and Google artwork, unaltered, per their badge
   guidelines). Google's PNG carries built-in padding: its visible badge is
   168 of 250 px tall, so it renders at 72px with a -12px margin to match the
   48px Apple badge exactly. */
.store-badge {
    display: inline-block;
    line-height: 0;
    border-radius: 10px;
}

.store-badge img {
    display: block;
    height: 48px;
    width: auto;
}

.store-badge-google img {
    height: 72px;
    margin: -12px;
}

.store-badge:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
}

/* ==========================================================================
   WEB-THEME-1 — the theme control
   ========================================================================== */

.theme-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: transparent;
    color: var(--text-secondary);
    cursor: pointer;
    transition: color .2s ease, border-color .2s ease, background .2s ease;
}

.theme-toggle:hover { color: var(--text); border-color: var(--text-muted); }

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

.theme-toggle svg { width: 18px; height: 18px; display: block; }

/* Only the glyph for the CURRENT state is shown. The button cycles
 * system -> light -> dark, and its aria-label names the state it is in. */
.theme-toggle [data-glyph] { display: none; }
:root[data-choice="system"] .theme-toggle [data-glyph="system"],
:root[data-choice="light"]  .theme-toggle [data-glyph="light"],
:root[data-choice="dark"]   .theme-toggle [data-glyph="dark"] { display: block; }
/* ⚠️ Before the controller runs, `data-choice` is absent. Without this the
 * button would render EMPTY on first paint — a 36px hole in the header. */
:root:not([data-choice]) .theme-toggle [data-glyph="system"] { display: block; }

/* ==========================================================================
   WEB-FILM-1 — the hero film
   ========================================================================== */

.hero-film {
    position: relative;
    /* ⛔ `min(1000px, 100%)`, NOT `1000px`. As a flex item with an
     * `aspect-ratio`, this box is sized from its content and the plain
     * max-width never clamped it to the column: at a 390px viewport it
     * measured 358px wide inside a 326px content box and ran off the right
     * edge — left gap 32px, right gap 0.
     *
     * ⚠️ Predates the cover layer and survived its removal, so the cover was
     * not the cause. Measured at 390 and 1920 after reverting. */
    max-width: min(1000px, 100%);
    /* ⛔ THE ACTUAL CAUSE OF THE MOBILE OVERFLOW. A flex item's automatic
     * minimum size is its content's min-content width, so this box refused to
     * shrink below the video's intrinsic width no matter what max-width said
     * — 358px inside a 326px column at 390px wide, hanging off the right edge.
     * `min-width: 0` is what lets max-width bind at all.
     *
     * ⚠️ `max-width: min(1000px, 100%)` alone fixed 768px and did NOT fix
     * 390px, which is how this was found: the clamp was never the binding
     * constraint on the narrow viewport. */
    min-width: 0;
    margin: 2.5rem auto 0;
    border-radius: 16px;
    overflow: hidden;
    background: #1A1412;
    box-shadow: 0 30px 80px var(--shadow);
    aspect-ratio: 16 / 9;
}

.hero-film video {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
}

.film-controls {
    position: absolute;
    right: 1rem;
    bottom: 1rem;
    display: flex;
    gap: .5rem;
}

.film-btn {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .5rem .85rem;
    border: 1px solid rgba(232, 221, 212, 0.25);
    border-radius: 999px;
    /* ⛔ Fixed light-on-dark, NOT themed. These sit ON the film, whose ground
     * is the same black in both themes — theming them would make them
     * invisible against it under the light palette. */
    background: rgba(26, 20, 18, 0.6);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    color: #E8DDD4;
    font: inherit;
    font-size: .82rem;
    cursor: pointer;
    transition: background .2s ease, border-color .2s ease;
}

.film-btn:hover { background: rgba(26, 20, 18, 0.85); border-color: rgba(232, 221, 212, 0.5); }
.film-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.film-btn svg { width: 14px; height: 14px; }

/* The replay control only exists once the film has ended. */
.film-btn[hidden] { display: none; }

/* ==========================================================================
   WEB-PILLARS-1 — the mark's three bands ARE the three pillars
   ========================================================================== */

.pillars-figure {
    display: grid;
    grid-template-columns: minmax(200px, 320px) 1fr;
    gap: 3rem;
    align-items: center;
    max-width: 1000px;
    margin: 0 auto;
}

.pillar-mark { width: 100%; height: auto; overflow: visible; }

.pillar-mark .band {
    /* Each band starts displaced along its own axis and settles home.
     * `--dy` is set per band; the assembled state is simply 0. */
    transform: translateY(var(--dy, 0)) scale(var(--s, 1));
    transform-origin: 100px 100px;
    transform-box: view-box;
    opacity: var(--o, 1);
    transition:
        transform 900ms cubic-bezier(.22, 1, .36, 1),
        opacity 600ms ease;
}

/* ⛔ The scattered state is the DEFAULT, so the assembly is what JS adds.
 * The reverse — assembled by default, scattered by a class — would leave the
 * mark broken for anyone whose JS fails, on the section that explains the
 * brand. */
/* ⚠️ Apex is CONTROL and base is EXECUTION — these were swapped, so the apex
 * band flew in from below the figure and the base band from above it. The
 * band names changed meaning; the offsets had to follow. */
.pillar-mark .band-control    { --dy: -46px; --o: 0; }
.pillar-mark .band-efficiency { --dy:   0px; --s: .82; --o: 0; }
.pillar-mark .band-execution  { --dy:  46px; --o: 0; }

.pillars-figure.is-assembled .band { --dy: 0px; --s: 1; --o: 1; }

/* Stagger: apex, base, then the middle locks it together. */
.pillars-figure.is-assembled .band-control    { transition-delay: 0ms; }
.pillars-figure.is-assembled .band-execution  { transition-delay: 90ms; }
.pillars-figure.is-assembled .band-efficiency { transition-delay: 190ms; }

/* Hovering or focusing a pillar lifts its band out of the figure.
 * ⚠️ Driven by a class from JS, not by a CSS sibling selector: the cards and
 * the mark are in different grid children and a `~` selector cannot reach
 * across the one that holds the mark. */
.pillars-figure.is-assembled.is-dimmed .band { opacity: .3; }
.pillars-figure.is-assembled .band.is-lit { opacity: 1; }

.pillar-list { display: grid; gap: 1rem; }

.pillar {
    padding: 1.25rem 1.4rem;
    border: 1px solid var(--border);
    border-left: 3px solid transparent;
    border-radius: 10px;
    background: var(--bg-secondary);
    transition: border-color .25s ease, background .25s ease, transform .25s ease;
    cursor: default;
}

.pillar:hover, .pillar:focus-within {
    border-left-color: var(--accent);
    transform: translateX(3px);
}

.pillar h3 { margin-bottom: .3rem; }

@media (max-width: 780px) {
    .pillars-figure { grid-template-columns: 1fr; gap: 2rem; }
    .pillar-mark-holder { max-width: 240px; margin: 0 auto; }
}

/* ==========================================================================
   WEB-ICONS-1 — line icons replace the emoji
   ========================================================================== */

.tool-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin-bottom: 1rem;
    border-radius: 11px;
    background: color-mix(in srgb, var(--tool-color, var(--accent)) 14%, transparent);
    color: var(--tool-color, var(--accent));
}

.tool-icon svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
}

/* ==========================================================================
   Motion: respect the system preference everywhere above
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
    .pillar-mark .band {
        transition: none;
        --dy: 0px; --s: 1; --o: 1;
    }
    .pillar, .theme-toggle, .film-btn { transition: none; }
    .pillar:hover, .pillar:focus-within { transform: none; }
}

/* ==========================================================================
   WEB-BRAND-1 / layout for the restructured page
   ========================================================================== */

/* ⚠️ The generated marks are a SQUARE 200x200 viewBox. The old hand-drawn
 * header mark was 180x145 and this rule was `24px x 19px` to match it —
 * leaving that would squash the triangle. */
.site-header-brand svg {
    width: 22px;
    height: 22px;
    align-self: center;
}

.brand-mark .brand-band { fill: var(--mark-ink, #E8DDD4); }

/* The nested mark moved out of the hero and into Philosophy, where its seven
 * levels and three bands are what the section is actually about. */
.philosophy .symbol { margin: 0 auto 2rem; }

.hero-film + .app-badges { margin-top: 2.5rem; }

.email-section {
    padding: 0 2rem 5rem;
    text-align: center;
}

.email-section .email-capture { margin-top: 0; }

/* Previously inline on the element. */
.footer-social {
    display: flex;
    gap: 1.5rem;
    justify-content: center;
    margin: 1.5rem 0;
    align-items: center;
}

.footer-social a {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    opacity: 0.75;
    transition: opacity .2s ease;
}

.footer-social a:hover { opacity: 1; }

/* The FAQ's container carried `padding: 4rem 2rem; max-width: 900px` inline. */
#faq .policy-content {
    padding: 4rem 2rem;
    max-width: 900px;
}

@media (max-width: 760px) {
    .hero-film { border-radius: 12px; margin-top: 1.75rem; }
    .film-controls { right: .6rem; bottom: .6rem; }
    .film-btn { padding: .45rem .7rem; font-size: .78rem; }
}

/* ⚠️ The pillar cards inherit `text-align: center` from the section, which was
 * right when they were three columns. As a list beside the mark they read as
 * an index, and an index is left-aligned. */
.pillar-list .pillar { text-align: left; }

/* ==========================================================================
   WEB-HERO-2 — the proposition leads
   ========================================================================== */

.hero-claim {
    font-size: clamp(2.1rem, 5vw, 3.4rem);
    font-weight: 300;
    line-height: 1.12;
    letter-spacing: -0.015em;
    max-width: 16ch;
    margin: 0 auto 1rem;
    color: var(--text);
    text-wrap: balance;
}

.hero-sub {
    font-size: clamp(1rem, 1.6vw, 1.15rem);
    color: var(--text-secondary);
    max-width: 46ch;
    margin: 0 auto;
    text-wrap: balance;
}

.price-anchor {
    max-width: 54ch;
    margin: -0.5rem auto 2.5rem;
    color: var(--text-secondary);
    font-size: 0.98rem;
    text-align: center;
    text-wrap: balance;
}

/* The support channel icons are line icons now, matching the tool set. */
.channel-icon svg {
    width: 22px;
    height: 22px;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    fill: none;
}

/*
 * ⚠️ Below 340px the bar cannot hold mark + wordmark + toggle + CTA on one
 * row however tightly it is packed — measured 118px tall (two rows) at 320px
 * even after the 420px trims. Only here does the wordmark give way; the mark
 * still identifies the site and the CTA stays whole, which is the right thing
 * to keep on the narrowest screen.
 */
@media (max-width: 339px) {
    .site-header-brand { font-size: 0; gap: 0; }
    .site-header-brand svg { width: 22px; height: 22px; }
}
