/* ============================================================
   CasyStudioCo — Master stylesheet (inlined)
   ------------------------------------------------------------
   Modular split source: css/{tokens,layout,components,utilities,print}.css
   Inlined here because GitHub Pages had cache/Jekyll issues with @import
   chain (404s on sub-files). Regenerate after editing the split files:
       { header } ; cat css/tokens.css css/layout.css ... > style.css
   Cascade order is significant:
       Tokens → Layout → Components → Utilities → Print
   ============================================================ */

/* ===== tokens.css ===== */
/* ============================================================
   CasyStudioCo — Design System: Tokens ("Aurora Glass")
   ------------------------------------------------------------
   Token layer (`:root`) is the single source of truth for
   colors, type, spacing, radii, shadows and motion. Every
   component below references tokens so that re-skinning the
   studio site is one edit, not fifty.

   Tokens
     --color-*       Surfaces, ink, glass and brand accents
     --font-*        Stack + fluid type scale (clamp)
     --space-*       4px base, 1..20
     --radius-*      sm | md | lg | xl | pill
     --shadow-*      sm | md | lg | glow
     --motion-*      fast | base | slow easing curves
     --container-*   max-width + side gutter

   Breakpoints (custom properties cannot drive media queries —
   these are the canonical values, used as literals throughout
   and documented here once):
     phone   ≤ 380px
     mobile  ≤ 600px
     tablet  ≤ 720px   (aurora drift animation enables > 720px)
     desktop ≥ 960px

   Theme
     Defaults to dark — "Aurora Glass": deep warm black, frosted
     glass surfaces (white-alpha), aurora mesh backdrop, orange
     glow accents. `prefers-color-scheme: light` flips surfaces
     and ink while keeping the accent identity.
   ============================================================ */

:root {
    /* Brand */
    --color-accent:        #FF6B00;
    --color-accent-hover:  #FF8A33;
    --color-accent-ink:    #FF8A33;   /* accent used as TEXT — ≥4.5:1 on --color-bg */
    --color-accent-grad-2: #FFB066;   /* second stop for gradient headline text */
    --color-accent-soft:   rgba(255, 107, 0, 0.14);
    --color-accent-ring:   rgba(255, 107, 0, 0.40);

    /* Aurora mesh accents — low-opacity radial layers in the page
       backdrop only; they never become foreground text colour. */
    --color-mesh-warm:     rgba(255, 107, 0, 0.16);   /* primary glow */
    --color-mesh-magenta:  rgba(236, 72, 153, 0.10);  /* deep accent */
    --color-mesh-violet:   rgba(139, 92, 246, 0.10);  /* atmospheric depth */

    /* Surfaces — dark default. Glass surfaces are white-alpha so
       they pick up the aurora behind them. */
    --color-bg:            #0A0908;
    --color-bg-elev:       #131110;
    --color-surface:       rgba(255, 255, 255, 0.04);
    --color-surface-hover: rgba(255, 255, 255, 0.07);
    --color-glass:         rgba(16, 14, 12, 0.62);    /* frosted topbar */
    --color-border:        rgba(255, 255, 255, 0.09);
    --color-border-strong: rgba(255, 255, 255, 0.16);
    --color-scrim:         rgba(6, 5, 4, 0.72);       /* modal backdrop dim — stays dark in both themes */

    /* Media-card ink + surface — the app-mockup background is always dark, so
       these are NOT theme-flipped: light & dark schemes share them. */
    --color-surface-media:      #131110;                  /* solid left anchor of the readability gradient */
    --color-ink-on-media:       #F5F1EB;
    --color-ink-on-media-muted: rgba(245, 241, 235, 0.74);
    --color-ink-on-media-faint: rgba(245, 241, 235, 0.52);
    --color-accent-on-media:    #FF8A33;                  /* bright orange — readable on the dark mockup */

    /* Ink */
    --color-text:          #F5F1EB;
    --color-text-muted:    #ADA79F;
    --color-text-faint:    #8E8982;
    --color-text-on-accent:#14100C;

    /* Status */
    --color-success:       #5EEAB4;
    --color-warn:          #FBBF24;
    --color-danger:        #F87171;

    /* Typography */
    --font-sans:
        -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text",
        "Inter", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    --font-mono:
        ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

    /* Fluid type scale — min, ideal, max */
    --text-xs:   0.75rem;                                     /* 12 */
    --text-sm:   0.875rem;                                    /* 14 */
    --text-base: 1rem;                                        /* 16 */
    --text-lg:   clamp(1.0625rem, 0.98rem + 0.4vw, 1.25rem);  /* 17–20 */
    --text-xl:   clamp(1.25rem, 1.10rem + 0.7vw, 1.5rem);     /* 20–24 */
    --text-2xl:  clamp(1.5rem, 1.25rem + 1.2vw, 2.25rem);     /* 24–36 */
    --text-3xl:  clamp(2rem, 1.5rem + 2.4vw, 3rem);           /* 32–48 */
    --text-4xl:  clamp(2.75rem, 1.85rem + 4.5vw, 5.5rem);     /* 44–88, hero */

    --leading-tight: 1.08;
    --leading-snug:  1.35;
    --leading-normal:1.55;
    --leading-loose: 1.7;

    --tracking-tight: -0.03em;
    --tracking-normal: 0;
    --tracking-wide: 0.06em;

    /* Spacing — 4px base */
    --space-1:  0.25rem;   /* 4  */
    --space-2:  0.5rem;    /* 8  */
    --space-3:  0.75rem;   /* 12 */
    --space-4:  1rem;      /* 16 */
    --space-5:  1.25rem;   /* 20 */
    --space-6:  1.5rem;    /* 24 */
    --space-8:  2rem;      /* 32 */
    --space-10: 2.5rem;    /* 40 */
    --space-12: 3rem;      /* 48 */
    --space-16: 4rem;      /* 64 */
    --space-20: 5rem;      /* 80 */

    /* Radii */
    --radius-sm:   6px;
    --radius-md:   12px;
    --radius-lg:   20px;
    --radius-xl:   28px;
    --radius-pill: 999px;

    /* Shadows */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.30);
    --shadow-md: 0 6px 18px rgba(0, 0, 0, 0.35);
    --shadow-lg: 0 18px 48px rgba(0, 0, 0, 0.45);
    --shadow-glow: 0 0 48px rgba(255, 107, 0, 0.25);

    /* Motion */
    --motion-fast: 140ms cubic-bezier(0.2, 0.7, 0.2, 1);
    --motion-base: 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
    --motion-slow: 380ms cubic-bezier(0.2, 0.7, 0.2, 1);

    /* Container */
    --container-max: 1080px;
    --container-pad: clamp(1.25rem, 4vw, 2.5rem);

    /* Focus ring — two-tone: inner bg separator + outer accent-ink ring.
       Uses --color-accent-ink (not raw accent) so the indicator clears
       WCAG 2.4.11 ≥3:1 against the page in BOTH modes (light #B84800 ≈4.95:1,
       dark #FF8A33 ≈8.49:1; raw #FF6B00 would be only 2.67:1 on the light bg). */
    --focus-ring: 0 0 0 2px var(--color-bg), 0 0 0 4px var(--color-accent-ink);

    color-scheme: dark;
}

