/* Surfspace overrides — the ONLY hand-written CSS in this folder.
   =============================================================================
   surf-ui.css (generated from surf-parse's SURFDOC_CSS) and app.css (vendored
   verbatim from the design reference) are both treated as read-only upstream
   files, so re-vendoring either is a straight copy. Every Surfspace-specific
   delta lives here and is loaded last.

   Two jobs:
     1. Retire the reference's CloudSurf brand sky. app.css:191 paints <body>
        with /assets/clouds-bg.png and app.css:219 tiles /assets/stars-tile.png
        in dark — CloudSurf company-brand textures that are off-brand for the
        Surfspace product page and are not vendored here (they 404'd on the
        first render check).
     2. Re-point the palette at the Surfspace landing tokens. Typography, the
        type scale, nav geometry and the pill CTAs are inherited from the
        reference untouched — those are the parts of the design being reused.
   ========================================================================== */

/* ── 1. Surface: a calm gradient ground, no image tiles ──────────────────── */

html {
    background-color: #eef3fa;
    background-image: none;
}

body {
    background-color: #eef3fa;
    /* Overrides the three-layer cloud stack at app.css:191-206. A pure-CSS
       wash keeps the frosted card treatment reading correctly (the glass
       tokens tint whatever sits behind them) with nothing to fetch. */
    background-image:
        radial-gradient(1200px 620px at 50% -12%, rgba(10, 132, 255, 0.16), transparent 70%),
        linear-gradient(180deg, #f4f8fd 0%, #eef3fa 42%, #e8eef7 100%);
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-size: cover;
}

html[data-theme="dark"] {
    background-color: #000206;
    background-image: none;
}

/* Replaces the star-tile rule at app.css:219 — same intent (a deep field
   behind the glass), zero requests. */
[data-theme="dark"] body {
    background-color: #000206;
    background-image:
        radial-gradient(1100px 560px at 50% -10%, rgba(10, 132, 255, 0.20), transparent 68%),
        linear-gradient(180deg, #04070f 0%, #000206 46%, #000206 100%);
    background-repeat: no-repeat;
    background-attachment: fixed;
    background-size: cover;
}

/* ── 2. Palette: the Surfspace landing accent ────────────────────────────── */

:root {
    /* iOS system blue, matching the live landing tokens
       (surf/frontend/templates/home/_brand_style.html:74). The ::style block
       in content/landing.surf sets the same value on the SurfDoc side; this
       carries it into the shell chrome, which ::style does not reach. */
    --accent: #0a84ff;
    --accent-hover: #0066d6;
    --accent-text: #ffffff;
    --shell-accent: #0a84ff;
}

[data-theme="dark"] {
    --background: #000206;
    --accent: #0a84ff;
    --accent-hover: #4aa3ff;
    --surface: rgba(14, 20, 34, 0.82);
    --surface-hover: rgba(22, 30, 48, 0.9);
    --nav-bg: rgba(4, 8, 18, 0.55);
    --shell-nav-bg: rgba(4, 8, 18, 0.6);
    --glass-bg: rgba(18, 26, 42, 0.5);
}

/* ── 3. Landing measure: the marketing band, not the prose measure ───────── */

/* The reference (cloudsurf-website) pins surf-parse v0.10.0; this folder
   renders with the cached v0.18.0. In 0.18.0 the shell wraps page content in
   `.surfdoc`, whose reading measure is `max-width: 48rem` (surf-ui.css:1467).
   That is right for doc prose and wrong for a landing page: measured at a
   1280px viewport it squeezed the whole body into a 720px column while the
   nav and footer ran the full 1120px band, and it left the cards ~208px wide.
   It also broke the crate's own `.surfdoc-banner + .surfdoc-features` bleed
   rule (surf-ui.css:2432), which sets an explicit `width: 1040px`: inside a
   720px parent the box is over-constrained, so CSS drops the `auto` margins
   to 0 and the grid ran to x=1320 — a real 40px horizontal scroll.

   Fix: give the landing body the same 1120px band the shell already uses for
   the nav (app.css:373) and the footer (surf-ui.css `-footer-inner`), so all
   three columns line up. `:has()` is how a child opts its own wrapper out of
   the prose measure; it degrades to the 0.18.0 default where unsupported. */
.surfdoc:has(> .home) {
    max-width: var(--ws-band-inner, 1120px);
    padding-left: 24px;
    padding-right: 24px;
}

/* Body is a flex column (app.css:230), so <main> is a flex item and inherits
   `min-width: auto` — a floor at its own min-content width. Measured at a
   390px viewport that floor was 394px (see the code-wrap rule below for the
   string that set it), so <main> refused to shrink to the viewport and
   documentElement.scrollWidth read 394 against a clientWidth of 390: a real
   4px horizontal scroll. At 360 the same floor cost 34px. `min-width: 0`
   retires the floor so the band always shrinks to the viewport, whatever a
   future paragraph's longest token turns out to be. */
.surfdoc:has(> .home) {
    min-width: 0;
}

/* Same floor, one level down: grid and flex children default to a min-content
   floor too, so a long token inside a card would push the track wider than
   its column instead of wrapping. */
.home .surfdoc-feature-card,
.home .surfdoc-pg-tile,
.home .surfdoc-pg-tiles-row > * {
    min-width: 0;
}

/* Now that the parent is wide enough, keep every band on one shared column
   and let the auto margins actually resolve. `width: auto` retires the
   explicit 1040px from the bleed rule so the grid can never out-run its
   parent again at any viewport. */
.home .surfdoc-features,
.home .surfdoc-banner + .surfdoc-features {
    width: auto;
    max-width: var(--ws-band-inner, 1120px);
    margin-left: auto;
    margin-right: auto;
    padding-left: 0;
    padding-right: 0;
}

/* The tile grid bleeds to the viewport edge by default, which left the tiles
   16px off the screen edge while every other band sat on the 1120 column.
   Pull it onto the same column. */
.home .surfdoc-product-grid {
    width: auto;
    max-width: var(--ws-band-inner, 1120px);
    margin-left: auto;
    margin-right: auto;
}

/* ── 4. Scroll-reveal: fail visible ──────────────────────────────────────── */

/* surf-ui.css:4437 hides every `.surfdoc-reveal` band at opacity 0 and waits
   for an IntersectionObserver that `to_shell_page()` never emits. Undo the
   bare hide, then re-apply it only when static/js/reveal.js is actually in
   play (the renderer stamps `html.surfdoc-js` inline in <head>) and only when
   motion is welcome. No JS or no observer => full content, never a blank page. */
.surfdoc-reveal {
    opacity: 1;
    transform: none;
}

@media (prefers-reduced-motion: no-preference) {
    html.surfdoc-js .surfdoc-reveal:not(.surfdoc-reveal-in) {
        opacity: 0;
        transform: translateY(16px);
    }
}

/* ── 5. Nav wordmark ─────────────────────────────────────────────────────── */

/* app.css:283 visually-hides the nav wordmark span on every screen size. That
   is correct for the reference, whose nav logo (nav-logo-v4.svg) is a lockup
   with "CloudSurf" already drawn into it. The Surfspace mark is emblem-only,
   so vendoring that rule verbatim left the bar with a shark and no name.
   Put the wordmark back so the bar reads mark + wordmark on the left, which
   is the reference's actual pattern — and the pairing the footer already uses. */
.surfdoc-shell-nav .surfdoc-shell-brand > span {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
    font-family: var(--ws-font-display);
    font-weight: 700;
    font-size: 17px;
    letter-spacing: -0.01em;
    color: var(--text);
}

.surfdoc-shell-nav .surfdoc-shell-brand {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    text-decoration: none;
}

/* The bar's emblem is a hair larger than the footer's; 28px sits level with
   the 17px wordmark's cap height. */
.surfdoc-shell-nav .surfdoc-shell-emblem {
    width: 28px;
    height: 28px;
}

/* ── 5b. Shell nav fit — no wrapped labels, no CTA collision (TASK-274b) ─── */

/* ROOT CAUSE (measured 2026-08-26, headless Chrome over the composed landing
   at 834 / 900 / 1024 / 1280 / 1440, guest AND authed):
   `.surfdoc-shell-nav-link` and `.surfdoc-shell-nav-cta` (the vendored crate
   sheet, `landing-design/assets/surfdoc.css` 4231 / 4245) declare neither
   `white-space` nor `flex-shrink`, and `app.css:326` surfaces the inline
   links from 834px — 190px below the crate's own 1024px cutover. Two defects
   followed, both reproduced before this block existed:

     1. WRAPPED LABELS. At 834 and 900 the bar measured `linkRows = 2` with
        38px links growing to 61px: the longest item broke across two lines
        (the pre-rename label at 113–136px, and "Sign in" / "Sign out" behind
        it). At 1024 and up the same bar measured one row — so the bug lived
        exactly in the 834–1023 band the app sheet opened.

     2. CTA COLLISION. The inline group is ABSOLUTELY centred on the viewport
        (`app.css:344`), so it cannot see the right-hand cluster. The left
        cluster is a 125px brand; the right is a 141px CTA plus a 44px toggle.
        Centring on the viewport therefore parks the links off-centre in the
        FREE space, and at 834 authed the last link ended at x=618 while the
        CTA began at x=607 — a measured 11px overlap that no amount of
        `white-space` alone would have fixed.

   The fix is both halves: pin the labels to one line, and below the 1200px
   band (where `app.css:378` already returns the group to flow) centre the
   links IN FLOW between the brand and the CTA instead of on the viewport, so
   the flex row itself guarantees they cannot collide. Below 834 nothing here
   applies — the inline group is `display: none` and the drawer is the menu. */

@media (min-width: 834px) {
    /* One line per label, always. Without this a narrow free span breaks the
       longest label instead of letting the row own its width. */
    .surfdoc-shell-nav .surfdoc-shell-nav-link,
    .surfdoc-shell-nav .surfdoc-shell-nav-cta {
        white-space: nowrap;
        flex-shrink: 0;
    }

    /* The wordmark and the two end clusters are fixed furniture: they set the
       free span the links centre inside, so they must never absorb pressure
       by shrinking (which is what re-introduces a wrapped label). */
    .surfdoc-shell-nav .surfdoc-shell-brand,
    .surfdoc-shell-nav .surfdoc-shell-nav-links,
    .surfdoc-shell-nav .surfdoc-shell-theme-toggle {
        flex-shrink: 0;
    }

    .surfdoc-shell-nav .surfdoc-shell-brand > span {
        white-space: nowrap;
    }
}

/* 834–1199: the band `app.css` opens but never returns to flow. Centre the
   links between the brand and the CTA — same in-flow model the >=1200 rule
   already uses, so the two bands agree instead of one overlapping. */
@media (min-width: 834px) and (max-width: 1199.98px) {
    .surfdoc-shell-nav .surfdoc-shell-nav-inline {
        position: static;
        transform: none;
        flex: 1 1 auto;
        min-width: 0;
        flex-wrap: nowrap;
        justify-content: center;
        gap: 2px;
        margin-left: var(--ws-space-sm, 16px);
        margin-right: var(--ws-space-sm, 16px);
    }

    /* The spacer's `flex: 1` would fight the group for the same free space
       and push the links back against the CTA. The group IS the spacer now. */
    .surfdoc-shell-nav .surfdoc-shell-nav-spacer {
        display: none;
    }
}

/* 1024–1199 has room for a real gap between items; 834–1023 keeps the 2px
   above, which is what the measured fit at 834 depends on. */
@media (min-width: 1024px) and (max-width: 1199.98px) {
    .surfdoc-shell-nav .surfdoc-shell-nav-inline {
        gap: 4px;
    }
}

/* ── 6. Small fit-and-finish for this page ───────────────────────────────── */

/* surf-ui.css:2289 sizes product tiles for hero-scale product cards
   (`min-height: clamp(400px, 42vw, 640px)` = 538px at a 1280 viewport, and
   the reference fills that with 104px product emblems). The download tiles
   carry one small icon, one line of copy and a button, which left roughly
   300px of dead space under each. Size them to their content so the band
   keeps the page's vertical rhythm. */
.home .surfdoc-pg-tile {
    min-height: 264px;
    padding-top: 40px;
    padding-bottom: 40px;
    /* The crate centers a copy-only tile vertically. Across a row of cards
       whose copy runs to different line counts that reads as misalignment —
       "Android" (one line) sat ~12px below "macOS"/"iPhone" (two). Top-align
       so every icon and title in a row shares a baseline. */
    justify-content: flex-start;
}

/* Reserve two lines of copy so the CTA buttons line up across the row too. */
.home .surfdoc-pg-tile-copy p {
    min-height: 3em;
}

/* Platform marks are image emblems (assets/platform/*.svg — real platform
   glyphs, accent-colored in-file because an <img>-embedded SVG cannot see
   currentColor). Dress them in the same 48px chip the icon: form gets, so a
   grid mixing forms reads as one family. */
.home .surfdoc-pg-tile-emblem {
    width: 48px;
    height: 48px;
    padding: 11px;
    box-sizing: border-box;
    border-radius: 12px;
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    object-fit: contain;
}

/* The hero emblem is a mark, not a photo — cap it so the stacked hero keeps
   the reference's headline-first proportions. */
.home .surfdoc-hero-image img {
    width: 96px;
    height: 96px;
    display: block;
    margin: 0 auto;
}

/* Inline code in body copy (the `your-app.doc.surf` proof strings) reads as a
   quiet chip rather than a red-on-grey default. */
.home code {
    font-family: "Surf Display Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.92em;
    padding: 0.1em 0.4em;
    border-radius: 6px;
    background: color-mix(in srgb, var(--accent) 12%, transparent);
    color: inherit;
    /* The Docs card carries `https://surf.space/docs/m/{slug}` — 32 characters
       with no break opportunity, and that one token set the card's
       min-content width to 352px (the floor the `min-width: 0` rules above
       retire). With the floors gone the card follows its column, and the
       token then ran past it: measured at 360, the chip is 276px wide and
       ended 30px beyond the card's 32px padding box, sitting on the border.
       `break-word` breaks a token only when it cannot fit a line of its own,
       so phones get a wrapped chip and wider viewports keep the string
       whole. (The `your-app.doc.surf` chip breaks at its own hyphen at every
       width; that is the browser default and predates this rule.) */
    overflow-wrap: break-word;
}

/* ── 7. Responsive: the missing middle steps ─────────────────────────────── */

/* The upstream sheets only ever step from "full desktop" straight to one
   column, so every grid on this page had a hole in the tablet range. These
   rules add the intermediate columns. Each is a bounded range, so the
   upstream single-column floors below the range still apply untouched. */

/* FEATURE GRIDS — surf-ui.css:2441 pins `[data-cols=3]` at three columns all
   the way down to the crate's 640px cutover (surf-ui.css:2718). Measured at
   768 that put three cards in a 720px band: 224px each, which broke all
   three card titles onto two lines. Two columns from 641–833 gives 348px
   cards — the same reading width the phone layout uses, and one-line
   titles. */
@media (min-width: 641px) and (max-width: 833.98px) {
    .home .surfdoc-features[data-cols="3"],
    .home .surfdoc-features[data-cols="4"] {
        grid-template-columns: repeat(2, 1fr);
    }

    /* The first band holds three cards, so two columns strand the third
       beside an empty slot. Let it take the row — a feature card is a text
       block, so a wide one still reads as a card, where the hole did not. */
    .home .surfdoc-features[data-cols="3"] > .surfdoc-feature-card:last-child:nth-child(odd) {
        grid-column: 1 / -1;
    }
}

/* DOWNLOAD TILES — surf-ui.css:2419 collapses `.surfdoc-pg-tiles-row` to one
   column below 768. Measured at a 768 viewport that produced 688 x 290 tiles:
   a 48px chip, one title and one line of copy centred in 688px of empty
   width, i.e. exactly the dead band this band must not have. Two columns from
   560–768 gives 232–336px tiles (measured at 560 / 600 / 768), matching the
   phone tile's proportions. */
@media (min-width: 560px) and (max-width: 768px) {
    /* The band is authored as two rows of three, and each row is its own
       grid — so a plain two-column override would strand the third tile of
       each row (measured: two 688px full-bleed tiles among four 336px ones).
       Dissolve the row wrappers and run all six tiles through one grid, which
       lays them out 2 x 3 with no orphan and no dead slot. */
    .home .surfdoc-pg-tiles {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: var(--ws-space-sm, 16px);
    }

    .home .surfdoc-pg-tiles-row[data-cols] {
        display: contents;
    }
}

@font-face {
    font-family: "Surf Display Mono";
    src: url("/static/fonts/SurfDisplayMono-Regular.woff2") format("woff2");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
