/* ==========================================================================
   site.css: the one stylesheet of the site, served as-is (no Sass).

   Design: liquid glass. A soft, slowly drifting colour wallpaper lies behind
   every page (tinted with the app's accent on app pages), and the content
   floats on frosted glass panels with a light rim. Clean type, generous
   space, large radii.

   Sections:
     1. Tokens              6. Home: hero, app tiles, contact
     2. Base, wallpaper     7. App hero
     3. Glass, buttons      8. Section header, download card, store badges
     4. Top bars            9. Prose pages
     5. Chips              10. Footers
                           11. Features  12. Screenshots  13. FAQ
   ========================================================================== */

/* ==========================================
   1. Tokens
   ========================================== */

/* Keep --tint-strength, --accent-ink-mix, --accent-ink-base and --bg in sync with the
   constants at the top of engine/scripts/check-site.mjs, which checks the accent contrast. */
:root {
    color-scheme: light dark;

    --bg: #f8f7fb;
    --surface: #efedf5;
    --text: #15141c;
    --text-muted: #5f5c6e;
    --border: #e4e1ec;

    /* Glass: a translucent fill, a light rim and a soft shadow. */
    --glass-fill: rgb(255 255 255 / 0.42);
    --glass-fill-strong: rgb(255 255 255 / 0.72);
    /* Hovered glass: a little more frosted than --glass-fill. */
    --glass-fill-hover: color-mix(in srgb, var(--glass-fill-strong) 35%, var(--glass-fill));
    --glass-rim: rgb(255 255 255 / 0.95);
    --glass-rim-soft: rgb(255 255 255 / 0.25);
    --glass-edge: rgb(20 18 40 / 0.06);
    --glass-shadow: 0 1px 2px rgb(20 18 40 / 0.04), 0 10px 36px rgb(40 30 90 / 0.1);
    --glass-shadow-lift: 0 2px 4px rgb(20 18 40 / 0.05), 0 20px 50px rgb(40 30 90 / 0.16);
    --glass-blur: blur(22px) saturate(180%);

    /* The frame around screenshots, dark like an iPhone's bezel. */
    --shot-frame: #1f1e26;

    /* The wallpaper colours. On app pages they come from the accent. */
    --wall-1: #ffd66b;
    --wall-2: #b9a4ff;
    --wall-3: #8fd3ff;
    --wall-4: #ffa8c5;
    --wall-strength: 80%;

    /* Accent: set per app with style="--accent: …" on an .accent-scope element. */
    --accent: #6e5bff;
    --on-accent: #000;
    --tint-strength: 7%;
    --accent-ink-mix: 45%;
    --accent-ink-base: #000;

    --radius: 1.75rem;
    --radius-lg: 2.25rem;
    --radius-sm: 1rem;
    /* Approximates Apple's squircle on a square icon */
    --icon-radius: 22.5%;
    --content-width: 68rem;
    --gutter: clamp(1.25rem, 5vw, 2.5rem);
    --topbar-height: 3.5rem;
    /* Below the status bar or the Dynamic Island when the page runs edge to edge (viewport-fit=cover). */
    --topbar-offset: calc(0.75rem + env(safe-area-inset-top, 0px));
    --section-space: clamp(4.5rem, 10vw, 7rem);

    --font: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Inter', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --font-display: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Inter', 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
    --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
}

@media (prefers-color-scheme: dark) {
    :root {
        --bg: #13121a;
        --surface: #1c1b26;
        --text: #f4f3f8;
        --text-muted: #a9a6b8;
        --border: #2f2d3c;

        --glass-fill: rgb(255 255 255 / 0.06);
        --glass-fill-strong: rgb(40 38 52 / 0.72);
        --glass-rim: rgb(255 255 255 / 0.28);
        --glass-rim-soft: rgb(255 255 255 / 0.04);
        --glass-edge: rgb(255 255 255 / 0.06);
        --glass-shadow: 0 1px 2px rgb(0 0 0 / 0.3), 0 10px 36px rgb(0 0 0 / 0.35);
        --glass-shadow-lift: 0 2px 4px rgb(0 0 0 / 0.35), 0 20px 50px rgb(0 0 0 / 0.5);

        --shot-frame: #3a3846;

        --wall-strength: 42%;

        --tint-strength: 13%;
        --accent-ink-mix: 80%;
        --accent-ink-base: #fff;
    }
}

/* --accent-ink must be declared on the element that sets --accent: on :root it would
   resolve var(--accent) to the default before an app overrides it. */
:root,
.accent-scope {
    --accent-ink: color-mix(in srgb, var(--accent) var(--accent-ink-mix), var(--accent-ink-base));
    --accent-tint: color-mix(in srgb, var(--accent) var(--tint-strength), var(--bg));
    --accent-soft: color-mix(in srgb, var(--accent) 22%, transparent);
}

