/*
    The public site's own layer, on top of the shared tokens.

    tokens.css supplies the palette, the surface treatments and the spacing scale, so the site and
    the launcher stay one product. What it does NOT supply is a display type scale: its --font-title
    is 22px because it was written for a desktop panel where the largest thing on screen is a page
    header. A landing page needs a 68px headline, so that scale is defined here rather than pushed
    back into tokens.css where it would be dead weight for three hosts that will never use it.

    Everything else defers. If a colour appears here as a literal, it is a bug.

    One rule worth stating because it decides a dozen small choices: ACCENT MARKS THE PRICE YOU ARE
    ABOUT TO PAY, not every price on screen. A term you are selecting is accent, the same as in the
    launcher's checkout, because it is the same control seen twice. A "from" price in a listing is
    ordinary text - you are browsing, not committing.
*/

/*
    Space Grotesk, self-hosted rather than linked from a CDN so the page owns every request it makes.
    Latin subset only - the site has no other script - and one variable file spans 400 to 700, so a
    weight is an axis position rather than another download.

    Copyright 2020 The Space Grotesk Project Authors, SIL Open Font License 1.1.
    https://github.com/floriankarsten/space-grotesk
*/
@font-face {
    font-family: "Space Grotesk";
    src: url("../fonts/space-grotesk-latin.woff2") format("woff2");
    font-weight: 400 700;
    font-style: normal;
    font-display: swap;
    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+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    --measure: 1200px;
    --nav-height: 76px;

    /*
        Display face, for the wordmark and every heading. Body text stays on the system stack: it is
        what the launcher renders in, and matching it there is worth more than matching the headings.
        The @font-face block below defines Space Grotesk; the rest of the stack is what shows while
        it loads and if it fails.
    */
    --font-display: "Space Grotesk", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;

    --display-1: clamp(2.75rem, 6.5vw, 4.25rem);
    --display-2: clamp(1.5rem, 2.6vw, 1.875rem);
    --lead: clamp(1rem, 1.4vw, 1.125rem);

    --label: 0.6875rem;
    --label-tracking: 0.09em;
}

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

html { scroll-behavior: smooth; }

/*
    Column, so the footer is pushed to the bottom of short pages rather than stopping wherever the
    content ran out. .aurora is fixed and #aurora-sksl is hidden, so neither takes part in the flex
    layout; the three flow children are the nav, main and the footer.
*/
body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--page-background);
    color: var(--text-primary);
    font-family: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, sans-serif;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

main { flex: 1 0 auto; display: flex; flex-direction: column; }

