/* ============================================================
   hero.css - the parameter-surface hero

   Layout is a single grid cell with three stacked layers:
     canvas  (the surface)
     scrim   (so type stays legible over it)
     content (headline, lede, CTA)

   The canvas is NOT positioned absolutely against the viewport.
   It fills the section, and the section owns its own height, so
   there is nothing to recompute on scroll and no fixed layer to
   fight the iOS address bar.
   ============================================================ */

.hero-3d {
    position: relative;
    isolation: isolate;
    /* dvh, not vh. vh on iOS Safari measures the viewport WITHOUT
       the address bar, so the hero jumps the moment the bar hides. */
    min-height: min(88dvh, 860px);
    display: grid;
    grid-template-rows: 1fr auto;
    overflow: hidden;
    background:
        radial-gradient(120% 90% at 78% 8%, rgba(138, 164, 232, 0.16), transparent 62%),
        radial-gradient(90% 70% at 12% 88%, rgba(111, 141, 216, 0.10), transparent 58%),
        var(--bg-base, #0a0f1e);
}

/* The canvas sits in the upper right and bleeds off the edge. Centring
   it would put the surface directly behind the headline and cost the
   type its contrast. Off to one side, the two occupy the same frame
   without competing. */
#hero-surface {
    position: absolute;
    inset: 0 -6% 0 auto;
    width: min(72%, 980px);
    height: 100%;
    z-index: 0;
    opacity: 0;
    transition: opacity 900ms var(--ease-out, ease);
    pointer-events: none;   /* the hero CTA is what should take clicks */
}
#hero-surface[data-ready="true"] { opacity: 1; }

.hero-3d-scrim {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    /* Left-weighted: dense where the text is, clear where the surface
       is, plus a bottom fade so the section joins the one below it
       instead of ending on a hard edge. */
    background:
        linear-gradient(90deg,
            var(--bg-base, #0a0f1e) 0%,
            rgba(10, 15, 30, 0.92) 26%,
            rgba(10, 15, 30, 0.45) 52%,
            rgba(10, 15, 30, 0.10) 78%),
        linear-gradient(180deg, transparent 62%, var(--bg-base, #0a0f1e) 100%);
}

.hero-3d-inner {
    position: relative;
    z-index: 2;
    align-self: center;
    display: grid;
    justify-items: start;
    gap: clamp(1rem, 2vw, 1.5rem);
    /* Capped so the headline breaks where it is written to break
       rather than running under the surface. */
    max-width: 52rem;
    /* The skill caps hero top padding at ~6rem: more than that and the
       content floats down the viewport and reads as a layout fault. */
    padding-block: clamp(3rem, 7vw, 6rem);
}

/* Wide enough that the authored line break is the one that happens.
   At 15ch the second line wrapped to a third and pushed the CTAs off
   the bottom of the viewport. */
.hero-3d-title { max-width: 24ch; }
.hero-3d-lede { max-width: 46ch; }

.hero-3d-cta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 0.5rem;
}

/* ── Buttons ────────────────────────────────────────────────
   One radius family (pill), one accent. Both labels are two words,
   so neither wraps at desktop. */
.btn-solid, .btn-ghost {
    font-family: var(--font-body);
    font-size: var(--step-0);
    font-weight: 550;
    line-height: 1;
    padding: 0.95em 1.6em;
    border-radius: var(--radius-pill, 999px);
    white-space: nowrap;
    text-decoration: none;
    transition: transform var(--dur-fast) var(--ease-out),
                background var(--dur-fast) var(--ease-out),
                border-color var(--dur-fast) var(--ease-out);
}

.btn-solid {
    background: var(--accent-blue, #8aa4e8);
    /* Near-black on blue, not white. White on #8aa4e8 is 3.1:1 and
       fails AA for body-size text; this is about 8:1. */
    color: #070b16;
    border: 1px solid transparent;
}
.btn-solid:hover { background: #a9bdf0; }

.btn-ghost {
    background: transparent;
    color: var(--text-primary, #eef1f8);
    border: 1px solid var(--border-hover, rgba(138, 164, 232, 0.35));
}
.btn-ghost:hover {
    background: rgba(138, 164, 232, 0.10);
    border-color: var(--accent-blue, #8aa4e8);
}

/* A real push on press, on both. */
.btn-solid:active, .btn-ghost:active { transform: translateY(1px); }
.btn-solid:focus-visible, .btn-ghost:focus-visible {
    outline: 2px solid var(--accent-blue, #8aa4e8);
    outline-offset: 3px;
}

/* ── Legend ─────────────────────────────────────────────────
   Explains the object rather than decorating it. Without this the
   surface is a pretty shape; with it, it is evidence. */
.hero-3d-legend {
    position: relative;
    z-index: 2;
    align-self: end;
    padding-block: 0 clamp(1.5rem, 3vw, 2.5rem);
    font-family: var(--font-body);
    font-size: var(--step--1);
    line-height: 1.6;
    color: var(--text-quiet, #8592b0);
    max-width: 54ch;
}
.hero-3d-legend .num { color: var(--text-muted, #a3adc4); }

/* ── Narrow ─────────────────────────────────────────────────
   Below the two-column point the surface moves behind the type and
   drops in opacity, because at that width there is nowhere for it to
   sit beside the headline. */
@media (max-width: 860px) {
    .hero-3d { min-height: auto; }
    #hero-surface {
        inset: 0;
        width: 100%;
        opacity: 0;
    }
    #hero-surface[data-ready="true"] { opacity: 0.5; }
    .hero-3d-scrim {
        background:
            linear-gradient(180deg,
                rgba(10, 15, 30, 0.86) 0%,
                rgba(10, 15, 30, 0.72) 48%,
                var(--bg-base, #0a0f1e) 100%);
    }
    .hero-3d-inner { padding-block: clamp(3.5rem, 12vw, 5rem); }
    /* The shared display scale bottoms out at ~40px, which put this
       headline on five lines at 390px. A hero headline that runs five
       lines is a font-size fault, not a copy-length one, so the scale
       drops rather than the words. */
    .hero-3d-title {
        max-width: 100%;
        font-size: clamp(1.85rem, 7.6vw, 2.6rem);
    }
}

/* The canvas is presentational. If motion is unwelcome the script
   still paints one frame, but it is dimmed further so a held image
   never competes with the text it sits behind. */
@media (prefers-reduced-motion: reduce) {
    #hero-surface[data-ready="true"] { opacity: 0.55; transition: none; }
}