/* On an app page the wallpaper takes the app's colour. */
.app-page {
    --wall-1: var(--accent);
    --wall-2: color-mix(in srgb, var(--accent) 55%, #ff7ab8);
    --wall-3: color-mix(in srgb, var(--accent) 35%, #8fd3ff);
    --wall-4: color-mix(in srgb, var(--accent) 70%, #fff);
}

/* ==========================================
   2. Base and wallpaper
   ========================================== */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    background: var(--bg);
    scroll-behavior: smooth;
    /* The page runs edge to edge (viewport-fit=cover), so the wallpaper also fills the strips
       beside the notch of an iPhone held sideways; the content stays clear of them. */
    padding-inline: env(safe-area-inset-left, 0px) env(safe-area-inset-right, 0px);
    /* Anchors stop below the sticky top bar. */
    scroll-padding-top: calc(var(--topbar-height) + var(--topbar-offset) + 1.5rem);
}

body {
    position: relative;
    margin: 0;
    min-height: 100vh;
    /* On iOS 100vh is the height with the toolbars hidden, so short pages would scroll. */
    min-height: 100svh;
    display: flex;
    flex-direction: column;
    color: var(--text);
    font-family: var(--font);
    font-size: 1.0625rem;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    overflow-x: clip;
}

/* The wallpaper: four large, soft colour fields that drift very slowly. It is fixed, so the
   glass panels show different colours as the page scrolls under them. */
body::before {
    content: '';
    position: fixed;
    inset: -20vmax;
    z-index: -1;
    background:
        radial-gradient(38vmax 30vmax at 18% 22%, color-mix(in srgb, var(--wall-1) var(--wall-strength), transparent), transparent 70%),
        radial-gradient(34vmax 30vmax at 82% 18%, color-mix(in srgb, var(--wall-2) var(--wall-strength), transparent), transparent 70%),
        radial-gradient(40vmax 32vmax at 75% 80%, color-mix(in srgb, var(--wall-3) var(--wall-strength), transparent), transparent 70%),
        radial-gradient(30vmax 26vmax at 22% 85%, color-mix(in srgb, var(--wall-4) var(--wall-strength), transparent), transparent 70%);
    filter: blur(20px);
    animation: drift 40s ease-in-out infinite alternate;
    pointer-events: none;
}

@keyframes drift {
    from { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); }
    to { transform: translate3d(-4vmax, 3vmax, 0) rotate(8deg) scale(1.08); }
}

main {
    flex: 1 0 auto;
    display: block;
}

h1,
h2,
h3,
h4 {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 700;
    line-height: 1.08;
    letter-spacing: -0.025em;
    text-wrap: balance;
}

p {
    margin: 0 0 1rem;
    text-wrap: pretty;
}

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

img {
    height: auto;
}

a {
    color: inherit;
}

button {
    font: inherit;
    color: inherit;
    cursor: pointer;
}

.icon {
    flex-shrink: 0;
}

:focus-visible {
    outline: 2px solid var(--accent-ink);
    outline-offset: 3px;
    border-radius: 6px;
}

::selection {
    background: color-mix(in srgb, var(--accent) 35%, transparent);
}

.container {
    width: 100%;
    max-width: var(--content-width);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.skip-link {
    position: absolute;
    top: 0.75rem;
    left: 0.75rem;
    z-index: 2000;
    padding: 0.6rem 1rem;
    border-radius: 999px;
    background: var(--text);
    color: var(--bg);
    font-weight: 600;
    text-decoration: none;
    transform: translateY(-200%);
    transition: transform 0.15s ease;
}

.skip-link:focus-visible {
    transform: none;
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    body::before {
        animation: none;
    }

    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}

/* ==========================================
   3. Glass and buttons
   ========================================== */

/* A frosted panel. The rim is a 1px gradient border drawn by ::before: bright at the top left
   where the light hits, nearly gone in the middle, a little brighter again at the bottom right. */
.glass {
    position: relative;
    background: var(--glass-fill);
    -webkit-backdrop-filter: var(--glass-blur);
    backdrop-filter: var(--glass-blur);
    box-shadow: var(--glass-shadow), inset 0 0 0 1px var(--glass-edge);
}

.glass::before {
    content: '';
    position: absolute;
    inset: 0;
    padding: 1px;
    border-radius: inherit;
    background: linear-gradient(150deg, var(--glass-rim), var(--glass-rim-soft) 35%, transparent 55%, var(--glass-rim-soft) 80%, var(--glass-rim));
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
    pointer-events: none;
}

.section-title {
    margin-bottom: 1.5rem;
    font-size: clamp(1.75rem, 4vw, 2.25rem);
}

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    min-height: 48px;
    padding: 0.6rem 1.4rem;
    font-size: 1rem;
    font-weight: 600;
    line-height: 1.3;
    color: var(--bg);
    text-align: center;
    text-decoration: none;
    white-space: nowrap;
    background: var(--text);
    border: 0;
    border-radius: 999px;
    box-shadow: 0 6px 20px rgb(20 18 40 / 0.18);
    transition: transform 0.25s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}

/* Hovered buttons, tiles and links move up 2px and get a deeper shadow; glass gets a little more
   frosted. */
.button:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 26px rgb(20 18 40 / 0.26);
}