@media (prefers-color-scheme: light) {
    :root {
        --color-bg:            #FAF7F2;
        --color-bg-elev:       #FFFFFF;
        --color-surface:       rgba(255, 255, 255, 0.65);
        --color-surface-hover: rgba(255, 255, 255, 0.92);
        --color-glass:         rgba(255, 253, 250, 0.72);
        --color-border:        rgba(26, 23, 20, 0.10);
        --color-border-strong: rgba(26, 23, 20, 0.18);

        --color-text:          #16120E;
        --color-text-muted:    #4E4942;
        --color-text-faint:    #6F6962;
        --color-text-on-accent:#14100C;

        --color-accent-ink:    #B84800;
        --color-accent-grad-2: #E06A00;
        --color-accent-soft:   rgba(255, 107, 0, 0.10);
        --color-accent-ring:   rgba(255, 107, 0, 0.35);

        --color-success:       #197A43;   /* ≈5.03:1 on light bg — was #1F8A4D (4.1:1) */
        --color-warn:          #8F5400;   /* ≈5.72:1 on light bg — was #A86200 (4.45:1) */
        --color-danger:        #C2410C;

        /* Aurora layers stay warmer & lighter on the bright surface */
        --color-mesh-warm:     rgba(255, 107, 0, 0.10);
        --color-mesh-magenta:  rgba(236, 72, 153, 0.07);
        --color-mesh-violet:   rgba(139, 92, 246, 0.07);

        --shadow-sm: 0 1px 2px rgba(20, 17, 15, 0.06);
        --shadow-md: 0 6px 18px rgba(20, 17, 15, 0.08);
        --shadow-lg: 0 18px 48px rgba(20, 17, 15, 0.12);
        --shadow-glow: 0 0 48px rgba(255, 107, 0, 0.18);

        color-scheme: light;
    }
}

/* ===== layout.css ===== */
/* ============================================================
   Layout — reset, base typography, page structure, responsive
   ============================================================ */

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

html {
    -webkit-text-size-adjust: 100%;
    text-rendering: optimizeLegibility;
    overflow-x: clip;
}

body {
    font-family: var(--font-sans);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--color-text);
    /* Aurora backdrop — static radial layers stacked on the solid
       surface token so light/dark mode just works. Kept to three
       layers for performance (Lighthouse-safe). The animated drift
       layer lives on body::before and only enables on desktop. */
    background-color: var(--color-bg);
    background-image:
        radial-gradient(42% 38% at 18% 8%,  var(--color-mesh-warm)    0%, transparent 70%),
        radial-gradient(36% 32% at 85% 18%, var(--color-mesh-magenta) 0%, transparent 70%),
        radial-gradient(50% 44% at 60% 96%, var(--color-mesh-violet)  0%, transparent 70%);
    background-attachment: fixed;
    background-repeat: no-repeat;
    min-height: 100dvh;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: clip;
}

/* Mobile devices struggle with `background-attachment: fixed` (jank,
   over-paint). Fall back to scrolled background — visually identical. */
@media (max-width: 720px) {
    body { background-attachment: scroll; }
}

/* Aurora drift — desktop + motion-tolerant users only. A blurred,
   slowly breathing duplicate of the mesh adds the "alive" quality
   without costing mobile paint budget. */
@media (min-width: 721px) and (prefers-reduced-motion: no-preference) {
    body::before {
        content: "";
        position: fixed;
        inset: -20%;
        z-index: -1;
        pointer-events: none;
        background:
            radial-gradient(42% 38% at 18% 12%, var(--color-mesh-warm)    0%, transparent 70%),
            radial-gradient(36% 32% at 85% 8%,  var(--color-mesh-magenta) 0%, transparent 70%),
            radial-gradient(50% 44% at 70% 88%, var(--color-mesh-violet)  0%, transparent 70%);
        filter: blur(40px);
        animation: aurora-drift 28s cubic-bezier(0.2, 0.7, 0.2, 1) infinite alternate;
    }
    @keyframes aurora-drift {
        from { transform: translate3d(-2%, -1%, 0) scale(1); }
        to   { transform: translate3d(2%, 2%, 0) scale(1.06); }
    }
}

img, svg { display: block; max-width: 100%; }

a { color: var(--color-accent-ink); text-decoration: none; }
a:hover { color: var(--color-accent-hover); }

::selection { background: var(--color-accent); color: var(--color-text-on-accent); }

:focus { outline: none; }
:focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-sm);
}
/* Windows High Contrast / forced-colors strips box-shadow, so the focus
   halo above would vanish. Restore a system-colour outline there. */
@media (forced-colors: active) {
    :focus-visible {
        outline: 2px solid CanvasText;
        outline-offset: 2px;
    }
}

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

/* ============================================================
   Container
   ============================================================ */

.container {
    max-width: var(--container-max);
    margin: 0 auto;
    padding: var(--space-6) var(--container-pad) var(--space-16);
}

/* Slim container for legal/text pages */
.container.container--narrow { max-width: 760px; }

/* ============================================================
   Base typography
   ============================================================ */

h1, h2, h3, h4 {
    font-family: var(--font-sans);
    color: var(--color-text);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
    font-weight: 700;
}

h1 { font-size: var(--text-3xl); }
h2 { font-size: var(--text-xl); margin-top: var(--space-8); margin-bottom: var(--space-3); }
h3 { font-size: var(--text-lg); }

p, li {
    font-size: var(--text-base);
    line-height: var(--leading-loose);
    color: var(--color-text-muted);
    margin-bottom: var(--space-3);
}
strong { color: var(--color-text); }
ul { padding-left: var(--space-5); margin-bottom: var(--space-4); }
li { margin-bottom: var(--space-1); }

.welcome { /* legacy: kept for compat — small eyebrow */
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: var(--tracking-wide);
    font-weight: 600;
    margin-bottom: var(--space-3);
}

.section-title {
    font-size: var(--text-2xl);
    font-weight: 700;
    color: var(--color-text);
    letter-spacing: var(--tracking-tight);
}

.subtitle {
    font-size: var(--text-lg);
    color: var(--color-text-muted);
    line-height: var(--leading-snug);
    max-width: 60ch;
    margin-bottom: var(--space-12);
}

.date { color: var(--color-text-faint); font-size: var(--text-sm); margin-bottom: var(--space-10); }

/* Sub-page legacy heading variant */
h1.page-title {
    font-size: var(--text-2xl);
    margin-bottom: var(--space-2);
    color: var(--color-text);
}

/* ============================================================
   Top bar — frosted glass pill, sticky
   Same markup on landing and every sub-page; only blurs where
   the browser actually supports backdrop-filter (solid glass
   token is the fallback either way).
   ============================================================ */

.topbar {
    position: sticky;
    top: var(--space-4);
    z-index: 40;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-12);
    padding: var(--space-2) var(--space-4);
    background: var(--color-glass);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-sm);
}
@supports ((backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px))) {
    .topbar {
        backdrop-filter: blur(20px) saturate(140%);
        -webkit-backdrop-filter: blur(20px) saturate(140%);
    }
}

.wordmark {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--color-text);
    font-weight: 700;
    letter-spacing: -0.01em;
    font-size: var(--text-base);
}
/* Renders the "Geometric Orbit" glyph from favicon.svg (inlined as a
   data URI so the brand mark is identical everywhere). The mark is
   transparent — no badge background or glow. The "CS" text in the
   span stays for robustness but is made transparent. */
.wordmark-mark {
    width: 30px;
    height: 30px;
    background-image:
        url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'><defs><linearGradient id='c' x1='0' y1='0' x2='0' y2='1'><stop offset='0' stop-color='%23FFB066'/><stop offset='0.6' stop-color='%23FF6B00'/><stop offset='1' stop-color='%23EC4899'/></linearGradient></defs><g fill='none' stroke-linecap='round'><path d='M47.5 9.9 A27 27 0 1 0 47.5 54.1' stroke='%23FF6B00' stroke-width='5'/><path d='M39.8 18.5 A9 9 0 1 0 32 32 A9 9 0 1 1 24.2 45.5' stroke='url(%23c)' stroke-width='8'/></g></svg>");
    background-size: 100% 100%;
    color: transparent;
    display: grid;
    place-items: center;
    font-size: 13px;
    font-weight: 900;
    letter-spacing: -0.04em;
}

/* Sub-page back link (legacy) */
.back {
    color: var(--color-accent-ink);
    font-size: var(--text-sm);
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin-bottom: var(--space-6);
}
.back:hover { color: var(--color-accent-hover); }