h1, h2, h3 { margin: 0; font-family: var(--font-display); line-height: 1.1; letter-spacing: -0.025em; font-weight: 700; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
img, canvas { display: block; max-width: 100%; }

/*
    FocusOnNavigate hands focus to the page heading so a screen reader lands on it, which the browser
    then rings as though it had been clicked. The tabindex is -1, so nothing here is reachable by Tab
    and no keyboard user loses an indicator.
*/
[tabindex="-1"]:focus { outline: none; }

/* ---------------------------------------------------------------------------------------------
   Background. Fixed so the shader does not scroll with the content, and the gradient underneath is
   the fallback the renderer reveals by hiding the canvas when WebGL is missing or the context is
   lost - the same arrangement the panel uses, for the same reason: a failed background must never
   leave the page on a bare colour.
   --------------------------------------------------------------------------------------------- */

.aurora {
    position: fixed;
    inset: 0;
    z-index: -1;
    background:
        radial-gradient(58% 78% at 6% 42%, #1E6FA84D 0%, transparent 62%),
        radial-gradient(54% 74% at 94% 38%, #7B3FA84D 0%, transparent 62%),
        var(--page-background);
}

.aurora canvas { width: 100%; height: 100%; }

/*
    Backdrop scrim. Not decoration - the panel measured this and the number is theirs: a live Aurora
    frame peaks at rgb(149,208,255), and against that --text-secondary behind a translucent surface
    lands at 3.9:1, under the 4.5 floor. Raising the surface fills until text passes is what turns
    glass into flat dark cards; dimming the backdrop fixes the same number and leaves the shader
    visible and moving, which is also what frosted glass over a light source actually looks like.

    Shaped rather than uniform, which is the correction after two flat attempts both looked wrong.
    The panel damps hard and evenly because it is a dense table with secondary text sitting directly
    on the shader in hundreds of places. This page is the opposite: nearly all of its text lives in
    raised surfaces inside a 1200px measure, and the shader is the only thing on screen carrying any
    colour at all. Dimming it evenly turns the launcher's vivid cyan and magenta into uniform murk -
    which is exactly what happened.

    So the dim follows the content instead. The centre band, where the measure sits, is damped hard;
    the outer edges are left almost untouched, and that is where AuroraTheme puts its curtains
    anyway - its own remarks call the dark centre "where the content sits". The page is reinforcing
    the shader's design rather than fighting it. The vertical pass darkens the foot, where the
    footer's small muted text would otherwise sit on bare shader.
*/
.aurora::after {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;

    /*
        Alpha is baked into the colour stops rather than set with `opacity`. An opacity property
        applies to the whole layer including the flat fill underneath the gradient, so raising it to
        strengthen the vignette silently strengthens the uniform dim as well - which is how the
        first attempt at this ended up darker than the value it was meant to lighten.
    */
    background:
        linear-gradient(180deg, #0A0E1400 62%, #0A0E14B8 100%),
        linear-gradient(90deg, #0A0E1400 0%, #0A0E14BF 20%, #0A0E14BF 80%, #0A0E1400 100%),
        #0A0E1433;
}

/* ---------------------------------------------------------------------------------------------
   Layout
   --------------------------------------------------------------------------------------------- */

.wrap {
    width: 100%;
    max-width: var(--measure);
    margin-inline: auto;
    padding-inline: var(--space-5);
}

.section { padding-block: clamp(1.75rem, 3vw, 2.75rem); }

/* The first thing under the ribbon needs more room above it than two sections need between them. */
main > .section:first-child:not(.section-center) { padding-top: clamp(2.5rem, 4vw, 3.5rem); }

/*
    A page that is one card and nothing else. It takes the whole space between the ribbon and the
    footer and centres in it, rather than hanging from the top with a screen of empty background
    underneath. Column, so the wrap keeps the block-flow width it has everywhere else.

    Both offsets below are margins that centring would otherwise count as content. The card is the
    only thing on the page, so a trailing margin under it is space with nothing after it to separate,
    and the footer's own gap is already covered by main filling the height - left in, the two of them
    put the card off centre by half their sum.
*/
.section-center { flex: 1; display: flex; flex-direction: column; justify-content: center; }
.section-center > .wrap { margin-bottom: 0; }
main:has(> .section-center) + .footer { margin-top: 0; }

.section-head { text-align: center; margin-bottom: clamp(1.25rem, 2.2vw, 1.75rem); }
.section-head h2 { font-size: var(--display-2); }

.section-head p {
    margin-top: var(--space-2);
    color: var(--text-secondary);
    font-size: 0.9375rem;
}

.label {
    font-size: var(--label);
    font-weight: 700;
    letter-spacing: var(--label-tracking);
    text-transform: uppercase;
    color: var(--text-secondary);
}

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

/* ---------------------------------------------------------------------------------------------
   Navigation
   --------------------------------------------------------------------------------------------- */

.nav {
    position: sticky;
    top: 0;
    z-index: 50;
    height: var(--nav-height);
    display: flex;
    align-items: center;
    background: #141B24E0;
    border-bottom: 1px solid var(--divider);
}

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

/*
    The wordmark, and the one place the display face is NOT used. Space Grotesk's wide geometric caps
    already carry their own air, so the tracking a locked-up wordmark needs reads as a gap between
    letters rather than as one mark; the UI face takes 0.16em cleanly at this size.
*/
.brand {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: 0.16em;
}

.brand img { display: block; flex: none; width: 28px; height: 28px; object-fit: contain; }

/*
    Header wordmark hover: a bright vertical band sweeps left-to-right through the letters and the
    text flickers as it passes. The unswept letters sit dim, so the pass reads as the mark being
    revealed rather than just tinted. Footer brand keeps its quiet treatment.

    background-clip: text paints the moving gradient onto the glyphs; -webkit-text-fill-color
    guards the rest state so the gradient only shows through while the animation runs.
*/
.nav .brand span {
    display: inline-block;
    background-image: linear-gradient(90deg,
        currentColor 0 33%,
        var(--accent) 36% 39%,
        color-mix(in srgb, currentColor 28%, transparent) 42%,
        color-mix(in srgb, currentColor 28%, transparent) 100%);
    background-size: 300% 100%;
    background-position: 0% 0;
    background-repeat: no-repeat;
    background-clip: text;
    -webkit-background-clip: text;
    -webkit-text-fill-color: currentColor;
}
.nav .brand:hover span,
.nav .brand:focus-visible span {
    -webkit-text-fill-color: transparent;
    animation:
        brand-scan 900ms cubic-bezier(0.2, 0.7, 0.2, 1) both,
        brand-flicker 900ms steps(1, end) both;
}
@keyframes brand-scan {
    from { background-position: 100% 0; }
    to   { background-position: 0% 0; }
}
@keyframes brand-flicker {
    0%   { opacity: 1; }
    8%   { opacity: 0.35; }
    11%  { opacity: 1; }
    27%  { opacity: 0.7; }
    30%  { opacity: 1; }
    58%  { opacity: 0.3; }
    62%  { opacity: 1; }
    100% { opacity: 1; }
}

.nav-links { display: flex; align-items: center; gap: var(--space-1); margin-inline: auto; }

/*
    Sized to the control scale the buttons beside them use, so the whole ribbon sits on one height
    and every item in it reads as something you can press.
*/
.nav-links a {
    display: flex;
    align-items: center;
    height: var(--control-height-lg);
    padding-inline: var(--space-4);
    border: 1px solid transparent;
    border-radius: var(--pill-radius);
    color: var(--text-secondary);
    font-size: 0.9375rem;
    font-weight: 500;
    white-space: nowrap;
    transition: color .15s, background-color .15s, border-color .15s;
}

.nav-links a:hover { background: var(--row-hover); color: var(--text-primary); }

.nav-links a[aria-current="page"] {
    background: var(--row-hover);
    border-color: var(--tile-stroke);
    color: var(--text-primary);
}

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

/* Signed in, this button carries a username, and an account named after an email address is long. */
.nav-actions .signin { max-width: 12rem; overflow: hidden; }

/* ---------------------------------------------------------------------------------------------
   Buttons. Three weights only - filled for the one action a screen wants, outlined for its
   alternative, quiet for everything else. A fourth would need a reason.
   --------------------------------------------------------------------------------------------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    height: var(--control-height-lg);
    padding-inline: var(--space-5);
    border: 1px solid transparent;
    border-radius: var(--field-radius);
    font: inherit;
    font-size: 0.9375rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color .15s, border-color .15s, color .15s, transform .1s;
}

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

.btn-primary { background: var(--accent); color: var(--primary-button-text); }
.btn-primary:hover { background: var(--accent-muted); }

.btn-outline { border-color: var(--accent); color: var(--accent); }
.btn-outline:hover { background: #5AC8FA1A; }

.btn-quiet { border-color: var(--panel-stroke); color: var(--text-primary); background: var(--ghost-bg); }
.btn-quiet:hover { background: var(--row-hover); }

.btn-lg { height: 52px; padding-inline: var(--space-6); font-size: 1rem; }

/* Full width, for the one action a form has. display:flex overrides .btn's inline-flex. */
.btn-block { display: flex; width: 100%; margin-top: var(--space-5); }

/* A quiet alternative to the primary action - a link, not a second button competing with it. */
.link-action {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    color: var(--accent);
    font-size: 0.9375rem;
    font-weight: 600;
}

.link-action svg { transition: transform .15s; }
.link-action:hover svg { transform: translateX(3px); }

/* ---------------------------------------------------------------------------------------------
   Surfaces
   --------------------------------------------------------------------------------------------- */

/*
    No backdrop-filter anywhere on this site, and the fills below are raised to compensate - both
    copied from the panel rather than re-derived, because it already paid for the answer.

    The background here is ALWAYS animated. Blurring a surface whose backdrop is a full-viewport
    canvas re-snapshots and re-blurs it on every frame, which is the expensive part; the desktop
    hosts have no blur at all and tokens.css says why - "layered alpha rather than a platform blur,
    which is exactly why it ports".

    So opacity is the only thing carrying the glass read, and the values are graded - tile, then
    card, then panel, then nav - so every surface is one material at a different depth rather than
    four unrelated greys. The binding constraint is --text-secondary, not body text: it paints every
    label and rate line and sits far closer to the surface than white does.
*/
.panel {
    background: #141B24A6;
    border: 1px solid var(--panel-stroke);
    border-radius: var(--panel-radius);
    box-shadow: var(--panel-shadow);
}

/* ---------------------------------------------------------------------------------------------
   Hero
   --------------------------------------------------------------------------------------------- */

.hero { padding-block: clamp(2rem, 4.5vw, 3.5rem) clamp(1.25rem, 2.5vw, 2rem); }

.hero-grid {
    display: grid;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.3fr);
    gap: clamp(1.5rem, 3.5vw, 3rem);
    align-items: center;
}

.hero h1 { font-size: var(--display-1); letter-spacing: -0.04em; }

.hero-lead {
    margin-top: var(--space-5);
    max-width: 27rem;
    color: var(--text-secondary);
    font-size: var(--lead);
}

.hero-actions { margin-top: clamp(1.75rem, 3vw, 2.5rem); display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-5); }

.badge {
    display: inline-flex;
    align-items: center;
    height: var(--control-height);
    padding-inline: var(--space-4);
    margin-bottom: var(--space-5);
    background: var(--tile-bg);
    border: 1px solid var(--tile-stroke);
    border-radius: var(--pill-radius);
    color: var(--accent);
    font-size: var(--label);
    font-weight: 700;
    letter-spacing: var(--label-tracking);
    text-transform: uppercase;
}

/*
    The hero image is the product's own window, not an illustration of it - the only honest answer to
    "what am I actually buying", and it stays current for free because tools/ViewPreview and
    tools/Capture-AppWindow.ps1 in ReflexFramework regenerate it from the shipping app.
*/
/*
    The back window sits in flow and sets the height; only the front one is positioned. A fixed
    min-height here instead meant the front window overflowed its container the moment the images got
    bigger, which is what made the whole shot read as texture rather than as a demonstration.
*/
.hero-shot { position: relative; padding-bottom: 24%; }

.shot {
    border-radius: var(--card-radius);
    border: 1px solid var(--panel-stroke);
    overflow: hidden;
    background: #0B1119;
    box-shadow: 0 28px 70px #000000B3;
}

.shot-back { position: relative; width: 72%; }
.shot-front { position: absolute; bottom: 0; right: 0; width: 78%; z-index: 1; }

.shot img { width: 100%; height: auto; }

/*
    A shot with its explanation beside it. The window keeps the width because it is the thing being
    explained; the prose only has to say which screen you are looking at.
*/
.shot-row {
    display: grid;
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
    gap: clamp(1.5rem, 3.5vw, 2.5rem);
    align-items: center;
}

.shot-row h3 { font-size: 1.125rem; }
.shot-row p { margin-top: var(--space-3); color: var(--text-secondary); font-size: 0.9375rem; }

/* ---------------------------------------------------------------------------------------------
   Numbered steps. Hairline-separated rows rather than cards: a step is one line of instruction, and
   a card around each would make eight of them look like eight products. An <ol>, so the order a
   reader cannot see in the layout is still in the markup - the drawn number is decorative. The track
   count comes from auto-fit, so three steps sit on one row and eight reflow instead of filling.

   The number is the only accent on the page outside a price, which is deliberate - it is what makes
   the list read as an ORDER rather than as bullets.
   --------------------------------------------------------------------------------------------- */

.steps {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(21rem, 1fr));
    column-gap: clamp(1.5rem, 4vw, 2.5rem);
}

.step {
    display: flex;
    gap: var(--space-4);
    padding-block: var(--space-4);
    border-top: 1px solid var(--divider);
}

/* Not .mono: that carries user-select:all, which turns a click near a step number into a selection
   of it, and --mono-color, which is the colour for values a reader copies. */
.step-n {
    flex: none;
    width: 1.75rem;
    font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
    font-size: 0.8125rem;
    /* The step text's own line box (0.9375rem x 1.6), so a smaller number still sits on its first
       line rather than riding above it. */
    line-height: 1.5rem;
    color: var(--accent);
}

.step p { font-size: 0.9375rem; line-height: 1.6; }

/* ---------------------------------------------------------------------------------------------
   Products
   --------------------------------------------------------------------------------------------- */

.product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: var(--space-4);
}

/*
    Artwork fills the card and the chrome stays out of its way - the palette is deliberately
    desaturated so the product art is the only saturated thing on any screen.

    --tint is per product and stands in for the banner at api/apps/{id}/image?type=Banner. It is a
    shape to fill, not a style to migrate.
*/
.product {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-4);
    min-height: 9rem;
    padding: var(--space-4);
    border: 1px solid var(--card-stroke);
    border-radius: var(--card-radius);
    overflow: hidden;
    background:
        radial-gradient(85% 140% at 16% 50%, var(--tint) 0%, #10161F00 72%),
        linear-gradient(120deg, #FFFFFF0F, #10161F00 55%),
        #10161FE8;
    transition: border-color .15s, transform .15s, box-shadow .15s;
}

.product:hover {
    border-color: var(--tile-stroke);
    transform: translateY(-2px);
    box-shadow: 0 16px 36px #00000066;
}

/*
    The icon-in-a-rounded-square convention the desktop hosts already use, rather than a bare letter
    floating in the card - a loose glyph reads as a missing asset, and a tile reads as a deliberate
    monogram. Swaps for the real banner without the layout moving.
*/
/* Real banner artwork, when the product has any. Replaces the monogram, not the layout around it. */
.product-art {
    flex: none;
    width: 6rem;
    height: 4.5rem;
    object-fit: cover;
    border-radius: var(--tile-radius);
    border: 1px solid #FFFFFF29;
}

.product-mark {
    flex: none;
    width: 3.5rem;
    height: 3.5rem;
    display: grid;
    place-items: center;
    background: #FFFFFF14;
    border: 1px solid #FFFFFF29;
    border-radius: var(--tile-radius);
    font-family: var(--font-display);
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: #FFFFFFC7;
}

.product-body { display: flex; flex-direction: column; gap: var(--space-05); min-width: 0; }
.product-body h3 { font-size: 1.0625rem; }
.product-from { color: var(--text-secondary); font-size: 0.875rem; }
.product-body .link-action { margin-top: var(--space-2); font-size: 0.875rem; }

/* ---------------------------------------------------------------------------------------------
   Terms. Deliberate parity with the launcher's checkout - the buyer meets this control twice and it
   has to be the same control both times, down to the accent on the price and the check on the right.
   --------------------------------------------------------------------------------------------- */

/*
    11rem, not 15: the tiles also render inside the checkout's narrower left column, where a 15rem
    minimum wrapped three terms onto two rows and broke the row-of-tiles the launcher shows.
*/
.terms { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--space-3); }

a.term { display: block; color: inherit; }

.term {
    position: relative;
    padding: var(--space-5);
    background: #141B248C;
    border: 1px solid var(--card-stroke);
    border-radius: var(--tile-radius);
    transition: border-color .15s, background-color .15s, box-shadow .2s, transform .1s;
}

.term:hover {
    border-color: var(--accent);
    background: #16303FA6;
    box-shadow: 0 0 0 1px var(--accent), 0 0 28px -4px var(--accent);
}

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

.term-name { font-size: 0.9375rem; color: var(--text-secondary); }
.term-price { font-family: var(--font-display); font-size: 2rem; font-weight: 700; letter-spacing: -0.035em; color: var(--accent); line-height: 1.2; }
.term-rate { font-size: 0.8125rem; color: var(--text-secondary); }

/* ---------------------------------------------------------------------------------------------
   Assurances. Not a row of adjectives - every one states a specific, checkable fact about what
   happens to the buyer, in the words the checkout already uses. "Premium quality" is a claim a
   competitor copies in a minute; "nothing renews" is a promise the product keeps.
   --------------------------------------------------------------------------------------------- */

.assurances {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    padding: clamp(1.25rem, 2.5vw, 1.75rem);
}

.assurance {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding-inline: clamp(0.5rem, 2vw, 1.5rem);
}

.assurance + .assurance { border-left: 1px solid var(--divider); }

.assurance .glyph {
    flex: none;
    width: 2.75rem;
    height: 2.75rem;
    display: grid;
    place-items: center;
    border: 1px solid var(--tile-stroke);
    border-radius: 50%;
    color: var(--accent);
}

.assurance p { font-size: 0.9375rem; line-height: 1.45; }

/* ---------------------------------------------------------------------------------------------
   Store
   --------------------------------------------------------------------------------------------- */

.featured { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); overflow: hidden; }

