/* ==========================================================================
   AirParkFlow landing
   Tokens are semantic, so the one light section on the page (.on-paper) is a value
   swap rather than a set of component overrides.
   Palette matches ParkingES.Core.Domain.Shared/TenantBrand/TenantBrandDefaults.cs
   so the marketing site and the product a buyer signs into are one system.
   ========================================================================== */

/* Self-hosted rather than linked from Google: that link was the page's last third-party
   request, it blocked first paint behind a DNS and TLS handshake, and it sent every Spanish
   visitor's IP to Google, which this site has no consent flow to cover.

   One family, not two. Geist and Inter are both neutral grotesques with near-identical
   proportions and x-height — at body size you cannot tell them apart, so the "pairing" cost
   a second font request and bought no contrast. Geist carries display and body; the
   contrast the page needed comes from the monospace face instead, which is a genuinely
   different voice and belongs to the subject (plates, refs, flight codes, times).

   Variable font, so one file carries every weight. Latin subset only: Spanish accents and
   punctuation (ñ á é í ó ú ¿ ¡) all sit inside U+00xx.

   Geist: MIT (Vercel). Redistributable. */
@font-face {
    font-family: 'Geist';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url('../fonts/geist-latin-var.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
        U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212,
        U+2215, U+FEFF, U+FFFD;
}


:root,
.on-ink {
    /* ---------------------------------------------------------------- ground

       Two rooms, and which one a section gets says what the section is for.

       Ink argues: the hero, the board moment, the closing ask. Paper demonstrates: the
       journey steps and the form. That split is not decoration — the product is light-only,
       so a near-white screenshot on near-black was a bright slab meeting a dark page with a
       hairline between them, and no amount of framing fixes the mass. Put the evidence in a
       light room and it stops fighting; keep the argument in ink and the page still opens
       the way it did.

       Every screenshot on this page is a light app UI. On a near-white ground they had
       nothing to be bright against, and the page spent its dark tier on three short bands
       that read as stripes rather than as a register. Inverted, the product shots become the
       only luminous objects on the page and carry themselves. The single light section is
       the form — see .on-paper — where the inversion tells the eye it has arrived at the
       part it is meant to act on.

       Contrast, measured against --paper #0b1020:
         text-primary 16.6:1  ·  text-secondary 9.1:1  ·  text-muted 6.7:1
         accent 9.5:1  ·  recogida 11.2:1
       All clear AA, including on --surface and --surface-sunken. */
    --paper: #0b1020;
    --surface: #141a2e;
    --surface-sunken: #070b16;
    --surface-raised: #1b2340;
    --text-primary: #eef0f7;
    --text-secondary: #aab3d0;
    --text-muted: #9099b8;
    --line: rgba(255, 255, 255, 0.10);
    --line-strong: rgba(255, 255, 255, 0.20);

    /* ----------------------------------------------------------------- brand

       The saturated indigo is unreadable on ink, so the accent that actually appears in
       text and rules is the same hue lightened. #4f46e5 survives in exactly one place — the
       primary button, which is a solid with white on top — so the brand colour still lands
       without being asked to do a job it fails at.

       Two colours, not one, because the product already has two and they mean something:
       the operations board colours a drop-off indigo and a pickup orange. Reusing that pair
       here means the accent is carrying a real distinction rather than decorating. */
    --accent: #a5b4fc;
    --accent-solid: #4f46e5;
    --accent-solid-hover: #4338ca;
    --accent-tint: rgba(165, 180, 252, 0.14);
    --accent-ring: rgba(165, 180, 252, 0.45);

    --entrega: #b3bcff;
    --recogida: #fdba74;

    --success: #6ee7b7;
    --success-tint: rgba(110, 231, 183, 0.12);
    --error: #fda4a4;
    --error-tint: rgba(253, 164, 164, 0.12);

    /* Type scale. One scale, roughly 1.35x per step, so every level is visibly a level:
         display 64 / section 44 / chapter 32 / step 24 / lede 19 / body 17 */
    --text-section: clamp(1.875rem, 3.4vw, 2.75rem);
    --text-chapter: clamp(1.5rem, 2.4vw, 2rem);
    --text-step: clamp(1.25rem, 1.8vw, 1.5rem);
    --text-lede: 1.1875rem;
    --text-body: 1.0625rem;

    /* Type. Geist carries display and body; the mono is the second voice. */
    --font-display: "Geist", system-ui, sans-serif;
    --font-body: "Geist", system-ui, -apple-system, sans-serif;
    /* Plates, booking refs, flight codes, terminals and times. The domain's own artifacts
       are identifiers, and identifiers want fixed widths. Promoted out of captions: this is
       the only face on the page with a distinct voice, and it was being spent on footnotes. */
    --font-mono: ui-monospace, "SF Mono", "Geist Mono", Menlo, Consolas, monospace;

    /* Shape lock: pill for interactive, one card radius, one input radius.
       8px, not 16: this is operations software, and a crisp corner reads as an instrument
       rather than a consumer app. */
    --radius-card: 8px;
    --radius-input: 6px;
    --radius-pill: 999px;
    --radius-focus: 4px;
    /* Depicts a physical phone bezel, so it is intentionally outside the UI scale. */
    --radius-device: 28px;

    /* Spacing scale. */
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;
    --space-8: 64px;
    --space-9: 88px;

    /* On ink a shadow cannot be seen; depth comes from a lighter rim and a cast that is
       darker than the ground rather than a grey blur. */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.40);
    --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 24px 60px rgba(2, 6, 23, 0.65), 0 2px 8px rgba(2, 6, 23, 0.45);

    --ease: cubic-bezier(0.16, 1, 0.3, 1);
}

/* Restores the ink room inside a light one — the board stage is the page's one dark moment
   and it now sits in the middle of the paper journey. */