/* Sub-page nav */
nav { display: flex; gap: var(--space-5); margin-bottom: var(--space-10); flex-wrap: wrap; }
nav a { color: var(--color-text-muted); font-size: var(--text-sm); font-weight: 500; }
nav a:hover { color: var(--color-accent-ink); }

/* ============================================================
   Hero — centered, oversized type, gradient accent, glow CTA
   The aurora on <body> carries the atmosphere; this block owns
   typography + spacing only.
   ============================================================ */

.hero {
    position: relative;
    padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(2.5rem, 6vw, 4.5rem);
    text-align: center;
}
.hero .eyebrow {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    padding: var(--space-2) var(--space-4);
    margin-bottom: var(--space-8);
}
.hero .eyebrow::before {
    content: "";
    width: 6px; height: 6px;
    border-radius: 50%;
    background: var(--color-accent);
    flex-shrink: 0;
}
.hero h1 {
    font-size: var(--text-4xl);
    line-height: var(--leading-tight);
    letter-spacing: var(--tracking-tight);
    font-weight: 700;
    color: var(--color-text);
    margin: 0 auto var(--space-6);
    max-width: 17ch;
    overflow-wrap: break-word;
}
.hero h1 .accent {
    /* Solid accent ink (calmer, less "AI gradient"); --color-accent-ink is
       the ≥4.5:1 text-safe accent in both modes. The gradient token
       (--color-accent-grad-2) stays defined but is no longer used here. */
    color: var(--color-accent-ink);
}
.hero .lede {
    font-size: var(--text-lg);
    color: var(--color-text-muted);
    line-height: var(--leading-snug);
    max-width: 52ch;
    margin: 0 auto var(--space-10);
}

.hero-cta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: center;
    justify-content: center;
}
.hero-cta__primary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 48px;
    min-width: 12.5rem;
    padding: 0 var(--space-8);
    background: var(--color-accent);
    color: var(--color-text-on-accent);
    border-radius: var(--radius-pill);
    font-weight: 700;
    font-size: var(--text-base);
    letter-spacing: -0.01em;
    box-shadow: var(--shadow-glow);
    transition: background var(--motion-fast), transform var(--motion-fast), box-shadow var(--motion-base);
}
.hero-cta__primary:hover {
    background: var(--color-accent-hover);
    color: var(--color-text-on-accent);
    transform: translateY(-2px);
    box-shadow: var(--shadow-glow), var(--shadow-md);
}
.hero-cta__secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 48px;
    min-width: 12.5rem;
    padding: 0 var(--space-8);
    color: var(--color-text);
    font-weight: 600;
    font-size: var(--text-base);
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    transition: background var(--motion-fast), transform var(--motion-fast), border-color var(--motion-fast);
}
.hero-cta__secondary:hover {
    color: var(--color-text);
    background: var(--color-surface-hover);
    transform: translateY(-2px);
}
@media (prefers-reduced-motion: reduce) {
    .hero-cta__primary:hover,
    .hero-cta__secondary:hover { transform: none; }
}

/* ============================================================
   Section header
   ============================================================ */

.section-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    margin-bottom: var(--space-6);
    flex-wrap: wrap;
}
.section-head .section-title { margin: 0; }
.section-head .section-meta {
    color: var(--color-text-faint);
    font-size: var(--text-sm);
    font-variant-numeric: tabular-nums;
}

/* ============================================================
   App grid — bento (cards live in components.css)
   Featured cards span the full row via the `app-card--featured`
   modifier rendered by the landing JS; multiple featured cards stack.
   ============================================================ */

.app-grid {
    display: grid;
    /* Two faithful keynote cards side by side; stacks to one column below. */
    grid-template-columns: 1fr 1fr;
    gap: var(--space-6);
    align-items: start;
    margin-bottom: var(--space-16);
    /* reserve space so async render of cards does not shift the page (CLS) */
    min-height: 280px;
}
/* Showcase cards (copy left, real device row right) are a wide layout: they
   always claim the full grid row and stack vertically, never sharing a row as
   half-width cards. Visual/device styles live in components.css. */
.app-grid .app-card--showcase { grid-column: 1 / -1; }
@media (max-width: 900px) {
    .app-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   Footer (landing)
   ============================================================ */

.site-footer {
    margin-top: var(--space-16);
    padding-top: var(--space-10);
    border-top: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    display: grid;
    gap: var(--space-6);
    grid-template-columns: 1fr;
}
.site-footer__brand { display: flex; flex-direction: column; gap: var(--space-2); }
.site-footer__brand .wordmark { font-size: var(--text-base); }
.site-footer__brand p { margin: 0; max-width: 42ch; }
.site-footer__row {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-6) var(--space-8);
    align-items: center;
    justify-content: space-between;
}
.site-footer__links { display: flex; flex-wrap: wrap; gap: var(--space-5); }
.site-footer__links a {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    font-weight: 500;
}
.site-footer__links a:hover { color: var(--color-accent-ink); }
.site-footer__legal {
    color: var(--color-text-faint);
    font-size: var(--text-xs);
    font-family: var(--font-mono);
    letter-spacing: 0;
}
.site-footer__note {
    color: var(--color-text-faint);
    font-size: var(--text-xs);
    max-width: 64ch;
    margin: 0;
}

/* Sub-page footer (legacy <footer>) */
footer:not(.site-footer) {
    margin-top: var(--space-16);
    padding-top: var(--space-6);
    border-top: 1px solid var(--color-border);
    color: var(--color-text-faint);
    font-size: var(--text-sm);
}

/* ============================================================
   Responsive (mobile-first overrides)
   The fluid type + auto-fill grid handle most cases. Below
   we tighten spacing for small screens and stack the footer.
   ============================================================ */

@media (min-width: 720px) {
    .site-footer {
        grid-template-columns: 1.4fr 1fr;
        align-items: start;
    }
    .site-footer__row { justify-content: flex-end; }
}

@media (max-width: 600px) {
    .container { padding: var(--space-4) var(--container-pad) var(--space-12); }
    .topbar { margin-bottom: var(--space-8); top: var(--space-2); }
    .hero h1 { max-width: none; }
    .app-grid { gap: var(--space-4); }
}

@media (max-width: 380px) {
    .container { padding: var(--space-3) var(--space-4) var(--space-10); }
    .topbar { gap: var(--space-2); }
    .wordmark span:not(.wordmark-mark) { display: none; }
    .site-footer__row { flex-direction: column; align-items: flex-start; gap: var(--space-4); }
}

/* ===== components.css ===== */
/* ============================================================
   Pill toggle (language switch)
   ============================================================ */

.lang-switch {
    display: inline-flex;
    align-items: center;
    padding: 3px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    gap: 2px;
}
.lang-switch a,
.lang-switch button {
    appearance: none;
    border: 0;
    cursor: pointer;
    font-family: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 44px;
    min-height: 38px;
    padding: 0 var(--space-3);
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-wide);
    color: var(--color-text-muted);
    background: transparent;
    transition: color var(--motion-fast), background var(--motion-fast);
}
.lang-switch a:hover,
.lang-switch button:hover { color: var(--color-text); }
.lang-switch a.active,
.lang-switch button.active {
    background: var(--color-accent);
    color: var(--color-text-on-accent);
    box-shadow: var(--shadow-sm);
}

/* ============================================================
   App cards — frosted glass with top hairline highlight
   ============================================================ */

/* Card shell — keynote-faithful: vertical flow (icon, name, category,
   description, meta, foot), full-bleed mockup behind, clipped to the radius.
   Per-element margins (not a flex gap) drive the interior rhythm. */