/*
    Fades to #10161F00, not to `transparent`. A gradient stop of `transparent` is rgba(0,0,0,0), so
    the browser interpolates the whole ramp through transparent BLACK - over a panel-sized radial
    that is most of the visible area, and it renders as a near-black smudge rather than a glow. The
    small product cards got away with it because their core fills the card; this one did not.
*/
.featured-art {
    min-height: 20rem;
    display: grid;
    place-items: center;
    background:
        radial-gradient(62% 78% at 44% 74%, var(--tint) 0%, #10161F00 72%),
        radial-gradient(50% 62% at 80% 16%, #FFFFFF29 0%, #10161F00 70%),
        linear-gradient(200deg, #FFFFFF1A, #10161F00 55%),
        #10161F;
}

/*
    The no-artwork state, and it is a REQUIRED state rather than a placeholder: ProductInfo says
    BannerAssetId is "zero when the product has no artwork" and that the store "falls back rather
    than showing a broken image". So this panel has to look composed with nothing in it - a tinted
    void only reads as art-shaped hole. The monogram is the same rounded-square convention the cards
    use, scaled up; a real banner replaces the whole block without the layout moving.
*/
.featured-mark {
    width: 6.5rem;
    height: 6.5rem;
    display: grid;
    place-items: center;
    background: #FFFFFF14;
    border: 1px solid #FFFFFF29;
    border-radius: var(--panel-radius);
    font-family: var(--font-display);
    font-size: 2.75rem;
    font-weight: 700;
    letter-spacing: -0.03em;
    color: #FFFFFFD6;
}

.featured-body {
    padding: clamp(1.5rem, 3vw, 2.5rem);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: flex-start;
    gap: var(--space-3);
}

.featured-body h2 { font-size: var(--display-2); }
.featured-body .btn { margin-top: var(--space-2); }

/* The left-aligned page head. Same distance to the content below as .section-head's centred one. */
.store-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: clamp(1.25rem, 2.2vw, 1.75rem);
}

.store-head p { margin-top: var(--space-2); font-size: 0.9375rem; }

.store-head h2 { font-size: var(--display-2); }
.store-count { color: var(--text-secondary); font-size: 0.875rem; }

/* ---------------------------------------------------------------------------------------------
   Product detail
   --------------------------------------------------------------------------------------------- */

.features { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: grid; gap: var(--space-2); }
.features li { display: flex; align-items: flex-start; gap: var(--space-3); font-size: 0.9375rem; }
.features svg { flex: none; margin-top: 0.15rem; color: var(--accent); }

/* Collapsed by default: the terms are the seller's full legal text, not page copy. */
.terms-disclosure { margin-top: var(--space-6); }
.terms-disclosure summary { cursor: pointer; color: var(--accent); font-size: 0.9375rem; font-weight: 600; }

.terms-disclosure pre {
    margin-top: var(--space-4);
    padding: var(--space-4);
    max-height: 22rem;
    overflow: auto;
    background: var(--field-bg);
    border: 1px solid var(--field-stroke);
    border-radius: var(--field-radius);
    color: var(--text-secondary);
    font-size: 0.8125rem;
    line-height: 1.6;
    white-space: pre-wrap;
}

/* ---------------------------------------------------------------------------------------------
   Checkout. Product left, order right, everything visible at once - the launcher's arrangement,
   because a buyer should never scroll to find what they are about to be charged.
   --------------------------------------------------------------------------------------------- */

.checkout-grid { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: var(--space-4); align-items: start; }

.plan-line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    margin-top: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--divider);
    font-size: 0.9375rem;
}