.on-ink {
    color: var(--text-primary);
    background: var(--paper);
}

/* The light room. Swapping the same semantic tokens back to their paper values re-skins
   every component inside without a single component-level override — which is what the
   tokens were built to allow. Two sections earn it: the journey, because it is nothing but
   screenshots of a light product, and the form, because paper is what you fill in. */
.on-paper {
    /* The document is color-scheme: dark, which native radios, checkboxes and scrollbars
       follow. Inside this section that produced black controls on white. */
    color-scheme: light;

    --paper: #f7f7f8;
    --surface: #ffffff;
    --surface-sunken: #eceef3;
    --surface-raised: #ffffff;
    --text-primary: #0f172a;
    --text-secondary: #55617a;
    --text-muted: #667085;
    --line: #e4e8f0;
    --line-strong: #cfd6e4;

    --accent: #4338ca;
    --accent-tint: #eef2ff;
    --accent-ring: rgba(79, 70, 229, 0.32);

    --entrega: #4338ca;
    /* #b45309 measured 4.33:1 on the light bezel; this is the same hue one step down. */
    --recogida: #92400e;

    --success: #047857;
    --success-tint: #ecfdf5;
    --error: #b42318;
    --error-tint: #fef3f2;

    --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06), 0 1px 3px rgba(15, 23, 42, 0.04);
    --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.06), 0 12px 28px rgba(15, 23, 42, 0.06);
    --shadow-lg: 0 8px 24px rgba(15, 23, 42, 0.08), 0 24px 56px rgba(15, 23, 42, 0.08);

    color: var(--text-primary);
    background: var(--paper);
}

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

html {
    scroll-behavior: smooth;
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    color: var(--text-primary);
    background: var(--paper);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

a {
    color: inherit;
    text-decoration: none;
}

img {
    display: block;
    max-width: 100%;
    height: auto;
}

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

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

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

.shell {
    width: min(1160px, calc(100% - 48px));
    margin-inline: auto;
}

.section {
    padding-block: var(--space-9);
}

.lede {
    max-width: 60ch;
    color: var(--text-secondary);
    font-size: var(--text-lede);
    line-height: 1.65;
}

/* The eyebrow is the first place the mono earns its promotion: it is a label, and a label
   set in the identifier face reads as a field name rather than as small marketing type. */
.eyebrow {
    margin-bottom: var(--space-3);
    color: var(--accent);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.skip-link {
    position: absolute;
    left: -9999px;
    z-index: 100;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-input);
    color: var(--surface);
    background: var(--text-primary);
}

.skip-link:focus {
    left: var(--space-4);
    top: var(--space-4);
}

/* ---------------------------------------------------------------- buttons */

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 46px;
    padding-inline: var(--space-5);
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    cursor: pointer;
    font: inherit;
    font-size: 0.9375rem;
    font-weight: 600;
    white-space: nowrap;
    transition: background 160ms var(--ease), border-color 160ms var(--ease),
                box-shadow 160ms var(--ease), transform 90ms var(--ease);
}

.button-primary {
    color: #ffffff;
    background: var(--accent-solid);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.18) inset, var(--shadow-md);
}

.button-primary:hover {
    background: var(--accent-solid-hover);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.22) inset, 0 0 0 4px var(--accent-tint);
}

.button-secondary {
    color: var(--text-primary);
    background: rgba(255, 255, 255, 0.05);
    border-color: var(--line-strong);
}

.button-secondary:hover {
    border-color: rgba(255, 255, 255, 0.38);
    background: rgba(255, 255, 255, 0.10);
}

/* The pair that sits on ink. White-on-ink is the strongest contrast the palette has, so it
   carries the primary ask; the ghost is a bordered sibling rather than a second solid, which
   would make the band read as two competing CTAs. */
.button-light {
    color: var(--surface-sunken);
    background: var(--text-primary);
    box-shadow: none;
}

.button-light:hover {
    background: #ffffff;
}

.button-ghost {
    color: var(--text-primary);
    border-color: rgba(255, 255, 255, 0.28);
    background: transparent;
}

.button-ghost:hover {
    border-color: rgba(255, 255, 255, 0.55);
    background: rgba(255, 255, 255, 0.06);
}

.button:active {
    transform: translateY(1px);
}

.button-full {
    width: 100%;
}

.site-header {
    position: sticky;
    top: 0;
    z-index: 20;
    border-bottom: 1px solid var(--line);
    background: rgba(11, 16, 32, 0.72);
    backdrop-filter: blur(14px) saturate(1.4);
}

.nav-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-5);
    min-height: 68px;
}

/* Its own colour, not the surrounding text's. The footer dims its row to --text-secondary
   for the tagline and links, and the wordmark was inheriting that — so the same brand read
   white in the header and grey at the bottom of the page. */
.brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--text-primary);
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}

/* The mark, not the app icon. logo_new.png is a white glyph on a solid indigo tile; that
   tile belongs on a favicon or a home-screen icon, which land on grounds we do not control,
   and not here, where the header already is one — and where it put a second block of brand
   indigo beside the CTA, so identity and action read as the same signal.

   Drawn as a mask rather than an <img> so the glyph takes currentColor: the page has two
   rooms now, and a mark with its colour baked in is exactly the thing that survives the
   first of them and breaks in the second. */

.brand img {
    width: 34px;
    height: 34px;
    border-radius: var(--radius-input);
}

.brand-wordmark__accent {
    color: var(--accent);
}

.nav-links {
    display: flex;
    align-items: center;
    gap: var(--space-6);
    margin-inline-start: auto;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    font-weight: 500;
}

.nav-links a {
    padding-block: var(--space-2);
    border-bottom: 2px solid transparent;
    transition: color 140ms var(--ease), border-color 140ms var(--ease);
}

.nav-links a:hover {
    color: var(--text-primary);
    border-bottom-color: var(--accent);
}