.app-card {
    position: relative;
    display: flex;
    flex-direction: column;
    padding: var(--space-8);
    /* Solid fallback first (browsers without backdrop-filter). */
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-xl);
    transition:
        transform var(--motion-base),
        border-color var(--motion-base),
        background var(--motion-base),
        box-shadow var(--motion-base);
    isolation: isolate;
    min-height: 240px;
    overflow: hidden;
}
@supports ((backdrop-filter: blur(20px)) or (-webkit-backdrop-filter: blur(20px))) {
    .app-card {
        backdrop-filter: blur(20px) saturate(140%);
        -webkit-backdrop-filter: blur(20px) saturate(140%);
    }
}
/* Top hairline — the "lit edge" that sells the glass. */
.app-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--color-border-strong), transparent);
    pointer-events: none;
    z-index: 3;
}

/* Full-bleed rendered mockup as the card background (device to the right,
   mist to the left). Clipped to the card radius; purely decorative. */
.app-card__bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    overflow: hidden;
    border-radius: inherit;
}
.app-card__bg img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: 76% center;   /* holds the device in the right third */
    display: block;
}
/* Readability gradient: solid-dark on the left for the text column,
   clearing to transparent on the right so the device stays visible. */
.app-card__bg::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg,
        var(--color-surface-media) 3%,
        rgba(19, 17, 16, 0.82) 28%,
        rgba(19, 17, 16, 0.22) 58%,
        transparent 82%);
}

/* Warm corner glow (decorative) — echoes the keynote card. Sits behind the
   card content and is clipped by the card's overflow:hidden. Orange-only. */
.app-card__glow {
    position: absolute;
    top: -30%;
    right: -25%;
    width: 65%;
    aspect-ratio: 1 / 1;
    z-index: 1;
    pointer-events: none;
    background: radial-gradient(closest-side, var(--color-accent-soft), transparent);
}
/* Lift real card content above the decorative bg + glow layers. */
.app-card > *:not(.app-card__glow):not(.app-card__bg) { position: relative; z-index: 2; }

.app-card:hover {
    transform: translateY(-4px);
    border-color: var(--color-border-strong);
    background: var(--color-surface-hover);
    box-shadow: var(--shadow-lg);
}
/* No card-level focus treatment: an accent border/ring around the whole card
   was too loud (especially after closing the "Learn more" overlay, when focus
   returns to the in-card trigger). Keyboard focus stays visible on the
   interactive elements themselves via the global :focus-visible ring (layout.css). */
@media (prefers-reduced-motion: reduce) {
    .app-card:hover { transform: none; }
}

/* Deep-link highlight — a brief accent ring + glow when an app is opened via
   /?app=<folder>. JS adds .app-card--deeplink for ~1.4s on initial load, then
   removes it; the keyframe fades both back to the card's resting state (no
   jump). reduced-motion users never get the class (JS-guarded); the media
   query below is belt-and-suspenders. */
.app-card--deeplink {
    animation: app-card-deeplink 1.4s ease-out 1;
}
@keyframes app-card-deeplink {
    0%, 55% {
        border-color: var(--color-accent);
        box-shadow: 0 0 0 3px var(--color-accent-ring), 0 0 48px rgba(255, 107, 0, 0.25);
    }
    100% {
        border-color: var(--color-border);
        box-shadow: 0 0 0 0 rgba(255, 107, 0, 0), 0 0 48px rgba(255, 107, 0, 0);
    }
}
@media (prefers-reduced-motion: reduce) {
    .app-card--deeplink { animation: none; }
}

/* Media variant — a card carrying a full-bleed rendered mockup (app.cardImage).
   Reserve the right third for the device and give it the keynote card height.
   `.app-card--featured` is kept on these cards purely as the deep-link hook
   (JS queries `.app-card--featured[data-app]`); it no longer changes layout. */
.app-card--media {
    padding-right: 214px;   /* clear the device area of the background image */
    min-height: 482px;
}

/* ============================================================
   Showcase variant (app.devices[]) — copy left, a row of real
   Apple-bezel device PNGs right. Replaces the single tilted
   composite mockup with straight, side-by-side devices.

   Apple guideline (hard): the PNGs already carry bezel + screenshot
   on a transparent background and are used AS-IS — this CSS only
   sizes/positions them. NO transform:rotate, NO added reflection,
   shadow or gloss on the device, NO mirror. The card carries its own
   violet/blue CSS glow ground (a gradient, not an image).

   Always an intrinsically dark context, so ink is forced light
   (like media cards, below). Spans the full grid row (layout.css).
   The device row takes a variable number of devices (ShutterLife 2,
   Sequence 1) and can grow later (Mac, Watch) without markup change.
   ============================================================ */
.app-card--showcase {
    display: grid;
    grid-template-columns: minmax(260px, 0.9fr) minmax(0, 1.35fr);
    gap: clamp(var(--space-6), 4vw, var(--space-12));
    align-items: center;
    padding: clamp(var(--space-6), 4vw, var(--space-10));
    min-height: 420px;
}
/* Violet/blue glow ground — a CSS gradient, no image, no reflection.
   Declared for the resting AND hover state so the card's generic
   :hover (which repaints background to a light glass surface) never
   flashes the violet away; the hover lift/border/shadow still apply. */
.app-card--showcase,
.app-card--showcase:hover {
    background:
        radial-gradient(66% 78% at 70% 80%, rgba(120, 108, 255, 0.30), rgba(74, 62, 158, 0.12) 46%, transparent 74%),
        linear-gradient(150deg, #151125 0%, #0c0913 58%, #0a0810 100%);
}

/* Copy column — same vertical flow as a plain card, left-aligned. */
.app-card__body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    min-width: 0;
}

/* Device row — straight devices on a shared baseline, largest first
   (→ leftmost on desktop). Right-aligned; wraps big-device-on-top on
   narrow screens (responsive section below). */
.app-card__devices {
    display: flex;
    align-items: flex-end;          /* shared baseline, like Apple's rows */
    justify-content: space-evenly;  /* spread devices across the row, even gaps + edge padding */
    flex-wrap: nowrap;
    gap: clamp(var(--space-2), 1.2vw, var(--space-4));
    width: 100%;
    min-width: 0;
}
.device-slot {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    flex: 0 0 auto;
}
/* Size by height, keep aspect ratio, never distort or rotate. max-width
   guards against overflow if a slot goes full-width (mobile wrap). */
.device {
    display: block;
    width: auto;
    max-width: 100%;
    object-fit: contain;
}
/* Real-proportional heights: the iPad reads clearly larger than the
   iPhone (taller frame + wider aspect ratio). Fluid, capped at the
   desktop sizes from the verified mockup. */
.device--iphone { height: clamp(150px, 14.3vw, 176px); }
.device--ipad   { height: clamp(166px, 15.8vw, 192px); }
.device--mac    { height: clamp(126px, 12.6vw, 162px); }
.device--watch  { height: clamp(82px, 7.8vw, 104px); }

/* Violet glow puck behind the device row (extra pop, echoes the
   mockup). Repositions the shared warm glow element to the right and
   recolours it — decorative, sits behind the devices (z-index below). */
.app-card--showcase .app-card__glow {
    top: 20%;
    right: 2%;
    width: 48%;
    max-width: 560px;
    background: radial-gradient(circle, rgba(126, 112, 255, 0.32), transparent 60%);
}

/* App icon — sits alone at the top of the card (keynote layout). Rounded
   badge; monogram fallback when there is no real icon. */
.app-icon {
    width: 54px; height: 54px;
    border-radius: 15px;
    flex-shrink: 0;
    align-self: flex-start;
    display: grid;
    place-items: center;
    /* >=14pt bold = Large Text per WCAG, satisfies 3:1 on coloured backgrounds */
    font-size: 20px;
    font-weight: 900;
    color: #fff;
    letter-spacing: -0.04em;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.30);
    box-shadow:
        inset 0 1px 0 rgba(255,255,255,0.2),
        0 4px 12px rgba(0,0,0,0.25);
}
/* Real app icon (apps/icons/<folder>.png) — same footprint and rounded
   mask as the monogram badge, so live apps and fallbacks line up. */