.order-lines { display: grid; gap: var(--space-2); }
.order-lines > div { display: flex; justify-content: space-between; gap: var(--space-4); font-size: 0.9375rem; }

.order-total {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    margin-block: var(--space-4);
    padding-top: var(--space-4);
    border-top: 1px solid var(--divider);
}

/* The acknowledgement. Never pre-ticked - it is evidence, and a default would make it worthless. */
.consent { display: flex; align-items: flex-start; gap: var(--space-3); margin-block: var(--space-4); font-size: 0.8125rem; line-height: 1.5; }
.consent input { flex: none; margin-top: 0.2rem; width: 1.1rem; height: 1.1rem; accent-color: var(--accent); }

.signin-gate { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--divider); }
.signin-gate p { font-size: 0.875rem; }

.field select {
    width: 100%;
    height: var(--control-height-lg);
    padding-inline: var(--space-3);
    background: var(--field-bg);
    border: 1px solid var(--field-stroke);
    border-radius: var(--field-radius);
    color: var(--text-primary);
    font: inherit;
}

/* ---------------------------------------------------------------------------------------------
   Account and sign-in
   --------------------------------------------------------------------------------------------- */

.auth-wrap { max-width: 27rem; }

.auth-methods { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-4); }

/* The provider mark rides in the button's own gap and never scales with its label. */
.auth-methods .btn svg { flex: none; width: 18px; height: 18px; }