.nav-actions {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}

.lang-switch {
    display: inline-flex;
    padding: 3px;
    border: 1px solid var(--line);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.05);
}

.lang-switch-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 36px;
    min-height: 30px;
    padding-inline: var(--space-2);
    border-radius: var(--radius-pill);
    /* --text-muted measured 4.29:1 against the switch's own ground once the page moved to
       paper. --text-secondary clears AA at 5.36:1. */
    color: var(--text-secondary);
    font-size: 0.8125rem;
    font-weight: 600;
    transition: color 140ms var(--ease), background 140ms var(--ease);
}

.lang-switch-link:hover {
    color: var(--text-primary);
}

.lang-switch-link.is-active {
    color: var(--text-primary);
    background: rgba(255, 255, 255, 0.12);
    box-shadow: none;
}

/* Mobile disclosure. Native details/summary keeps keyboard and expanded
   semantics without any JavaScript. */
.nav-disclosure {
    display: none;
    position: relative;
}

.nav-disclosure > summary {
    display: grid;
    place-items: center;
    width: 42px;
    height: 42px;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-input);
    cursor: pointer;
    list-style: none;
}

.nav-disclosure > summary::-webkit-details-marker {
    display: none;
}

.nav-disclosure-bars,
.nav-disclosure-bars::before,
.nav-disclosure-bars::after {
    display: block;
    width: 18px;
    height: 2px;
    border-radius: 2px;
    background: var(--text-primary);
}

.nav-disclosure-bars {
    position: relative;
}

.nav-disclosure-bars::before,
.nav-disclosure-bars::after {
    position: absolute;
    left: 0;
    content: "";
}

.nav-disclosure-bars::before { top: -6px; }
.nav-disclosure-bars::after  { top: 6px; }

.nav-disclosure-panel {
    position: absolute;
    top: calc(100% + 12px);
    right: 0;
    display: grid;
    gap: var(--space-4);
    width: max(220px, 60vw);
    padding: var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
    font-weight: 500;
}

/* ------------------------------------------------------------------ hero

   Asymmetric, and the product visual is live HTML rather than a screenshot.

   The previous arrangement — centred eyebrow, centred headline, centred subhead, two centred
   buttons, screenshot below — is the single most-shipped hero in SaaS, and it read as one.
   Splitting it puts the claim and the evidence side by side instead of stacked, and the
   evidence is now the object the operator actually stares at all day: the next few tasks,
   counting down. Built in markup, so it is crisp at any pixel density, localises, and can
   carry the one moving thing on the page. */
.hero {
    position: relative;
    padding-block: var(--space-8) var(--space-8);
    overflow: hidden;
}

.hero::before {
    content: "";
    position: absolute;
    inset: -35% 20% auto -25%;
    height: 120%;
    pointer-events: none;
    background:
        radial-gradient(ellipse 42% 45% at 38% 45%, rgba(110, 100, 255, 0.42), transparent 68%),
        radial-gradient(ellipse 30% 35% at 62% 62%, rgba(129, 140, 248, 0.22), transparent 70%);
    filter: blur(30px);
}

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

.hero-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
    align-items: center;
    gap: var(--space-8);
}

.hero-copy {
    max-width: 34rem;
}

/* Scale is planned against the copy column width so the Spanish headline,
   which is the longer of the two locales, stays within three lines. */
.hero-copy h1 {
    font-size: clamp(2.25rem, 4.2vw, 3.5rem);
    /* Greedy wrap, not the inherited balance: the sentences are held together by
       non-breaking spaces, so greedy fills whole sentences per line and lands the
       break on a full stop. */
    text-wrap: wrap;
    letter-spacing: -0.032em;
    line-height: 1.08;
}

.hero-text {
    max-width: 44ch;
    margin-top: var(--space-5);
    color: var(--text-secondary);
    font-size: var(--text-lede);
    line-height: 1.6;
}

.hero-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
    margin-top: var(--space-6);
}

/* ------------------------------------------------------- hero task board */

.hero-board {
    position: relative;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-card);
    background:
        linear-gradient(rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0)) ,
        var(--surface);
    box-shadow: var(--shadow-lg);
}

.hero-board__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--line);
}

.hero-board__title {
    font-size: 0.9375rem;
    font-weight: 650;
    letter-spacing: -0.015em;
}

/* The clock is the page's one live element. A pulse rather than a ticking number: a number
   that moves invites the reader to check it, and it would be lying — the board behind it is
   a fixed moment. The dot only says the surface is live. */
.hero-board__clock {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--text-secondary);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
}

.hero-board__clock::before {
    content: "";
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
    animation: pulse 2.4s var(--ease) infinite;
}

@keyframes pulse {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 var(--accent-ring); }
    50%      { opacity: 0.65; box-shadow: 0 0 0 5px transparent; }
}

.hero-board__list {
    display: grid;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* The row is the product's own object: kind, who, reference, plate, countdown. Drop-off
   indigo and pickup orange are the operations board's colours, not a decorative pair. */
.task {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-3) var(--space-4);
    padding: var(--space-4) var(--space-5);
    border-bottom: 1px solid var(--line);
}

.task:last-child {
    border-bottom: 0;
}

.task__kind {
    grid-column: 1 / -1;
    color: var(--kind, var(--accent));
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.task--pickup {
    --kind: var(--recogida);
}

.task__who {
    min-width: 0;
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: -0.01em;
}

.task__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: 6px;
}

.task__due {
    text-align: right;
    line-height: 1.2;
}

.task__due b {
    display: block;
    color: var(--kind, var(--accent));
    font-family: var(--font-mono);
    font-size: 1.0625rem;
    font-weight: 600;
    letter-spacing: -0.02em;
}

.task__due span {
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.75rem;
}

.hero-board__foot {
    padding: var(--space-3) var(--space-5);
    border-top: 1px solid var(--line);
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    text-align: center;
}