.button:active {
    transform: scale(0.97);
}

.button-glass {
    color: var(--text);
    background: var(--glass-fill);
    box-shadow: var(--glass-shadow), inset 0 0 0 1px var(--glass-edge);
}

.button-glass:hover {
    background: var(--glass-fill-hover);
    box-shadow: var(--glass-shadow-lift), inset 0 0 0 1px var(--glass-edge);
}

.button-small {
    min-height: 36px;
    padding: 0.35rem 1rem;
    font-size: 0.875rem;
}

/* The accent button in the app header. */
.app-header .button {
    color: var(--on-accent);
    background: var(--accent);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 25%, transparent);
}

.app-header .button:hover {
    box-shadow: 0 4px 12px color-mix(in srgb, var(--accent) 30%, transparent);
}

/* ==========================================
   4. Top bars: slim site header and sticky app header
   ========================================== */

/* A floating glass capsule. */
.topbar {
    position: sticky;
    top: var(--topbar-offset);
    z-index: 1000;
    height: var(--topbar-height);
    margin: var(--topbar-offset) var(--gutter) 0;
}

.topbar-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0 1.5rem;
    max-width: calc(var(--content-width) - 2 * var(--gutter));
    min-height: var(--topbar-height);
    padding-inline: 1.25rem 0.5rem;
    background: var(--glass-fill-strong);
    border-radius: 999px;
}

.app-header {
    margin-bottom: calc(-1 * (var(--topbar-height) + var(--topbar-offset)));
}

/* Back buttons on the far left: "Apps" in the app header, the owner's name in the site header
   of the legal pages. Both lead to the home page. */
.home-link,
.back-link {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    min-height: 44px;
    color: var(--text-muted);
    font-size: 0.9375rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.2s ease;
}

.home-link {
    margin-right: -0.625rem;
}

.home-link::after {
    content: '';
    width: 1px;
    height: 22px;
    margin-left: 0.575rem;
    background: color-mix(in srgb, var(--text-muted) 30%, transparent);
}

.home-link:hover,
.back-link:hover {
    color: var(--text);
}

.home-link .icon,
.back-link .icon {
    transition: transform 0.2s ease;
}

.home-link:hover .icon,
.back-link:hover .icon {
    transform: translateX(-2px);
}

.brand-name {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    margin-right: auto;
    color: var(--text);
    white-space: nowrap;
    font-size: 1.0625rem;
    font-weight: 650;
    letter-spacing: -0.01em;
}

.topbar-links,
.nav-list {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.nav-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 0.6rem;
    color: var(--text-muted);
    font-size: 0.9375rem;
    font-weight: 500;
    text-decoration: none;
    white-space: nowrap;
    transition: color 0.2s ease, background-color 0.2s ease;
}

.nav-link:hover {
    color: var(--text);
}

@media (min-width: 768px) {
    .nav-link {
        min-height: 36px;
        border-radius: 999px;
    }

    .nav-link:hover {
        background: color-mix(in srgb, var(--text) 7%, transparent);
    }
}

/* The app header's section links. Below 768px they are hidden and only the "Get the app"
   button shows; on a phone the sections are a short scroll away. */
.nav-section {
    display: none;
}

.app-header .button {
    margin-left: 0.5rem;
}

@media (min-width: 768px) {
    .nav-section {
        display: list-item;
    }

    .app-header .nav-link {
        padding-inline: 0.85rem;
    }
}

/* ==========================================
   5. Chips
   ========================================== */

/* A small glass label above a title. */
.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0;
    padding: 0.4rem 1rem;
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text);
    border-radius: 999px;
}

/* ==========================================
   6. Home: hero, app tiles, contact
   ========================================== */

.home-hero {
    padding-block: clamp(3rem, 8vw, 5.5rem) clamp(2.5rem, 6vw, 4rem);
}

/* On a phone the portrait sits centred above the text; from 640px it is on the left of it. */
.home-hero-inner {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.25rem;
    text-align: center;
}