/* Stacked methods space on the flex gap; .btn-block's margin belongs to a form's submit. */
.auth-methods .btn-block { margin-top: 0; }
.auth-divider + .auth-methods { margin-top: 0; }

/* A rule with the alternative written into it, rather than a bare line and a floating label. */
.auth-divider {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-block: var(--space-5);
    color: var(--text-secondary);
    font-size: 0.8125rem;
}

.auth-divider::before,
.auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--divider); }

.method-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.method-list li { display: flex; gap: var(--space-3); font-size: 0.9375rem; text-transform: capitalize; }
.method-list .muted { text-transform: none; }

.auth-panel { padding: clamp(1.5rem, 3vw, 2.25rem); }
.auth-note { margin-top: var(--space-5); text-align: center; font-size: 0.875rem; }

.field { display: block; margin-bottom: var(--space-4); }
.field > span { display: block; margin-bottom: var(--space-2); font-size: 0.875rem; color: var(--text-secondary); }

.field input {
    width: 100%;
    height: var(--control-height-lg);
    padding-inline: var(--space-3);
    background: var(--field-bg);
    border: 1px solid var(--field-stroke);
    border-radius: var(--field-radius);
    color: var(--text-primary);
    font: inherit;
    font-size: 0.9375rem;
}

.field input:focus-visible { outline: none; border-color: var(--accent); }