/* A monospaced chip for the domain's identifiers — plates, booking refs, flight codes.
   These are the artifacts the operator reads off a screen all day; giving them a fixed-width
   face and a border makes them read as data rather than as more sentence. */
.chip {
    display: inline-flex;
    align-items: center;
    padding: 2px 7px;
    border: 1px solid var(--line);
    border-radius: var(--radius-focus);
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-secondary);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: -0.01em;
    white-space: nowrap;
}

.chip--plate {
    color: var(--text-primary);
    font-weight: 600;
}


/* Five grey words centred in a band was filler in logo-wall position, claiming credibility
   it did not carry. Same five capabilities, now set as a labelled row that reads as a spec
   line rather than a fake trust strip. */
/* ----------------------------------------------------------- board stage

   The page's one loud moment. Everything else is disciplined and quiet so this can be big:
   the operations board, full bleed, lit from behind, at its native resolution. It appears
   exactly once — the argument is "here is the surface your day runs on", and repeating it
   would turn the argument into a slideshow. */

.board-stage {
    position: relative;
    margin-bottom: var(--space-8);
    padding-block: var(--space-8) var(--space-9);
    background: var(--surface-sunken);
    overflow: hidden;
}

.board-stage::before {
    content: "";
    position: absolute;
    inset: -30% -10% auto -10%;
    height: 80%;
    pointer-events: none;
    background: radial-gradient(ellipse 45% 55% at 50% 30%, rgba(99, 91, 255, 0.34), transparent 70%);
    filter: blur(24px);
}

.board-stage .shell {
    position: relative;
    z-index: 1;
}

.board-stage__head {
    margin-bottom: var(--space-6);
}

.board-stage__note {
    max-width: 76ch;
}

.board-stage__head h2 {
    max-width: 24ch;
    font-size: var(--text-chapter);
}

/* ------------------------------------------------------------------ crop

   A screenshot shown below about 0.8 of its own scale stops being evidence and becomes
   texture: the app's 13px UI type lands at 6px and nobody reads it. Four shots on this page
   were running at 0.43–0.51 because a whole 1200px app frame was being squeezed into a
   half-width column, when the sentence beside each one only ever referred to one card in it.

   So: crop to the card, in CSS, from the same source file. --fx/--fy are the crop origin as
   a fraction of the source, --fw/--fh its size, --ar the resulting box ratio (source ratio
   x --fw / --fh). Translate percentages resolve against the image's own box, which is what
   makes the offsets exact at any container width. */

/* ---------------------------------------------------------------- screen

   The product is light-only by design (the admin sets darkModeSelector: 'none'), so on an
   ink page every screenshot arrives as a bright rectangle with no explanation. Tinting them
   to match would be lying about what a buyer signs into.

   So the light is made deliberate instead: each shot sits inside dark window chrome with a
   title bar, which is what a screen looks like when it is on. The frame does three jobs at
   once — it stops the white reading as an unfinished blob, it gives five differently shaped
   captures one silhouette, and the bar carries the identifier voice into the position the
   loose caption underneath used to occupy.

   The pale outer shadow is the screen emitting rather than a glow effect: a lit panel throws
   light onto what is behind it, and without it the frame sat on the page like a sticker. */

.screen {
    margin: 0;
    padding: 10px;
    border: 1px solid var(--line-strong);
    border-radius: 14px;
    background: var(--surface);
    /* The cast holds the frame off the page; the pale ring is the screen emitting onto what
       is behind it. A lit panel throws light, and without it a bright rectangle on ink reads
       as a hole punched in the page rather than as a screen that is on. */
    box-shadow:
        var(--shadow-lg),
        0 0 0 1px rgba(255, 255, 255, 0.04),
        0 12px 90px -10px rgba(150, 165, 255, 0.22);
}

/* No horizontal padding of its own, and its bottom gap equals the frame's inset. The bar
   sits inside .screen's 10px, so any padding here stacks on top of it — 4px 6px 12px gave
   the frame four different gutters (16px beside the label, 14px above it, 12px under the
   bar, 10px around the shot) and read as the frames being padded inconsistently. One value
   now: the label's edges line up with the screenshot's edges. */
.screen__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: 0 0 10px;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: -0.01em;
}

.screen__path {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    min-width: 0;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A single dot, not three. Three coloured circles are macOS cosplay: they say "this is a
   picture of a Mac", which is not a claim this page needs to make. One dot says the surface
   is live, and it is the same marker the hero board already uses. */
.screen__path::before {
    content: "";
    flex: none;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--state, var(--accent));
}

.screen__state {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    color: var(--state, var(--accent));
    font-weight: 600;
    letter-spacing: 0.04em;
    text-overflow: ellipsis;
    text-transform: uppercase;
    white-space: nowrap;
}

.screen--pickup {
    --state: var(--recogida);
}

/* Inset, with its own hairline. The bezel is what the phone shots have and the app shots did
   not: 10px of frame between the white and the page, so the eye crosses two edges instead of
   falling off one. The frame owns the outer radius; the screen gets a smaller inner one. */
.screen > picture > img,
.screen > img {
    display: block;
    width: 100%;
    border: 1px solid rgba(255, 255, 255, 0.10);
    border-radius: 5px;
    box-shadow: none;
}

/* In the light room the bezel needs to be a tone down from the page, not up, and the pale
   emission ring has nothing to emit against. */
.on-paper .screen {
    background: var(--surface-sunken);
    box-shadow: var(--shadow-md);
}

.on-paper .screen > picture > img,
.on-paper .screen > img {
    border-color: var(--line-strong);
}