.home-hero-text {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

.portrait {
    flex-shrink: 0;
    width: 120px;
    height: 120px;
    object-fit: cover;
    border-radius: 50%;
    box-shadow: 0 0 0 4px var(--glass-fill-strong), var(--glass-shadow-lift);
}

@media (min-width: 40rem) {
    .home-hero-inner {
        flex-direction: row;
        justify-content: center;
        gap: clamp(2rem, 4vw, 3rem);
        text-align: left;
    }

    .home-hero-text {
        align-items: flex-start;
    }

    .portrait {
        width: clamp(144px, 18vw, 180px);
        height: clamp(144px, 18vw, 180px);
    }
}

.home-hero h1 {
    font-size: clamp(2.5rem, 7vw, 4rem);
    font-weight: 750;
    letter-spacing: -0.04em;
}

/* A wave next to the name. */
.home-hero h1::after {
    content: '👋';
    display: inline-block;
    margin-left: 0.25em;
    letter-spacing: 0;
    transform-origin: 70% 80%;
    animation: wave 2.4s ease-in-out 0.6s 2;
}

@keyframes wave {
    0%, 60%, 100% { transform: rotate(0); }
    10%, 30% { transform: rotate(16deg); }
    20%, 40% { transform: rotate(-8deg); }
}

@media (prefers-reduced-motion: reduce) {
    .home-hero h1::after {
        animation: none;
    }
}

.home-intro {
    max-width: 34rem;
    margin: 0;
    font-size: clamp(1.125rem, 2.4vw, 1.3125rem);
    color: var(--text-muted);
}


/* App tiles: a two-column grid of glass cards. */

.app-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 48rem) {
    .app-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Text on the left, the hero screenshot on the right. The preview box is 82% as tall as the
   screenshot and the tile cuts off the rest, so at least that much of it is always visible. */
.app-tile {
    --preview-width: 8.5rem;
    display: grid;
    grid-template-columns: minmax(0, 1fr) var(--preview-width);
    gap: 1.5rem;
    overflow: hidden;
    padding: 1.75rem 1.75rem 0;
    border-radius: var(--radius-lg);
    transition: transform 0.25s ease, background-color 0.25s ease, box-shadow 0.25s ease;
}

/* After a short delay, so passing over a tile does not flash it. */
.app-tile:hover,
.app-tile:focus-within {
    transform: translateY(-2px);
    background: var(--glass-fill-hover);
    box-shadow: var(--glass-shadow-lift), inset 0 0 0 1px var(--glass-edge);
    transition-duration: 0.35s;
    transition-delay: 40ms;
}

.app-tile-body {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding-bottom: 1.5rem;
}

/* The icon, and the label of a past app at the other end of the row, next to the screenshot and
   level with the top of both. */
.app-tile-top {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    align-self: stretch;
    gap: 0.5rem 0.75rem;
    margin-bottom: 1rem;
}

.app-tile-icon {
    width: 56px;
    height: 56px;
    border-radius: var(--icon-radius);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 14%, transparent), 0 0 0 0.5px rgb(0 0 0 / 0.08);
}

.app-tile h3 {
    font-size: 1.5rem;
}

.app-tile-tagline {
    margin: 0.3rem 0 0;
    font-size: 0.9375rem;
    font-weight: 500;
    line-height: 1.4;
    color: var(--accent-ink);
}

.app-tile-description {
    margin: 0.75rem 0 0;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--text-muted);
}

.app-tile-link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 44px;
    margin-top: auto;
    padding-top: 0.5rem;
    font-weight: 600;
    color: var(--accent-ink);
    text-decoration: none;
}

/* The link covers the whole tile. */
.app-tile-link::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
}

.app-tile-link .icon {
    transition: transform 0.2s ease;
}

.app-tile:hover .app-tile-link .icon {
    transform: translateX(3px);
}

.app-tile-preview {
    position: relative;
    aspect-ratio: 600 / 1068;
}

/* Framed like the screenshots on the app pages. */
.app-tile-preview img {
    width: 100%;
    border-radius: 1.5rem;
    outline: 5px solid var(--shot-frame);
    /* A small, soft glow in the app's colour. */
    box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 25%, transparent);
}

/* Between phone and two columns a tile spans the full width and has room to spare: the screenshot is
   shown whole, with the same room below it as at the sides, and the link sits level with its bottom. */
@media (min-width: 40rem) and (max-width: 47.99rem) {
    .app-tile {
        padding-bottom: 1.75rem;
    }

    .app-tile-body {
        padding-bottom: 0;
    }

    .app-tile-preview {
        aspect-ratio: auto;
    }
}

/* Only shown on a phone, next to the hero screenshot. */
.app-tile-preview-extra {
    display: none;
}

/* On a phone two smaller screenshots sit side by side under the text, shown whole, with some
   room below them before the tile ends. */
@media (max-width: 39.99rem) {
    .app-tile {
        grid-template-columns: 1fr;
        gap: 0;
        padding-bottom: 1.75rem;
    }

    .app-tile-preview {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 1.25rem;
        aspect-ratio: auto;
        justify-self: center;
        width: 100%;
        max-width: 22rem;
        /* Inside the 5px frame of the screenshots. */
        padding-inline: 5px;
    }

    .app-tile-preview img {
        border-radius: 1.25rem;
    }

    .app-tile-preview-extra {
        display: block;
    }
}

/* Past projects: apps that are no longer on the App Store, below the current ones. */

.past-apps {
    padding-top: var(--section-space);
}

.section-lead {
    margin: -0.75rem 0 1.5rem;
    font-size: 1.0625rem;
    color: var(--text-muted);
}

.app-tile-status {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin: 0;
    padding: 0.2rem 0.65rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--text-muted);
    background: var(--glass-fill-strong);
    border-radius: 999px;
    box-shadow: inset 0 0 0 1px var(--border);
}

/* Contact */

.contact {
    padding-top: var(--section-space);
}

.contact-card {
    padding: clamp(2rem, 6vw, 3.5rem);
    text-align: center;
    border-radius: var(--radius-lg);
}

.contact-card .section-title {
    margin-bottom: 0.75rem;
}