/* The line that sits between the last field and the form's action. */
.field-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); font-size: 0.875rem; }
.field-row a { color: var(--accent); }
.field-row a:hover { color: var(--accent-muted); }

/* A box and its label as one target. .consent is the taller sibling, for text that wraps. */
.checkbox { display: inline-flex; align-items: center; gap: var(--space-2); color: var(--text-secondary); cursor: pointer; }
.checkbox input { flex: none; width: 1rem; height: 1rem; margin: 0; accent-color: var(--accent); }
.checkbox:hover { color: var(--text-primary); }

/*
    One error line, above the form. A refusal names what to do next and never which half was wrong -
    telling the person in front of the screen that the username exists is a support incident.
*/
.form-error {
    margin-bottom: var(--space-4);
    padding: var(--space-3);
    background: #FF64641F;
    border: 1px solid #FF646459;
    border-radius: var(--field-radius);
    color: var(--danger);
    font-size: 0.875rem;
}

/*
    In the auth card only. Everything else in it is centred, so a message that is not reads as
    misaligned - while the same box on the checkout spans the full measure beside left-aligned order
    lines, where centring one short sentence is what would look wrong.
*/
.auth-panel .form-error,
.auth-panel #auth-status { text-align: center; }

.validation-message { display: block; margin-top: var(--space-2); color: var(--danger); font-size: 0.8125rem; }