/* ------------------------------------------------------------ status rail

   The three chapters were "El cliente reserva. / Operaciones diarias. / Recogida." — labels
   invented for the page. The product already has a typed sequence that means something and
   that the reader will meet again inside the app: a reservation is Confirmada, then
   Entregada, then Completada. Using the real state machine makes the spine informative
   rather than decorative, and sticking it to the top means the reader always knows which
   state the screenshot in front of them belongs to.

   Orange on the last state for the same reason the task rows use it: pickup is the
   operations board's orange. */

/* Chrome, not content: the rail is a dark bar that stays dark in the light room, so it and
   the header read as one stack the page scrolls under. It carries .on-ink for that reason —
   inside .on-paper its own tokens would have resolved to dark-on-dark. */
.status-rail {
    position: sticky;
    top: 68px;
    z-index: 10;
    margin-bottom: var(--space-7);
    border-block: 1px solid rgba(255, 255, 255, 0.10);
    background: rgba(11, 16, 32, 0.95);
    backdrop-filter: blur(14px) saturate(1.4);
}

.status-rail ol {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: 0;
    list-style: none;
    overflow-x: auto;
    scrollbar-width: none;
}

.status-rail ol::-webkit-scrollbar {
    display: none;
}

.status-rail li {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding-block: var(--space-4);
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    transition: color 260ms var(--ease);
}

/* The connector is the rule between states, so the row reads as a sequence rather than as
   three separate labels. It fills as the reader advances. */
.status-rail li:not(:last-child)::after {
    content: "";
    width: clamp(16px, 5vw, 64px);
    height: 1px;
    background: var(--line-strong);
    transition: background 260ms var(--ease);
}

.status-rail li::before {
    content: "";
    width: 7px;
    height: 7px;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    transition: background 260ms var(--ease), border-color 260ms var(--ease),
                box-shadow 260ms var(--ease);
}

.status-rail li.is-done {
    color: var(--text-secondary);
}

.status-rail li.is-done::before {
    border-color: var(--state, var(--accent));
    background: var(--state, var(--accent));
}

.status-rail li.is-done:not(:last-child)::after {
    background: var(--state, var(--accent));
}

.status-rail li.is-current {
    color: var(--state, var(--accent));
}

.status-rail li.is-current::before {
    border-color: var(--state, var(--accent));
    background: var(--state, var(--accent));
    box-shadow: 0 0 0 4px color-mix(in srgb, var(--state, var(--accent)) 22%, transparent);
}

.status-rail li:last-child {
    --state: var(--recogida);
}

.capability-strip {
    padding-block: var(--space-5);
    border-block: 1px solid var(--line);
    background: var(--surface-sunken);
}

.capability-grid {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-3) var(--space-7);
}

/* Five words spaced evenly across a rule was filler in logo-wall position, claiming
   credibility it did not carry. Set in the identifier face at real weight, the same five
   read as a spec line rather than a fake trust strip. */
.capability-grid span {
    display: inline-flex;
    align-items: center;
    gap: var(--space-3);
    color: var(--text-secondary);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    font-weight: 500;
    letter-spacing: -0.01em;
}

/* The dot before each item was decoration standing in for meaning — it carried no state and
   repeated five times. The identifier face and the spacing already separate the items. */

/* A coloured dot before every label is decoration pretending to be status. The words are
   already a list; separating them with space is enough. */

/* --------------------------------------------------------------- journey */

.journey-intro {
    margin-bottom: var(--space-8);
}

.journey-intro h2,
.journey-intro .lede {
    max-width: 46rem;
}

.journey-intro h2 {
    font-size: var(--text-section);
}

.journey-intro .lede {
    margin-top: var(--space-4);
}

.step {
    margin-bottom: var(--space-8);
}

.step-copy h3 {
    font-size: var(--text-step);
}

.step-copy p {
    max-width: 52ch;
    margin-top: var(--space-4);
    color: var(--text-secondary);
    font-size: var(--text-body);
}

.step-copy-wide p {
    max-width: 68ch;
}

/* Selector carries its own weight instead of !important. The two !important declarations
   here existed to beat `.step-copy p`, which out-specifies a lone class — and in doing so
   they made every contextual override of this element dead code, including the one the dark
   band needs. Matching `.step-copy p` and adding the class wins on specificity alone. */
.step-copy p.step-highlight,
.board-stage .step-highlight {
    display: inline-block;
    margin-top: var(--space-5);
    padding: var(--space-3) var(--space-4);
    border-left: 3px solid var(--accent);
    border-radius: 0 var(--radius-input) var(--radius-input) 0;
    color: var(--accent);
    background: var(--accent-tint);
    font-weight: 600;
}

/* No stage. On paper a screenshot needed a tinted ground so white app chrome would not
   dissolve into a near-white page; on ink it is the brightest object in the section and
   carries itself. The border and the cast are all the separation it needs. */
.step-visual {
    position: relative;
}

/* A caption turns a screenshot from decoration into evidence: it names what the reader is
   looking at and states the real values in the shot — the reservation code, the plate, the
   money, the time. Every one of these is genuinely on screen above it. */
.shot-caption {
    margin: var(--space-4) 0 0;
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    line-height: 1.5;
    letter-spacing: -0.01em;
}

/* Family A: asymmetric split. The screenshot is the visual, not a card. */
/* 0.6fr was sized for a single phone. The trio needs roughly 530px to sit at full size
   without the flex basis collapsing, so the columns even out. */
.step-split {
    display: grid;
    grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
    align-items: center;
    gap: var(--space-7);
}

/* Three phones rather than one: the customer books, gets confirmed, and is told where to go.
   A single screen could only show the first of those. The outer two sit back and slightly
   lower so the eye lands on the middle one, and the negative margins let them overlap
   instead of reading as three separate pictures in a row. */
.step-visual-phone {
    max-width: none;
    justify-self: stretch;
}

.phone-trio {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
}

/* The trio is the flex container itself, so a caption placed inside it lands beside the
   phones rather than under them. Wrapping onto its own full-width line puts it back. */