.contact-lead {
    max-width: 30rem;
    margin: 0 auto 2rem;
    color: var(--text-muted);
}

.contact-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.contact-link {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 1.25rem 0.5rem 0.5rem;
    text-align: left;
    text-decoration: none;
    border-radius: 999px;
    transition: transform 0.25s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}

.contact-link:hover,
.contact-link:focus-visible {
    transform: translateY(-2px);
    background: var(--glass-fill-hover);
    box-shadow: var(--glass-shadow-lift), inset 0 0 0 1px var(--glass-edge);
}

.contact-glyph {
    display: grid;
    place-items: center;
    width: 40px;
    height: 40px;
    flex-shrink: 0;
    border-radius: 50%;
    color: var(--bg);
    background: var(--text);
}

.contact-labels {
    display: flex;
    flex-direction: column;
    min-width: 0;
    line-height: 1.3;
}

.contact-label {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.contact-handle {
    font-size: 0.9375rem;
    font-weight: 600;
    overflow-wrap: anywhere;
}

@media (prefers-reduced-motion: reduce) {
    .app-tile:hover,
    .app-tile:focus-within {
        transform: none;
    }
}

/* ==========================================
   7. App hero
   ========================================== */

.app-hero {
    padding: calc(var(--topbar-height) + var(--topbar-offset) + clamp(2.75rem, 6.5vw, 4rem)) 0 0;
    text-align: center;
    overflow-x: clip;
}

/* On a phone the text sits centred above the screenshots; from 992px the text is on the
   left and the screenshots are on the right. */
.hero-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: center;
}

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

/* The app's icon and name, like the header of its App Store page. */
.hero-app {
    display: flex;
    align-items: center;
    gap: 0.875rem;
    margin-bottom: 1.5rem;
    text-align: left;
}

.hero-app-icon {
    width: 64px;
    height: 64px;
    flex-shrink: 0;
    border-radius: var(--icon-radius);
    box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 14%, transparent), 0 0 0 0.5px rgb(0 0 0 / 0.08);
}

.hero-app-name {
    margin: 0;
    font-size: 1.1875rem;
    font-weight: 650;
    line-height: 1.25;
    letter-spacing: -0.015em;
}

.hero-app-tagline {
    margin: 0.1rem 0 0;
    font-size: 0.9375rem;
    line-height: 1.35;
    color: var(--text-muted);
}

.hero-title {
    margin-bottom: 1rem;
    font-size: clamp(2.5rem, 6vw, 3.5rem);
    font-weight: 750;
    letter-spacing: -0.045em;
}

.hero-subtitle {
    max-width: 38rem;
    margin: 0 auto 1.75rem;
    font-size: clamp(1.0625rem, 1.8vw, 1.1875rem);
    color: var(--text-muted);
}

/* Two classes, so that the margin: 0 of .store-badges further down does not win. */
.store-badges.hero-cta {
    margin-bottom: 1.75rem;
}

/* In place of the App Store badge when the app is not, or not yet, on the App Store. */
.store-note {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 1.75rem;
    padding: 0.65rem 1.15rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text);
    border-radius: 999px;
}

.store-note .icon {
    color: var(--accent-ink);
}

.hero-trust {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 1.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--text-muted);
}