.app-icon--img {
    display: block;
    object-fit: cover;
    background: var(--color-bg-elev);
}

/* Name — keynote size, allowed to wrap (no ellipsis truncation). */
.app-card h3,
.app-card__name {
    margin: var(--space-5) 0 0;
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-text);
    letter-spacing: -0.01em;
    line-height: 1.2;
}

/* Accent audience/category sub-label — the keynote's coloured line under the
   name (e.g. "For photographers"). Rendered only when app.cat is set. */
.app-card__cat {
    margin: var(--space-1) 0 0;
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--color-accent-ink);
}

/* Description — keynote reading measure, no line clamp. */
.app-card__desc {
    margin: var(--space-3) 0 0;
    max-width: 34ch;
    font-size: var(--text-base);
    color: var(--color-text-muted);
    line-height: var(--leading-snug);
}

/* Platform meta line ("iOS · macOS") — quiet mono credential, keynote-style. */
.app-card__meta {
    margin: var(--space-3) 0 0;
    font-size: var(--text-xs);
    font-family: var(--font-mono);
    letter-spacing: -0.01em;
    color: var(--color-text-faint);
}

/* Foot — a fixed vertical stack so both cards read identically: "Learn more"
   on top, the store slot directly below (Apple badge for live apps, the
   "Coming soon"/"Bald" pill otherwise). Template order is trigger → store. */
.app-card__foot {
    margin-top: auto;
    padding-top: var(--space-6);
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-3);
}

/* Official Apple App Store badge — used unmodified, ~40px, with clear space
   around it (Apple badge guidelines). Only rendered for genuinely live apps. */
.app-card__store {
    display: inline-flex;
    align-items: center;
    padding: var(--space-1);   /* clear space so nothing crowds the badge */
    border-radius: var(--radius-md);
    line-height: 0;
    transition: transform var(--motion-fast);
}
.app-card__store:hover { transform: translateY(-1px); }
.app-card__store img {
    height: 40px;
    width: auto;
    display: block;
}
@media (prefers-reduced-motion: reduce) {
    .app-card__store:hover { transform: none; }
}

/* QR on the card itself, next to the badge. Hidden by default for the same
   reason as in the overlay: on a touch device the badge is the shorter path.
   Restricted to showcase cards on purpose — they claim the full grid row, so
   there is room beside the badge. A narrow card in a multi-column grid would
   have to shrink the code to a size nobody can scan. */
.app-card__qr { display: none; }

/* Badge and QR share one row, the same pairing as in the overlay. The foot
   itself stacks vertically (Learn more, then this row), so the wrapper is what
   keeps the two download routes beside each other instead of below. */
.app-card__get {
    display: flex;
    align-items: flex-start;   /* top edges on one line, see the QR block below */
    gap: var(--space-4);
    flex-wrap: wrap;
}

@media (min-width: 860px) and (pointer: fine) {
    /* Hint BESIDE the code, not under it (owner, 14.08.). Stacked, the block
       stood 100px tall next to a 48px button and read as a second, unrelated
       thing rather than the button's neighbour. Side by side it is only as tall
       as the code itself. */
    .app-card--showcase .app-card__qr {
        display: flex;
        flex-direction: row;
        align-items: center;
        gap: var(--space-2);
        /* The badge link carries 4px of clear space above its artwork
           (.app-card__store padding). Matching it here starts the code on the
           same line as the badge artwork, not 4px above it. */
        padding-top: var(--space-1);
    }
    .app-card--showcase .app-card__qr img {
        display: block;
        flex: none;                 /* the code is square — never let the text squeeze it */
        width: 72px;
        height: 72px;
        padding: 5px;               /* the quiet zone scanners need */
        background: #fff;           /* stays white in dark mode: a QR needs the contrast */
        border-radius: var(--radius-sm);
        color: #000;                /* the SVG draws its modules in currentColor */
    }
    .app-card--showcase .app-card__qr span {
        font-size: 0.7rem;
        line-height: 1.3;
        /* Two short lines beside the code. Wider and it starts competing with
           the card's own description for the eye. */
        max-width: 84px;
        color: var(--color-text-muted);
    }
}

/* "Coming soon"/"Bald" pill — shown instead of a badge for apps that declare
   store intent but are not in the App Store yet (status:"soon"). Non-interactive
   (a <span>), never a dead 404 link. Same guard as before (realStoreUrl()). */
.app-card__soon {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 var(--space-4);
    border-radius: var(--radius-pill);
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    color: var(--color-text-faint);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: 0;
    cursor: default;
}

/* Media cards are an always-dark context (the mockup + gradient stay dark in
   both colour schemes), so their ink is forced light regardless of theme. */
.app-card--media h3,
.app-card--media .app-card__name  { color: var(--color-ink-on-media); }
.app-card--media .app-card__desc  { color: var(--color-ink-on-media-muted); }
.app-card--media .app-card__meta  { color: var(--color-ink-on-media-faint); }
.app-card--media .app-card__cat   { color: var(--color-accent-on-media); }
.app-card--media .app-card__soon {
    border-color: rgba(255, 255, 255, 0.20);
    background: rgba(255, 255, 255, 0.05);
    color: var(--color-ink-on-media-muted);
}

/* Showcase cards share the media cards' always-dark (violet) context, so
   their ink is forced light in both colour schemes too. */
.app-card--showcase .app-card__name { color: var(--color-ink-on-media); }
.app-card--showcase .app-card__desc { color: var(--color-ink-on-media-muted); }
.app-card--showcase .app-card__meta { color: var(--color-ink-on-media-faint); }
.app-card--showcase .app-card__cat  { color: var(--color-accent-on-media); }
.app-card--showcase .app-card__soon {
    border-color: rgba(255, 255, 255, 0.20);
    background: rgba(255, 255, 255, 0.05);
    color: var(--color-ink-on-media-muted);
}

.empty-state {
    grid-column: 1 / -1;
    padding: var(--space-12);
    text-align: center;
    color: var(--color-text-muted);
    background: var(--color-surface);
    border: 1px dashed var(--color-border-strong);
    border-radius: var(--radius-xl);
}

/* ============================================================
   Legal links + FAQ (sub-pages)
   ============================================================ */

.legal-links { display: flex; flex-direction: column; gap: var(--space-3); }
.legal-links a {
    display: block;
    padding: var(--space-4) var(--space-5);
    background: var(--color-surface);
    border-radius: var(--radius-md);
    color: var(--color-text);
    font-size: var(--text-base);
    font-weight: 600;
    border: 1px solid var(--color-border);
    transition: border-color var(--motion-base), background var(--motion-base);
}
.legal-links a:hover {
    border-color: var(--color-border-strong);
    background: var(--color-surface-hover);
    color: var(--color-text);
}
.legal-links a span {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    font-weight: 400;
    display: block;
    margin-top: var(--space-1);
}

.faq {
    position: relative;
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: var(--space-5) var(--space-6);
    margin-bottom: var(--space-3);
    border: 1px solid var(--color-border);
    overflow: hidden;
}
.faq::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    background: linear-gradient(90deg, transparent, var(--color-border-strong), transparent);
    pointer-events: none;
}
.faq h3 { font-size: var(--text-base); margin-bottom: var(--space-2); color: var(--color-text); }
.faq p { margin-bottom: 0; font-size: var(--text-sm); }

/* ============================================================
   Callout — accent-tinted note box (e.g. "authoritative legal
   notice" pointer on app impressum pages). Replaces the old
   inline-styled paragraphs; works in dark and light mode.
   ============================================================ */