.account-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); gap: var(--space-4); }
.account-panel { padding: clamp(1.25rem, 2.5vw, 1.75rem); display: flex; flex-direction: column; gap: var(--space-3); }
.account-panel p { font-size: 0.9375rem; }

/* A hardware id is a support handle: selectable, monospace, never a label. */
.mono { font-family: ui-monospace, "Cascadia Mono", Consolas, monospace; font-size: 0.875rem; color: var(--mono-color); user-select: all; }

.order-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }

.order-list li {
    display: grid;
    grid-template-columns: 1fr auto auto;
    gap: var(--space-4);
    align-items: baseline;
    padding-bottom: var(--space-3);
    border-bottom: 1px solid var(--divider);
    font-size: 0.9375rem;
}

.order-list li:last-child { border-bottom: 0; padding-bottom: 0; }

/* ---------------------------------------------------------------------------------------------
   Footer
   --------------------------------------------------------------------------------------------- */

.footer { border-top: 1px solid var(--divider); margin-top: clamp(2.5rem, 5vw, 4rem); }

.footer .wrap {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4) var(--space-5);
    padding-block: var(--space-6);
}

/* Pushed to the far edge, so the row reads brand-left, links-right rather than trailing off centre. */
.footer-links { display: flex; flex-wrap: wrap; gap: var(--space-5); margin-left: auto; }
.footer a { color: var(--text-secondary); font-size: 0.875rem; }
.footer a:hover { color: var(--text-primary); }
.footer small { color: var(--text-secondary); font-size: 0.875rem; }
.footer .brand { font-size: 0.875rem; color: var(--text-secondary); }
.footer .brand img { width: 24px; height: 24px; }