.hero-trust li {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.hero-trust .icon {
    color: var(--accent-ink);
}

/* Three screenshots in a fan: the hero image in front, two others tilted behind it. On a
   phone the bottom fades out, so the phones seem to rise out of the page. */
.hero-visual {
    position: relative;
    display: flex;
    justify-content: center;
    height: clamp(24rem, 52vw, 30rem);
    margin-top: 2rem;
    -webkit-mask-image: linear-gradient(#000 70%, transparent);
    mask-image: linear-gradient(#000 70%, transparent);
}

.hero-image,
.hero-side {
    position: absolute;
    top: 0;
    width: 240px;
    border-radius: 2rem;
    outline: 6px solid var(--shot-frame);
    box-shadow: 0 30px 60px color-mix(in srgb, var(--accent) 25%, rgb(0 0 0 / 0.25));
}

.hero-image {
    z-index: 1;
}

.hero-side {
    display: none;
}

/* On a phone the hero shows no screenshot: the carousel follows right below. The icon then
   sits centred above the app's name. */
@media (max-width: 39.99rem) {
    .hero-visual {
        display: none;
    }

    .hero-app {
        flex-direction: column;
        text-align: center;
    }

    /* Narrower than the text below, so it reads as part of the app's name. */
    .hero-app-tagline {
        padding-inline: 2rem;
        text-wrap: balance;
    }
}

@media (min-width: 40rem) {
    .hero-side {
        display: block;
    }

    .hero-side-1 {
        transform: translate(-62%, 3rem) rotate(-8deg) scale(0.9);
    }

    .hero-side-2 {
        transform: translate(62%, 3rem) rotate(8deg) scale(0.9);
    }
}

@media (min-width: 992px) {
    .app-hero {
        padding-top: calc(var(--topbar-height) + var(--topbar-offset) + 6rem);
        text-align: left;
    }

    .hero-grid {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 2rem;
    }

    .hero-text {
        align-items: flex-start;
    }

    .hero-subtitle {
        margin-left: 0;
    }

    .hero-text .store-badges,
    .hero-trust {
        justify-content: flex-start;
    }

    /* The whole fan is visible, so no fade. The screenshots shrink on narrower screens. The
       fan sits 2rem down in a box 4rem taller than the hero image, so the hero image is
       centred next to the text and the tilted side screenshots, 3rem lower, still fit. */
    .hero-visual {
        --shot-width: clamp(190px, 16vw, 230px);
        height: calc(var(--shot-width) * 1303 / 600 + 4rem);
        margin-top: 0;
        -webkit-mask-image: none;
        mask-image: none;
    }

    .hero-image,
    .hero-side {
        top: 2rem;
        width: var(--shot-width);
        border-radius: 2.125rem;
    }

    /* The hero image sits a little lower than the fan's top, so it reads as centred. */
    .hero-image {
        top: 2.75rem;
    }

    .hero-side-1 {
        transform: translate(-48%, 3rem) rotate(-8deg) scale(0.88);
    }

    .hero-side-2 {
        transform: translate(48%, 3rem) rotate(8deg) scale(0.88);
    }
}

/* ==========================================
   8. Section header, download card, store badges
   ========================================== */

.section-header {
    max-width: 40rem;
    margin: 0 auto 3rem;
    text-align: center;
}

.section-header h2,
.faq-intro h2,
.download-card h2 {
    margin-bottom: 0.75rem;
    font-size: clamp(2rem, 5vw, 3rem);
    letter-spacing: -0.035em;
}

.section-description {
    margin: 0;
    font-size: 1.125rem;
    color: var(--text-muted);
}

/* The footer's top margin is the space below. */
.download-section {
    padding-top: var(--section-space);
}

.download-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    overflow: hidden;
    padding: clamp(2.5rem, 7vw, 4.5rem) clamp(1.5rem, 5vw, 3rem);
    text-align: center;
    border-radius: var(--radius-lg);
    background:
        radial-gradient(70% 80% at 50% 0%, var(--accent-soft), transparent 70%),
        var(--glass-fill);
}

.download-icon {
    width: 96px;
    height: 96px;
    margin-bottom: 1.5rem;
    border-radius: var(--icon-radius);
    box-shadow: 0 3px 12px color-mix(in srgb, var(--accent) 16%, transparent), 0 0 0 0.5px rgb(0 0 0 / 0.08);
}

.download-text {
    max-width: 36rem;
    margin: 0 auto 2rem;
    font-size: 1.0625rem;
    color: var(--text-muted);
}

.store-badges {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    justify-content: center;
    margin: 0;
}

.store-badge-link {
    display: inline-flex;
    border-radius: 0.6rem;
    transition: transform 0.25s ease, filter 0.2s ease;
}

.store-badge {
    width: auto;
    height: 50px;
}

.store-badge-link:hover {
    transform: translateY(-2px);
    filter: drop-shadow(0 6px 14px rgb(20 18 40 / 0.3));
}

@media (max-width: 768px) {
    .store-badge {
        height: 45px;
    }
}

/* ==========================================
   9. Prose pages: privacy policy, Impressum, 404
   ========================================== */

/* The text sits on one large glass sheet. */
.prose {
    max-width: 48rem;
    margin-top: clamp(2rem, 6vw, 3.5rem);
}

.prose-sheet {
    --sheet-padding: clamp(1.5rem, 6vw, 3.5rem);
    padding: var(--sheet-padding);
    border-radius: var(--radius-lg);
    background: var(--glass-fill-strong);
}

.prose h1 {
    margin-bottom: 1.5rem;
    font-size: clamp(2.25rem, 6vw, 3rem);
    letter-spacing: -0.035em;
}

.prose h2 {
    margin: 2.5rem 0 0.5rem;
    font-size: 1.25rem;
    letter-spacing: -0.015em;
}

.prose h3 {
    margin: 1.75rem 0 0.4rem;
    font-size: 1.0625rem;
}

.prose p,
.prose ul,
.prose ol {
    margin-block: 0.85rem;
    color: var(--text-muted);
}

.prose ul,
.prose ol {
    padding-left: 1.2rem;
}

.prose li {
    margin-block: 0.3rem;
}

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

.prose address {
    margin-block: 0.85rem;
    font-style: normal;
    color: var(--text-muted);
}

.prose a {
    color: var(--text);
    text-decoration-color: color-mix(in srgb, var(--text-muted) 60%, transparent);
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    overflow-wrap: anywhere;
    transition: text-decoration-color 0.15s ease;
}

.prose a:hover {
    text-decoration-color: currentColor;
}

.prose .updated {
    margin-top: -0.75rem;
    font-size: 0.9rem;
}

/* Tables scroll sideways on a phone instead of widening the page. */
.prose table {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    margin-block: 1.25rem;
    border-collapse: separate;
    border-spacing: 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 0.9375rem;
    -webkit-overflow-scrolling: touch;
}

.prose th,
.prose td {
    padding: 0.6rem 0.85rem;
    white-space: nowrap;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--border);
}

.prose th {
    background: var(--surface);
    color: var(--text);
    font-weight: 600;
}

.prose td {
    color: var(--text-muted);
}

/* On a phone the table runs to the sheet's edges, like the screenshot carousel, so it reads as
   scrollable instead of cut off; its first and last columns still line up with the text. */
@media (max-width: 40rem) {
    .prose-sheet table {
        max-width: none;
        margin-inline: calc(-1 * var(--sheet-padding));
        border-inline: 0;
        border-radius: 0;
    }

    .prose-sheet th:first-child,
    .prose-sheet td:first-child {
        padding-left: var(--sheet-padding);
    }

    .prose-sheet th:last-child,
    .prose-sheet td:last-child {
        padding-right: var(--sheet-padding);
    }
}

.prose tbody tr:last-child td {
    border-bottom: 0;
}

.prose tbody td:first-child {
    color: var(--text);
    font-weight: 600;
}

.not-found {
    padding-block: clamp(1rem, 6vw, 3rem);
    text-align: center;
}

.not-found-code {
    margin: 0 0 0.5rem;
    font-family: var(--font-display);
    font-size: clamp(5rem, 20vw, 8rem);
    font-weight: 750;
    line-height: 1;
    letter-spacing: -0.05em;
    color: color-mix(in srgb, var(--text) 18%, transparent);
}

/* ==========================================
   10. Footers
   ========================================== */

.site-footer {
    margin-top: var(--section-space);
    padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
    font-size: 0.875rem;
    color: var(--text-muted);
}

/* One line, also on a phone. */
.site-footer-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0 1rem;
    padding-top: 1.5rem;
    /* A hairline over the content width only, not over the container's padding. */
    background: linear-gradient(color-mix(in srgb, var(--text-muted) 20%, transparent) 0 0) top / calc(100% - 2 * var(--gutter)) 1px no-repeat;
}