.phone-trio .shot-caption {
    flex: 0 0 100%;
    order: 1;
    text-align: center;
}

.phone-trio__item {
    flex: 0 1 200px;
    display: block;
}

/* The phone frames are baked into the PNGs, with the bezel corners cut out as alpha. So the
   image supplies its own border and its own radius, and any card chrome laid over it draws a
   straight edge across a rounded corner — which is exactly what a stray `.step-visual >
   picture > img` rule did here: an 8px radius and a 1px border cutting the corners, with the
   shadow showing through the transparent pixels behind them. Stated explicitly now. */
.phone-trio__item img {
    display: block;
    width: 100%;
    height: auto;
    border: 0;
    border-radius: var(--radius-device);
}

/* Set back by scale, offset and overlap — not by opacity. Fading them worked on ink, where
   a dimmed thing reads as further away; on paper the same 14% reads as washed out, which is
   the one thing a product shot must not look like. */
.phone-trio__item--back {
    transform: translateY(18px) scale(0.9);
}

.phone-trio__item--back:first-child {
    margin-right: -34px;
}

.phone-trio__item--back:last-child {
    margin-left: -34px;
}

/* The lead phone sits above both neighbours and carries the heavier shadow. */
.phone-trio__item--front {
    position: relative;
    z-index: 1;
}

.phone-trio__item--front img {
    box-shadow: var(--shadow-lg);
}

.phone-trio__item--back img {
    box-shadow: var(--shadow-md);
}

/* Family B: full-bleed band. It used to be the page's dark moment; now that ink is the
   ground, it lifts instead — a raised surface running edge to edge. The board stage owns the
   deep end, so these two never read as the same device. */
.step-band {
    margin-bottom: var(--space-8);
    padding-block: var(--space-9);
    border-block: 1px solid var(--line);
    background: var(--surface);
}

.step-band .step-copy p.step-highlight {
    border-left-color: var(--accent);
    color: var(--accent);
    background: rgba(165, 180, 252, 0.12);
}

.step-band-inner {
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    align-items: center;
    gap: var(--space-8);
}

/* Family C: full-width stage, copy above the widest asset. */
.step-stage {
    display: grid;
    gap: var(--space-6);
}

.step-visual-stage img {
    border-radius: var(--radius-card);
}

/* Family D: paired cells. Parallel items, so a container earns its keep. */
.step-pair {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5);
    margin-bottom: var(--space-8);
}

.pair-cell {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
    min-width: 0;
    padding: var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
}

.pair-cell h3 {
    font-size: 1.1875rem;
}

.pair-cell p {
    color: var(--text-secondary);
    font-size: 0.9375rem;
}

/* The frame sits on the cell floor. The two shots are different shapes because they are
   different things — a dialog and a board — so forcing one ratio on both meant cutting
   through a card in whichever lost. Copy first lines the headings up, and this lines the
   frames up, without either image being cropped to suit the other. */
.pair-cell .step-visual {
    margin-top: auto;
}

/* Closing pair, tighter than the openers. */
.step-close {
    display: grid;
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    align-items: center;
    gap: var(--space-7);
}

/* The finale. Everything above it alternates copy-left/asset-right, and running that rhythm
   one more time made the payoff land as just another row. Centred and full width, it reads
   as the end of the story rather than the last item in a list. */
.step-final {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
    text-align: center;
}

.step-final .step-copy {
    max-width: 46ch;
    margin-inline: auto;
}

.step-final .step-copy h3 {
    font-size: clamp(1.5rem, 2.6vw, 2rem);
    letter-spacing: -0.02em;
}

.step-final .step-visual .screen {
    border-color: var(--accent-ring);
}

/* The closing ask. Sunken and lit from behind, so it bookends the hero rather than
   arriving as one more section of body copy. */
.pilot-band {
    position: relative;
    padding-block: var(--space-9);
    background: var(--surface-sunken);
    overflow: hidden;
}

.pilot-band::before {
    content: "";
    position: absolute;
    inset: auto -10% -40% -10%;
    height: 80%;
    pointer-events: none;
    background: radial-gradient(ellipse 45% 60% at 50% 70%, rgba(99, 91, 255, 0.26), transparent 70%);
    filter: blur(24px);
}

.pilot-band .shell {
    position: relative;
    z-index: 1;
}



.pilot-head h2 {
    max-width: 20ch;
    font-size: var(--text-section);
    letter-spacing: -0.025em;
}

.pilot-head .lede {
    margin-top: var(--space-4);
}

/* Three terms, separated by a single vertical rule rather than boxed into three equal
   cards. The rule falls away on mobile where the stack already separates them. */
.pilot-terms {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-6);
    margin: var(--space-8) 0 var(--space-7);
}

.pilot-term {
    padding-left: var(--space-5);
    border-left: 2px solid var(--accent);
}

.pilot-term dt {
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -0.015em;
    color: var(--text-primary);
}

.pilot-term dd {
    margin: var(--space-2) 0 0;
    color: var(--text-secondary);
    font-size: 0.9375rem;
    line-height: 1.6;
}



.pilot-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3);
}

/* The page's one light room; see .on-paper for why. */
.forms-section {
    border-block: 1px solid var(--line);
}

.forms-intro {
    margin-bottom: var(--space-7);
}

.forms-intro h2,
.forms-intro .lede {
    max-width: 46rem;
}

.forms-intro h2 {
    font-size: var(--text-section);
}

.forms-intro .lede {
    margin-top: var(--space-4);
}

/* One form, centred and narrow. Two side-by-side cards asking for the same four fields
   split the conversion and read as a layout someone had not finished deciding about. */
.forms-shell {
    max-width: 44rem;
}

.lead-form-single {
    padding: var(--space-7);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
    box-shadow: var(--shadow-md);
}