.callout {
    background: var(--color-accent-soft);
    border-left: 4px solid var(--color-accent);
    border-radius: var(--radius-sm);
    padding: var(--space-3) var(--space-4);
    margin: var(--space-4) 0;
}

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

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: var(--space-3) var(--space-6);
    background: var(--color-accent);
    color: var(--color-text-on-accent);
    border-radius: var(--radius-pill);
    font-weight: 700;
    font-size: var(--text-base);
    box-shadow: var(--shadow-sm);
    transition: background var(--motion-fast), transform var(--motion-fast);
    margin-top: var(--space-2);
}
.btn:hover { background: var(--color-accent-hover); color: var(--color-text-on-accent); transform: translateY(-1px); }
@media (prefers-reduced-motion: reduce) {
    .btn:hover { transform: none; }
}

/* ============================================================
   Sub-page pattern (Privacy / Support / Terms / Impressum)
   ============================================================ */

.subpage-eyebrow {
    color: var(--color-accent-ink);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    margin: 0 0 var(--space-2);
}

.back-link {
    color: var(--color-text-muted);
    font-size: var(--text-sm);
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    margin-bottom: var(--space-6);
    transition: color var(--motion-fast);
}
.back-link:hover { color: var(--color-accent-ink); }

.container--narrow h1.page-title {
    font-size: var(--text-3xl);
    margin-bottom: var(--space-2);
}

.legal-content { margin-top: var(--space-8); }
.legal-content > h2 {
    margin-top: var(--space-10);
    padding-top: var(--space-6);
    border-top: 1px solid var(--color-border);
    font-size: var(--text-lg);
}
.legal-content > h2:first-of-type {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}
.legal-content > h3 {
    margin-top: var(--space-5);
    font-size: var(--text-base);
    color: var(--color-text);
}
.legal-content > p,
.legal-content > ul {
    margin-bottom: var(--space-4);
    max-width: 68ch;
}
.legal-content .btn { margin-bottom: var(--space-4); }

/* ============================================================
   Detail trigger — in-card button that opens the app overlay.
   Its OWN action, visually distinct from the orange store pill.
   ============================================================ */

.detail-trigger {
    appearance: none;
    font-family: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    min-height: 44px;
    padding: 10px var(--space-4);
    border-radius: var(--radius-pill);
    border: 1px solid var(--color-border-strong);
    background: var(--color-surface);
    color: var(--color-text);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: 0;
    transition:
        border-color var(--motion-fast),
        background var(--motion-fast),
        color var(--motion-fast),
        gap var(--motion-fast);
}
.detail-trigger:hover {
    border-color: var(--color-accent);
    background: var(--color-surface-hover);
    color: var(--color-accent-ink);
    gap: var(--space-3);   /* keynote link-arrow: arrow nudges on hover */
}
.detail-trigger svg { width: 14px; height: 14px; }
@media (prefers-reduced-motion: reduce) {
    .detail-trigger:hover { gap: var(--space-2); }
}

/* Media context: the trigger sits on the dark mockup, so it takes light ink
   and a light-alpha surface (theme-independent) to stay readable. */
.app-card--media .detail-trigger {
    border-color: rgba(255, 255, 255, 0.20);
    background: rgba(255, 255, 255, 0.06);
    color: var(--color-ink-on-media);
}
.app-card--media .detail-trigger:hover {
    border-color: var(--color-accent);
    background: rgba(255, 255, 255, 0.10);
    color: #fff;
}
/* Same dark-context treatment for the showcase card trigger. */
.app-card--showcase .detail-trigger {
    border-color: rgba(255, 255, 255, 0.20);
    background: rgba(255, 255, 255, 0.06);
    color: var(--color-ink-on-media);
}
.app-card--showcase .detail-trigger:hover {
    border-color: var(--color-accent);
    background: rgba(255, 255, 255, 0.10);
    color: #fff;
}

/* ============================================================
   App-detail overlay (modal dialog)
   Vanilla, no dependency. `[hidden]` keeps it out of the layout
   and a11y tree; `.is-open` drives the fade/scale-in. Reduced
   motion is handled by the global transition-killing rule.
   ============================================================ */

.overlay {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    opacity: 0;
    transition: opacity var(--motion-base);
}
/* Author rule beats the UA `[hidden]{display:none}` only with this
   extra specificity — without it the flex display would leak. */
.overlay[hidden] { display: none; }
.overlay.is-open { opacity: 1; }

.overlay__backdrop {
    position: absolute;
    inset: 0;
    background: var(--color-scrim);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.overlay__dialog {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(960px, 100%);
    max-height: calc(100vh - var(--space-8));
    max-height: calc(100dvh - var(--space-8));
    overflow: hidden;
    background: var(--color-bg-elev);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-xl);
    box-shadow: var(--shadow-lg);
    transform: translateY(12px) scale(0.985);
    transition: transform var(--motion-base);
}
.overlay.is-open .overlay__dialog { transform: none; }

/* Warm top hairline — the same lit edge the app cards carry, tying the modal
   to the new card look. Decorative, non-interactive, orange-only. */
.overlay__dialog::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 1px;
    z-index: 3;
    background: linear-gradient(90deg, transparent, var(--color-accent-ring), transparent);
    pointer-events: none;
}

.overlay__close {
    position: absolute;
    top: var(--space-4);
    right: var(--space-4);
    z-index: 2;
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text);
    border-radius: var(--radius-pill);
    font-size: 26px;
    line-height: 1;
    cursor: pointer;
    transition: background var(--motion-fast), border-color var(--motion-fast);
}
.overlay__close:hover {
    background: var(--color-surface-hover);
    border-color: var(--color-border-strong);
}

.overlay__header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-5) var(--space-6);
    padding-right: var(--space-16);
    border-bottom: 1px solid var(--color-border);
}
.overlay__icon {
    width: 56px;
    height: 56px;
    flex-shrink: 0;
    border-radius: 14px;
    object-fit: cover;
    background: var(--color-bg);
    box-shadow: inset 0 1px 0 rgba(255,255,255,0.15), 0 4px 12px rgba(0,0,0,0.25);
}
.overlay__title {
    margin: 0;
    font-size: var(--text-xl);
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--color-text);
}
.overlay__platform {
    margin: 2px 0 0;
    font-size: var(--text-sm);
    color: var(--color-text-muted);
    font-family: var(--font-mono);
}

.overlay__body {
    flex: 1 1 auto;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    display: grid;
    gap: var(--space-6);
    padding: var(--space-6);
}
@media (min-width: 760px) {
    .overlay__body {
        grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
        gap: var(--space-8);
        align-items: start;
        padding: var(--space-8);
    }
}

/* Gallery */
/* One source for the gallery height: the viewport and the arrow buttons both
   read it, and they used to carry the same literal twice. Raised from
   min(58vh, 520px) on 2026-08-12 — at that size a whole phone rendered 463px
   tall, which put 17pt app text at 8.7 CSS px, roughly half the size of the
   body copy sitting next to it. Unreadable regardless of image sharpness.
   The vh term keeps short windows from overflowing the dialog. */
.overlay__gallery {
    position: relative;
    min-width: 0;
    --overlay-gallery-h: min(70vh, 720px);
}
.overlay__viewport {
    overflow: hidden;
    height: var(--overlay-gallery-h);
}
.overlay__track {
    display: flex;
    height: 100%;
    transition: transform var(--motion-base);
}
.overlay__slide {
    flex: 0 0 100%;
    min-width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    box-sizing: border-box;
}
/* Screenshots are pre-framed iPhone composites (real Apple bezel); shown as-is. */
.overlay__shot {
    display: block;
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.overlay__nav {
    position: absolute;
    top: calc(var(--overlay-gallery-h) / 2);
    transform: translateY(-50%);
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border: 1px solid var(--color-border-strong);
    background: var(--color-glass);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    color: var(--color-text);
    border-radius: var(--radius-pill);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    transition: background var(--motion-fast), opacity var(--motion-fast);
}
.overlay__nav:hover { background: var(--color-surface-hover); }
.overlay__nav--prev { left: var(--space-3); }
.overlay__nav--next { right: var(--space-3); }
.overlay__nav.is-disabled { opacity: 0.32; cursor: default; }

.overlay__indicator {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
}
.overlay__counter {
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    font-variant-numeric: tabular-nums;
    color: var(--color-text-muted);
}
.overlay__dots { display: flex; gap: var(--space-1); }
.overlay__dot {
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
    display: grid;
    place-items: center;
}
.overlay__dot::before {
    content: "";
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--color-border-strong);
    transition: background var(--motion-fast), transform var(--motion-fast);
}
.overlay__dot:hover::before { background: var(--color-text-muted); }
.overlay__dot.is-active::before { background: var(--color-accent); transform: scale(1.3); }