.footer-copy {
    margin: 0;
    white-space: nowrap;
}

.footer-links {
    display: flex;
    gap: 1rem;
}

@media (max-width: 26rem) {
    .site-footer {
        font-size: 0.75rem;
    }

    .footer-links {
        gap: 0.75rem;
    }
}

.footer-links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: inherit;
    text-decoration: none;
}

.footer-links a:hover,
.footer-links a:focus-visible {
    color: var(--text);
}

/* ==========================================
   11. Features: a grid of glass cards
   ========================================== */

.features-section {
    padding-top: var(--section-space);
}

.features-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

@media (min-width: 40rem) {
    .features-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (min-width: 60rem) {
    .features-grid {
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 1.25rem;
    }
}

.feature-card {
    padding: 1.75rem;
    border-radius: var(--radius);
}

.feature-icon {
    display: grid;
    place-items: center;
    width: 3rem;
    height: 3rem;
    margin-bottom: 1.25rem;
    color: var(--accent-ink);
    background: var(--accent-soft);
    border-radius: 0.95rem;
}

.feature-title {
    margin-bottom: 0.5rem;
    font-size: 1.1875rem;
    font-weight: 650;
    letter-spacing: -0.015em;
}

.feature-description {
    max-width: 34rem;
    margin: 0;
    font-size: 1rem;
    color: var(--text-muted);
}

/* ==========================================
   12. Screenshots
   ========================================== */

.screenshots-section {
    padding-top: var(--section-space);
}

/* On a phone the carousel follows the hero text directly: its header is only read out by
   screen readers (like .sr-only), and the gap above it is smaller. */
@media (max-width: 39.99rem) {
    .screenshots-section {
        padding-top: 3rem;
    }

    .screenshots-section .section-header {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }
}

.screenshots-container {
    --shot-width: 260px;
    position: relative;
}

/* iPhone or iPad, for apps with iPad screenshots. Radio buttons in a segmented control: the
   unchecked device's row is hidden with :has(), so it works without JS. */
.device-picker {
    display: flex;
    width: fit-content;
    gap: 0.25rem;
    margin: 0 auto 1.5rem;
    padding: 0.25rem;
    border: 0;
    border-radius: 999px;
}

.device-picker label {
    padding: 0.45rem 1.25rem;
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--text-muted);
    border-radius: 999px;
    cursor: pointer;
    transition: background-color 0.2s, color 0.2s;
}

.device-picker input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
}

/* Neutral like an iOS segmented control, so the text reads well with any accent colour. */
.device-picker label:has(input:checked) {
    color: var(--text);
    background: color-mix(in srgb, var(--text) 12%, transparent);
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 8%, transparent);
}

.device-picker label:has(input:focus-visible) {
    outline: 2px solid var(--accent-ink);
    outline-offset: 2px;
}

.screenshots-scroll[data-device="ipad"],
.screenshots-section:has(.device-picker input[value="ipad"]:checked) .screenshots-scroll[data-device="iphone"] {
    display: none;
}

.screenshots-section:has(.device-picker input[value="ipad"]:checked) .screenshots-scroll[data-device="ipad"] {
    display: flex;
}