/*
    Two independent choices, so two controls: the background is a shader, the surface is a token set,
    and neither implies the other. Same split the admin panel and the desktop hosts present.

    Captions use the site's .label rather than the footer's link typography: at link size and colour
    they read as two more footer links. Controls take their fill and stroke from the field tokens,
    which is what makes the picker restyle itself the moment it is used.
*/
.theme-picker { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); }

.theme-choice { display: inline-flex; align-items: center; gap: var(--space-2); }

/*
    appearance:none takes the select out of native rendering, so it is a box this stylesheet controls
    rather than a platform widget dropped into the footer. Removing the native appearance also
    removes the UA dropmarker, so the chevron is drawn here.
*/
.theme-choice select {
    appearance: none;
    -webkit-appearance: none;
    height: var(--control-height-sm);
    padding-inline: var(--space-2) 26px;
    background-color: var(--field-bg);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23AEAEB2' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right var(--space-2) center;
    background-size: 10px 6px;
    border: 1px solid var(--field-stroke);
    border-radius: var(--field-radius);
    color: var(--text-primary);
    font: inherit;
    font-size: 0.875rem;
    line-height: normal;
}

/*
    appearance:none does not reach the OS-drawn popup, so the option surface still needs a colour of
    its own or Glass renders white text on white.

    It must be an OPAQUE one. --panel-bg is deliberately translucent, and the option list is painted
    by the platform outside the page's compositing tree - it has no backdrop to blend with, so a
    translucent colour collapses to whatever flat approximation the platform picks. That grey wash is
    not a colour choice; it is translucency used where translucency does not exist.
*/
.theme-choice select option { background: var(--surface-opaque); color: var(--text-primary); }

/* ---------------------------------------------------------------------------------------------
   Responsive
   --------------------------------------------------------------------------------------------- */

@media (max-width: 980px) {
    .hero-grid, .featured { grid-template-columns: minmax(0, 1fr); }

    /*
        Tightened, never hidden. Display:none here left Pricing and Support reachable only from the
        footer, which is a scroll away and not where anyone looks for navigation - and there is no
        menu button to replace them with.
    */
    .nav-links { gap: 0; }
    .nav-links a { padding-inline: var(--space-2); font-size: 0.875rem; }
    .nav .wrap { gap: var(--space-3); }
    .checkout-grid { grid-template-columns: minmax(0, 1fr); }
    .featured-art { min-height: 13rem; }
    .shot-row { grid-template-columns: minmax(0, 1fr); }
    .hero-shot { min-height: 18rem; }
    .assurance + .assurance { border-left: 0; border-top: 1px solid var(--divider); padding-top: var(--space-4); margin-top: var(--space-4); }
}

/*
    The wordmark drops to the mark alone, and only in the ribbon - the footer has room to wrap. Below
    this the three nav links plus two buttons no longer fit beside the name, and the ribbon is the
    one row on the site where nothing may be hidden: there is no menu button to hide it behind.
*/
@media (max-width: 720px) {
    .nav .brand span { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .btn, .product, .term, .nav-links a, .link-action svg { transition: none; }
    .nav .brand:hover span,
    .nav .brand:focus-visible span {
        animation: none;
        -webkit-text-fill-color: currentColor;
    }
}