/* Demo or pilot, as a choice inside the form. Two selectable panels rather than bare radios:
   the note under each title is what actually distinguishes them, and it needs room. */
.intent-choice {
    margin: 0 0 var(--space-2);
    padding: 0;
    border: 0;
}

.intent-choice legend {
    padding: 0;
    margin-bottom: var(--space-3);
    color: var(--text-secondary);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.intent-options {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-3);
}

.intent-option {
    display: flex;
    gap: var(--space-3);
    align-items: flex-start;
    padding: var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius-input);
    background: var(--paper);
    cursor: pointer;
    transition: border-color 160ms var(--ease), background 160ms var(--ease);
}

.intent-option:hover {
    border-color: var(--line-strong);
}

.intent-option:has(input:checked) {
    border-color: var(--accent);
    background: var(--accent-tint);
}

.intent-option:has(input:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.intent-option input {
    margin: 0;
    flex: none;
    width: 18px;
    height: 18px;
    accent-color: var(--accent);
}

.intent-option__body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.intent-option__title {
    font-family: var(--font-display);
    font-size: 0.9375rem;
    font-weight: 650;
    color: var(--text-primary);
}

.intent-option__note {
    color: var(--text-secondary);
    font-size: 0.8125rem;
    line-height: 1.45;
}

/* Name/company and email/phone pair up; the form is half as tall as the stacked version. */
.field-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-4);
}

.button-submit {
    margin-top: var(--space-2);
    width: 100%;
}

.lead-form {
    display: grid;
    gap: var(--space-4);
}

.field {
    display: grid;
    gap: 6px;
}

.lead-form label {
    color: var(--text-primary);
    font-size: 0.875rem;
    font-weight: 600;
}

.lead-form input:not([type="checkbox"]):not([type="radio"]) {
    width: 100%;
    min-height: 46px;
    padding-inline: var(--space-4);
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-input);
    outline: none;
    color: var(--text-primary);
    background: var(--surface);
    font: inherit;
    transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}

.lead-form input::placeholder {
    color: var(--text-muted);
}

.lead-form input:not([type="checkbox"]):not([type="radio"]):focus {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-ring);
}

.lead-form input[type="checkbox"] {
    width: 18px;
    height: 18px;
    margin: 2px 0 0;
    flex: 0 0 auto;
    accent-color: var(--accent);
}

.consent-row {
    display: grid;
    gap: 6px;
}

/* Same story as .step-highlight: three !important declarations to out-rank `.lead-form
   label`. Naming the label in the selector wins on specificity and leaves the rule
   overridable. */
.lead-form label.consent-label {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    color: var(--text-secondary);
    font-size: 0.875rem;
    font-weight: 400;
    line-height: 1.5;
    cursor: pointer;
}

.consent-label a {
    color: var(--accent);
    font-weight: 600;
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.field-error,
.validation-summary {
    color: var(--error);
    font-size: 0.8125rem;
    font-weight: 500;
}

.field-error:empty {
    display: none;
}

.validation-summary ul {
    margin: 0;
    padding-left: var(--space-5);
}

.validation-summary:has(ul:empty) {
    display: none;
}

.lead-form button {
    margin-top: var(--space-2);
}

.alert {
    margin-top: var(--space-5);
    padding: var(--space-4);
    border-radius: var(--radius-input);
    font-size: 0.9375rem;
    font-weight: 500;
}

.alert-success {
    color: var(--success);
    background: var(--success-tint);
    border: 1px solid rgba(4, 120, 87, 0.24);
}

.alert-error {
    color: var(--error);
    background: var(--error-tint);
    border: 1px solid rgba(180, 35, 24, 0.24);
}

/* ------------------------------------------------------------------- faq */

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

.faq-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    gap: var(--space-8);
    align-items: start;
}

.faq-grid > h2 {
    font-size: var(--text-section);
    max-width: 18ch;
}

/* Three bordered boxes stacked in a column is the same card treatment the rest of the page
   just stopped using. Hairline rules give the same grouping without another container, and
   the question itself becomes the affordance. */
.faq-list {
    display: grid;
    border-top: 1px solid var(--line);
}

.faq-list details {
    border-bottom: 1px solid var(--line);
}

.faq-list summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding-block: var(--space-5);
    cursor: pointer;
    font-family: var(--font-display);
    font-size: 1.0625rem;
    font-weight: 650;
    letter-spacing: -0.015em;
    list-style: none;
    transition: color 140ms var(--ease);
}

/* Safari still paints its own triangle without this. */
.faq-list summary::-webkit-details-marker {
    display: none;
}

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

/* A rotating rule beats a chevron glyph here: no icon font, no inline SVG, and it animates
   from plus to minus with one transform. */
.faq-list summary::after {
    content: "";
    flex: none;
    width: 14px;
    height: 14px;
    background:
        linear-gradient(var(--text-muted), var(--text-muted)) center / 14px 1.5px no-repeat,
        linear-gradient(var(--text-muted), var(--text-muted)) center / 1.5px 14px no-repeat;
    transition: transform 220ms var(--ease);
}

.faq-list details[open] summary::after {
    transform: rotate(135deg);
}

.faq-list details p {
    max-width: 60ch;
    padding-bottom: var(--space-5);
    color: var(--text-secondary);
    line-height: 1.65;
}

/* ---------------------------------------------------------------- legal */

.legal-page {
    padding-block: var(--space-8) var(--space-9);
}

.legal-content > * {
    max-width: 68ch;
}

/* ------------------------------------------------------------------ about */

.about-content > * {
    max-width: 68ch;
}

/* The headings need their own rhythm: this page reuses .legal-page for its frame but not
   .legal-content, so it inherits none of that block's heading spacing. */
.about-content h1 {
    margin-bottom: var(--space-4);
    font-size: var(--text-section);
}