/* As tall as the iPhone screenshots, so the arrows stay centred; narrower than the screen on a phone.
   --shot-ratio (width / height of the iPad screenshots) is set on the list, portrait or landscape. */
.screenshots-scroll[data-device="ipad"] :is(.screenshot-card, .screenshot-image) {
    width: min(var(--shot-width) * 1303 / 600 * var(--shot-ratio), 100vw - 2 * var(--gutter) - 2rem);
}

.screenshots-scroll {
    display: flex;
    gap: 1.5rem;
    margin: 0;
    /* The vertical padding keeps the frames and shadows from being cut off. */
    padding: 0.75rem 1.5rem 2rem;
    list-style: none;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline: 1.5rem;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
}

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

.screenshot-card {
    flex: 0 0 auto;
    width: var(--shot-width);
    scroll-snap-align: start;
}

.screenshot-card figure {
    margin: 0;
}

.screenshot-image {
    width: var(--shot-width);
    border-radius: 1.75rem;
    outline: 5px solid var(--shot-frame);
    box-shadow: var(--glass-shadow);
}

/* Framed App Store screenshots bring their own device frame and background. */
.is-framed .screenshot-image {
    border-radius: 1rem;
    outline: 0;
}

.screenshot-card figcaption {
    margin-top: 0.9rem;
    padding-inline: 0.5rem;
    font-size: 0.875rem;
    line-height: 1.45;
    text-align: center;
    color: var(--text-muted);
}

.carousel-arrow {
    position: absolute;
    /* Centred on the images, not on images plus captions. */
    top: calc(0.5rem + var(--shot-width) * 1303 / 600 / 2);
    z-index: 2;
    display: grid;
    place-items: center;
    width: 48px;
    height: 48px;
    padding: 0;
    color: var(--text);
    background: var(--glass-fill-strong);
    border: 0;
    border-radius: 50%;
    transform: translateY(-50%);
    transition: transform 0.3s var(--ease-spring);
}

.carousel-arrow:hover {
    transform: translateY(-50%) scale(1.08);
}

.carousel-prev {
    left: -0.5rem;
}

.carousel-next {
    right: -0.5rem;
}

/* On a phone the carousel is scrolled by touch. Without JS the arrows do nothing. */
@media (max-width: 767px) {
    .screenshots-container {
        --shot-width: 220px;
        margin-inline: calc(var(--gutter) * -1);
    }

    .screenshots-scroll {
        padding-inline: var(--gutter);
        scroll-padding-inline: var(--gutter);
    }

    .carousel-arrow {
        display: none;
    }
}

/* ==========================================
   13. FAQ
   ========================================== */

.faq-section {
    padding-top: var(--section-space);
}

/* The heading and a mail button on the left, the questions on the right. */
.faq-layout {
    display: grid;
    gap: 2rem;
}

.faq-intro .section-description {
    margin-bottom: 1.5rem;
}

@media (min-width: 56rem) {
    .faq-layout {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1.7fr);
        gap: 4rem;
        align-items: start;
    }

    .faq-intro {
        position: sticky;
        top: calc(var(--topbar-height) + var(--topbar-offset) + 2rem);
    }
}

.faq-accordion {
    display: grid;
    gap: 0.75rem;
}

.faq-item {
    border-radius: var(--radius);
    transition: background-color 0.2s ease;
}

.faq-item[open] {
    background: var(--glass-fill-strong);
}

.faq-answer a {
    color: var(--text);
    text-decoration-color: color-mix(in srgb, var(--accent) 70%, var(--text-muted));
    text-decoration-thickness: 2px;
    text-underline-offset: 3px;
}

/* The questions and answers are not selectable, so tapping a question does not select its text.
   Links in the answers still work. */
.faq-item summary,
.faq-answer {
    -webkit-user-select: none;
    user-select: none;
}

.faq-item summary {
    display: flex;
    align-items: center;
    gap: 1rem;
    min-height: 44px;
    padding: 1.15rem 1.5rem;
    font-size: 1.0625rem;
    font-weight: 600;
    line-height: 1.45;
    color: var(--text);
    cursor: pointer;
    list-style: none;
}

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

.faq-item summary:focus-visible {
    outline-offset: -3px;
    border-radius: var(--radius);
}

/* A plus in a small circle that turns into a cross. */
.faq-item summary::after {
    content: '';
    flex-shrink: 0;
    width: 1.75rem;
    height: 1.75rem;
    margin-left: auto;
    border-radius: 50%;
    background:
        linear-gradient(var(--text) 0 0) center / 10px 1.5px no-repeat,
        linear-gradient(var(--text) 0 0) center / 1.5px 10px no-repeat,
        color-mix(in srgb, var(--text) 7%, transparent);
    transition: transform 0.3s var(--ease-spring);
}

.faq-item[open] summary::after {
    transform: rotate(45deg);
}

.faq-body {
    padding: 0 1.5rem 1.35rem;
}

.faq-answer {
    margin: 0;
    color: var(--text-muted);
}