/* Single-screenshot apps: drop the nav chrome entirely. */
.overlay__gallery.is-single .overlay__nav,
.overlay__gallery.is-single .overlay__indicator { display: none; }

/* Content */
.overlay__content { min-width: 0; }
.overlay__desc {
    margin: 0 0 var(--space-5);
    font-size: var(--text-base);
    line-height: var(--leading-normal);
    color: var(--color-text);
}
.overlay__sections {
    display: flex;
    flex-direction: column;
    gap: var(--space-5);
}
.overlay__section h3 {
    margin: 0 0 var(--space-1);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--color-accent-ink);
}
.overlay__section p {
    margin: 0;
    font-size: var(--text-sm);
    line-height: var(--leading-normal);
    color: var(--color-text-muted);
}
/* Per-app legal links (Privacy / Support / Notes) live in the overlay so the
   card foot can stay two-element (keynote-faithful) without losing them. */
.overlay__links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-5);
    align-items: center;
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: 1px solid var(--color-border);
}
.overlay__links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--color-text-muted);
    font-size: var(--text-xs);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    transition: color var(--motion-fast);
}
.overlay__links a:hover { color: var(--color-accent-ink); }
/* App Store badge — Apple's own artwork, used under their marketing guidelines
   (developer.apple.com/app-store/marketing/guidelines, read 2026-08-12):
   minimum onscreen height 40px, clear space at least one quarter of the badge
   height on every side, artwork never recreated, recoloured, angled, animated
   or stretched. Hence a fixed height with width:auto — never width:100%, which
   is what the old text button did and what would distort the badge. */
.overlay__store {
    display: inline-block;
    margin-top: var(--space-5);
    padding: 11px;          /* clear space: 1/4 of the 44px badge height */
    margin-left: -11px;     /* pull the padding out of the text column's flow */
    border-radius: var(--radius-md);
    line-height: 0;
}
.overlay__store:focus-visible {
    outline: 2px solid var(--color-accent-ring);
    outline-offset: 2px;
}
.overlay__store-badge {
    display: block;
    height: 44px;           /* above Apple's 40px floor, and a comfortable tap target */
    width: auto;
}

/* The badge and the QR code sit side by side and share one baseline: they are
   two routes to the same download, not a primary and an afterthought. */
.overlay__get {
    display: flex;
    align-items: center;
    gap: var(--space-5);
    flex-wrap: wrap;
}

/* Hidden by default — on a phone or tablet the badge already leads straight
   into the App Store, and a QR code you would have to scan with the device
   showing it is a small joke at the visitor's expense.
   `pointer: fine` is the honest test: it asks for a mouse or trackpad, which
   is what "this person is not holding the device" actually means. A width
   query alone would show it on a tablet in landscape. */
.overlay__qr { display: none; }

@media (min-width: 860px) and (pointer: fine) {
    .overlay__qr:not([hidden]) {
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: var(--space-2);
        margin-top: var(--space-5);
    }
    .overlay__qr-code {
        display: block;
        width: 96px;
        height: 96px;
        padding: 6px;                       /* the quiet zone scanners need */
        background: #fff;                   /* stays white in dark mode: a QR needs the contrast */
        border-radius: var(--radius-sm);
        color: #000;                        /* the SVG draws its modules in currentColor */
    }
    .overlay__qr-hint {
        font-size: 0.75rem;
        line-height: 1.3;
        max-width: 110px;
        text-align: center;
        color: var(--color-text-muted);
    }
}

@media (max-width: 600px) {
    .overlay { padding: 0; }
    .overlay__dialog {
        width: 100%;
        max-height: 100vh;
        max-height: 100dvh;
        border: 0;
        border-radius: 0;
    }
    .overlay__header {
        padding: var(--space-4) var(--space-5);
        padding-right: var(--space-12);
    }
    .overlay__body { padding: var(--space-5); }
}

@media (prefers-reduced-motion: reduce) {
    .overlay,
    .overlay__dialog,
    .overlay__track { transition: none; }
}

/* ============================================================
   Component responsive overrides
   These must live AFTER the component base styles to win the
   cascade; that's why they sit in components.css rather than
   layout.css alongside the layout-level breakpoints.
   ============================================================ */

/* ------------------------------------------------------------
   Media cards on single column (≤900px) — restack, don't overlap.
   At this breakpoint .app-grid collapses to one column (layout.css)
   and the card is too narrow for the desktop split (copy left /
   device right, sharing one full-bleed background image): the copy
   would land on top of the rendered phone and both turn unreadable.
   So we restack — the copy flows on the card's SOLID DARK surface
   (media cards are an always-dark context in both themes, see
   tokens.css), and the mockup becomes its OWN framed media block
   below the copy: full content width, fixed ratio, cover-cropped
   toward the device (it sits in the right of the source image).
   Desktop (≥901px, two-column grid) is left completely untouched.
   ------------------------------------------------------------ */
@media (max-width: 900px) {
    /* Solid dark panel behind the copy — no image underlay, so the
       forced light ink (below) always clears contrast. */
    .app-card--media {
        padding-right: var(--space-8);   /* drop the reserved device column */
        min-height: 0;
        background: var(--color-surface-media);
    }

    /* Mockup: full-bleed background → framed media block, moved to the
       bottom of the flex column (source order renders .app-card__bg first). */
    .app-card--media .app-card__bg {
        position: static;
        order: 1;                        /* below copy + foot */
        width: 100%;
        height: auto;
        aspect-ratio: 3 / 2;
        margin-top: var(--space-6);
        border-radius: var(--radius-lg);
        border: 1px solid var(--color-border);
    }
    .app-card--media .app-card__bg img {
        height: 100%;
        object-position: 78% center;     /* device (right of frame) stays in view */
    }
    /* The left-dark readability gradient is only for copy-over-image;
       with the framed layout it would just shade the frame — drop it. */
    .app-card--media .app-card__bg::after { display: none; }

    /* Copy no longer needs to be pinned to a tall card bottom (the
       framed image follows it), so relax the auto top margin. */
    .app-card--media .app-card__foot { margin-top: var(--space-4); }
}

/* ------------------------------------------------------------
   Showcase cards on single column (≤900px) — copy stacks above the
   device row. The grid two-column split collapses to one column; the
   device row centres beneath the copy. Devices stay straight and on a
   shared baseline (no rotate/reflection). Desktop is untouched.
   ------------------------------------------------------------ */
@media (max-width: 900px) {
    .app-card--showcase {
        grid-template-columns: 1fr;
        gap: var(--space-8);
        min-height: 0;
    }
    .app-card--showcase .app-card__devices { justify-content: center; }
    /* Glow recentres behind the (now centred) device row. */
    .app-card--showcase .app-card__glow {
        top: auto;
        bottom: 0;
        right: 50%;
        transform: translateX(50%);
        width: 80%;
    }
}

/* ------------------------------------------------------------
   Showcase device row on phones (≤560px) — wrap so the LARGEST device
   leads on its own full-width row and smaller devices sit beneath it
   (iPad/Mac on top, iPhone/Watch below). Guarantees no horizontal
   overflow at any phone width. For a future 3+ device card, revisit
   which device should lead the full-width row.
   ------------------------------------------------------------ */