.about-content h2 {
    margin-top: var(--space-7);
    margin-bottom: var(--space-4);
    font-size: 1.25rem;
}

.about-content .lede {
    margin-bottom: var(--space-5);
    font-size: var(--text-lede);
}

.about-content p {
    margin-bottom: var(--space-4);
    color: var(--text-secondary);
}

/* Photo beside the name, not above it: at this size the face is a credential rather than a
   portrait, and it reads faster next to what it identifies. */
.founder {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-5);
    margin: var(--space-5) 0 var(--space-6);
    padding: var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
}

.founder__photo {
    flex: none;
}

.founder__photo img {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    border: 1px solid var(--line-strong);
    object-fit: cover;
}

.founder__body {
    min-width: 0;
}

.about-content .founder__name {
    margin-bottom: 2px;
    color: var(--text-primary);
    font-family: var(--font-display);
    font-size: 1.125rem;
    font-weight: 700;
    letter-spacing: -0.02em;
}

.about-content .founder__meta {
    margin-bottom: var(--space-3);
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
}

.about-content .founder__links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    margin-bottom: 0;
}

.founder__links a {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.about-actions {
    margin-top: var(--space-5);
}

/* The identity block. A definition list because that is what it is — a label and the fact
   it names — and rows only appear when configured, so the shape has to hold at any length. */
.legal-identity {
    display: grid;
    gap: var(--space-3);
    margin: var(--space-5) 0 var(--space-6);
    padding: var(--space-5);
    border: 1px solid var(--line);
    border-radius: var(--radius-card);
    background: var(--surface);
}

.legal-identity > div {
    display: grid;
    grid-template-columns: minmax(0, 12rem) minmax(0, 1fr);
    gap: var(--space-3);
}

.legal-identity dt {
    color: var(--text-muted);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
    letter-spacing: -0.01em;
}

.legal-identity dd {
    margin: 0;
    color: var(--text-primary);
}

.legal-identity a {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

.footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
}

.legal-content h1 {
    margin-bottom: var(--space-3);
    font-size: var(--text-section);
}

.legal-updated {
    margin-bottom: var(--space-6);
    color: var(--text-muted);
    font-size: 0.9375rem;
}

.legal-content h2 {
    margin-top: var(--space-7);
    margin-bottom: var(--space-3);
    font-size: 1.125rem;
}

.legal-content p {
    margin-bottom: var(--space-4);
    color: var(--text-secondary);
}

.site-footer {
    padding-block: var(--space-6);
    border-top: 1px solid var(--line);
}

.footer-inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    color: var(--text-secondary);
    font-size: 0.9375rem;
}

.footer-links a:hover {
    color: var(--accent);
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

/* --------------------------------------------------------------- motion
   Justification (storytelling): the journey is chronological, so steps
   arriving in reading order reinforce the sequence. Nothing else animates. */

/* Scoped to .js so that content is never hidden when scripts do not run.
   The class is set by an inline snippet in the document head. */
.js [data-reveal] {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 600ms var(--ease), transform 600ms var(--ease);
}

.js [data-reveal].is-visible {
    opacity: 1;
    transform: none;
}

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

    .js [data-reveal] {
        opacity: 1;
        transform: none;
        transition: none;
    }

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

/* ----------------------------------------------------------- responsive */

@media (max-width: 1024px) {
    .hero-grid,
    .step-split,
    .step-band-inner,
    .step-close,
    .faq-grid {
        grid-template-columns: 1fr;
        gap: var(--space-6);
    }

    /* The board is a wide object; below this it would be squeezed rather than read. */
    .hero-board {
        max-width: 34rem;
    }

    .capability-grid {
        grid-template-columns: repeat(3, 1fr);
        gap: var(--space-3);
    }

    /* Stacked here too. Everything else at this width is already one column, and two cells
       side by side get about 380px each — at which the dialog shot (nearly square) towers
       over the board shot (half as tall), and margin-top:auto answers that by leaving a
       third of the short cell empty above its frame. */
    .step-pair {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 720px) {
    .shell {
        width: min(100% - 32px, 1160px);
    }

    .section,
    .faq-section {
        padding-block: var(--space-8);
    }

    .nav-links,
    .nav-actions .button-nav {
        display: none;
    }

    .nav-disclosure {
        display: block;
    }

    .nav-inner {
        gap: var(--space-3);
    }

    .nav-links {
        margin-inline-start: 0;
    }

    .hero {
        padding-block: var(--space-7) var(--space-8);
    }

    .hero-actions .button {
        flex: 1 1 auto;
    }

    .capability-grid {
        grid-template-columns: repeat(2, 1fr);
        text-align: left;
    }

    .step-pair,
    .pilot-terms,
    .intent-options,
    .field-row {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Three overlapping phones at phone width is three unreadable slivers. The lead screen
       carries the point on its own. */
    .phone-trio__item--back {
        display: none;
    }

    .step-visual-phone {
        justify-self: center;
    }

    /* All three states have to fit the viewport: the rail scrolls as a safety net, but a
       reader who never scrolls it sideways would simply never see the last state. */
    .status-rail li {
        gap: var(--space-2);
        font-size: 0.625rem;
        letter-spacing: 0.03em;
    }

    .status-rail li:not(:last-child)::after {
        width: clamp(10px, 3vw, 20px);
    }

    .phone-trio__item--front {
        flex: 0 1 240px;
    }

    /* The cap belongs here, not at 1024. Between 721 and 1024 all three phones still render,
       so capping the container at 260px crushed 560px of phones into it and they stacked
       almost on top of each other. Below 720 only the lead screen shows, and 260px is its
       size. */
    .step-visual-phone {
        max-width: 260px;
        justify-self: start;
    }

    .lead-form-single {
        padding: var(--space-5);
    }

    .footer-inner {
        align-items: flex-start;
        flex-direction: column;
    }
}