@media (max-width: 560px) {
    .app-card--showcase .app-card__devices {
        flex-wrap: wrap;
        justify-content: center;
        gap: var(--space-4);
    }
    .device-slot--ipad,
    .device-slot--mac { flex-basis: 100%; }
    /* Compact, overflow-safe heights for the stacked phone view. */
    .device--iphone { height: clamp(176px, 46vw, 210px); }
    .device--ipad   { height: clamp(196px, 52vw, 236px); }
}

@media (max-width: 600px) {
    .app-card { padding: var(--space-6); }
    .app-card--media { padding-right: var(--space-6); }
}

@media (max-width: 380px) {
    .app-card { padding: var(--space-5); }
    .app-card--media { padding-right: var(--space-5); }
    .app-icon { width: 48px; height: 48px; font-size: 18px; border-radius: 13px; }
}

/* ===== utilities.css ===== */
/* ============================================================
   Utilities — a11y helpers, scroll-reveal
   Loaded after components so utility overrides win the cascade.
   ============================================================ */

/* Skip-to-content (a11y) */
.skip-link {
    position: absolute;
    left: var(--space-4);
    top: var(--space-4);
    padding: var(--space-2) var(--space-4);
    background: var(--color-accent);
    color: var(--color-text-on-accent);
    border-radius: var(--radius-md);
    font-weight: 700;
    font-size: var(--text-sm);
    transform: translateY(-200%);
    transition: transform var(--motion-base);
    z-index: 100;
}
.skip-link:focus-visible {
    transform: translateY(0);
    color: var(--color-text-on-accent);
    box-shadow: var(--shadow-md);
}

/* ============================================================
   Scroll-reveal — IntersectionObserver-driven fade+slide.
   Elements opt in via the `.reveal` class. JS adds `.is-visible`
   when the element enters the viewport. Reduced-motion users skip
   the transform entirely and see content immediately.
   ============================================================ */

.reveal {
    opacity: 0;
    transform: translateY(20px);
    transition:
        opacity var(--motion-slow),
        transform var(--motion-slow);
    will-change: opacity, transform;
}
.reveal.is-visible {
    opacity: 1;
    transform: translateY(0);
}
/* Stagger inside the app grid so cards don't pop in as a block. */
.app-grid .reveal:nth-child(2) { transition-delay:  80ms; }
.app-grid .reveal:nth-child(3) { transition-delay: 160ms; }
.app-grid .reveal:nth-child(4) { transition-delay: 240ms; }

@media (prefers-reduced-motion: reduce) {
    .reveal {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* ============================================================
   Back-to-Top button
   Lives on long legal/info sub-pages. Wired up by /back-to-top.js.
   Hidden until the page is scrolled past ~200px.
   ============================================================ */

.back-to-top {
    position: fixed;
    right: var(--space-5);
    bottom: var(--space-5);
    /* Respect iOS home-indicator + notch on mobile Safari. */
    bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px));
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    background: var(--color-glass);
    color: var(--color-text);
    font-size: var(--text-lg);
    line-height: 1;
    cursor: pointer;
    box-shadow: var(--shadow-md);
    opacity: 0;
    visibility: hidden;
    transform: translateY(8px);
    transition:
        opacity var(--motion-base),
        transform var(--motion-base),
        visibility 0s linear var(--motion-base),
        background var(--motion-fast),
        border-color var(--motion-fast),
        color var(--motion-fast);
    z-index: 50;
    /* Avoid Safari double-tap zoom on the icon. */
    touch-action: manipulation;
}
@supports ((backdrop-filter: blur(14px)) or (-webkit-backdrop-filter: blur(14px))) {
    .back-to-top {
        backdrop-filter: blur(14px) saturate(140%);
        -webkit-backdrop-filter: blur(14px) saturate(140%);
    }
}
.back-to-top.is-visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition:
        opacity var(--motion-base),
        transform var(--motion-base),
        visibility 0s,
        background var(--motion-fast),
        border-color var(--motion-fast),
        color var(--motion-fast);
}
.back-to-top:hover {
    color: var(--color-accent-ink);
    border-color: var(--color-accent-ring);
}
.back-to-top:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 3px;
}
.back-to-top svg {
    width: 18px;
    height: 18px;
    display: block;
}

@media (max-width: 380px) {
    .back-to-top {
        right: var(--space-4);
        bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
    }
}

@media (prefers-reduced-motion: reduce) {
    .back-to-top {
        transition: opacity 0s, visibility 0s;
    }
    .back-to-top.is-visible {
        transition: opacity 0s, visibility 0s;
    }
    html {
        scroll-behavior: auto;
    }
}

/* ============================================================
   Footer language switch — quiet inline text toggle (WP-007).
   Lives next to the copyright in the bottom row. No pill, no
   background, no leading label. Active language is communicated
   by font-weight + accent-ink text colour. Tap target is held at
   44×44 px via inline-block + min-width/min-height + padding so
   the visual stays compact but mobile-friendly.
   ============================================================ */
.site-footer__meta {
    display: flex;
    align-items: center;
    gap: var(--space-3) var(--space-5);
    flex-wrap: wrap;
}
.footer-lang {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    /* override the generic `nav { display:flex; gap; margin-bottom }`
       rule from layout.css so the inline footer toggle stays on one
       line with no bottom margin. */
    margin: 0;
}
.footer-lang a {
    display: inline-block;
    min-width: 44px;
    min-height: 44px;
    padding: 13px var(--space-2);
    text-align: center;
    color: var(--color-text-faint);
    font-size: var(--text-xs);
    font-weight: 500;
    letter-spacing: var(--tracking-wide);
    line-height: 1;
    border-radius: var(--radius-sm);
    transition: color var(--motion-fast);
}
.footer-lang a:hover {
    color: var(--color-text);
}
.footer-lang a[aria-current="true"] {
    color: var(--color-accent-ink);
    font-weight: 700;
}
.footer-lang span[aria-hidden="true"] {
    color: var(--color-text-faint);
    font-size: var(--text-xs);
    line-height: 1;
    user-select: none;
}

/* ============================================================
   Table of contents (datenschutz long page)
   ============================================================ */
.toc {
    margin: var(--space-6) 0 var(--space-8);
    padding: var(--space-5) var(--space-6);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface);
}
.toc__title {
    margin: 0 0 var(--space-3);
    font-size: var(--text-sm);
    font-weight: 600;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--color-text-muted);
}
.toc ol {
    margin: 0;
    padding-left: var(--space-6);
    display: grid;
    gap: var(--space-1) var(--space-4);
    grid-template-columns: 1fr;
}
@media (min-width: 720px) {
    .toc ol { grid-template-columns: 1fr 1fr; }
}
.toc a {
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: var(--text-sm);
}
.toc a:hover,
.toc a:focus-visible { color: var(--color-accent-ink); }

/* ===== print.css ===== */
/* ============================================================
   Print — legal pages are the primary print target.
   Plain white page, black ink, no chrome (topbar, language
   switch, back-to-top, aurora) so a printed privacy policy or
   legal notice reads like a document, not a screenshot.
   ============================================================ */

@media print {
    body {
        background: #fff !important;
        color: #000;
    }
    body::before { display: none; }

    .topbar,
    .lang-switch,
    .back-link,
    .back,
    .back-to-top,
    .skip-link,
    .footer-lang,
    .hero-cta {
        display: none !important;
    }

    h1, h2, h3, h4, p, li, strong, .date {
        color: #000 !important;
    }

    a {
        color: #000 !important;
        text-decoration: underline;
    }

    .legal-content > h2 {
        border-top-color: #ccc;
        break-after: avoid;
    }

    .container {
        max-width: none;
        padding: 0;
    }
}
