/* ==========================================================================
   Homepage only.

   The hero, the 3D stage that fills it, the carousel controls and the dissolve
   into the first band. None of it exists on any other page, and it was a third
   of the shared stylesheet — which every text page was paying for and none of
   them used. Loaded from index.html after site.css.
   ========================================================================== */

/* The hero ends on the stage ground and the first band starts on the cloth, so
   the junction was a hard step from near-black to cream. This carries the
   hero's ground down INTO the band and dissolves it, rather than trying to fade
   the hero itself — the hero clips its own overflow, so it cannot reach across
   the boundary.

   It is a background LAYER, not a pseudo-element: background-image paints over
   background-color and under the in-flow content, so there is no stacking
   order to get wrong (a negative z-index child would paint behind the band's
   own background, which is the trap this project has already hit once).

   The stops approximate a smoothstep. A straight linear ramp is continuous in
   value but not in slope, and the kink where it reaches zero reads as a faint
   band edge. */
.band--seam {
    /* The fade has to finish before the copy starts, or the section heading
       ends up on a half-dark ground and loses its contrast. Content is pushed
       to 95% of the seam, where the overlay is down to about 2% and the ground
       is cream again. On desktop the band's own rhythm already clears it, so
       this only adds room on phones. */
    --seam: clamp(200px, 30vh, 340px);
    padding-top: max(var(--band-pad), calc(var(--seam) * 0.95));
    background-image: linear-gradient(to bottom,
        rgba(11, 7, 4, 1)    0%,
        rgba(11, 7, 4, 0.97) 8%,
        rgba(11, 7, 4, 0.90) 18%,
        rgba(11, 7, 4, 0.78) 29%,
        rgba(11, 7, 4, 0.62) 41%,
        rgba(11, 7, 4, 0.44) 54%,
        rgba(11, 7, 4, 0.28) 67%,
        rgba(11, 7, 4, 0.15) 79%,
        rgba(11, 7, 4, 0.06) 89%,
        rgba(11, 7, 4, 0.01) 96%,
        rgba(11, 7, 4, 0)    100%);
    background-repeat: no-repeat;
    background-size: 100% var(--seam);
}

/* ============================== HERO ============================== */
/* The hero IS the set. The stage canvas fills it; the type stands inside the
   same space, so the page reads dark exactly once — here. */
.hero {
    position: relative;
    min-height: 100svh;
    display: grid;
    grid-template-rows: 1fr auto;
    align-content: center;
    gap: var(--s6);
    padding: calc(64px + var(--s7)) var(--gutter) var(--s7);
    background-color: var(--stage-ground);
    color: var(--cream-20);
    overflow: hidden;
}

.hero__stage {
    position: absolute;
    inset: 0;
    z-index: 0;
}

/* Scrim. The type stands in the set, so its legibility cannot depend on what
   the set happens to be doing behind it. Weighted to the side the copy sits
   on, and fading to nothing over the figure. */
.hero::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    /* No scrim on mobile: nothing sits over the figure there, so nothing
       needs shading — and a fade across the models' faces is exactly what we
       do not want. */
    background: none;
}

@media (min-width: 900px) {
    /* Desktop keeps a scrim because the type does overlay the set there. It is
       fully clear by 62%, well left of the figure at ~72%. */
    .hero::before {
        background: linear-gradient(96deg,
            rgba(11, 7, 4, 0.94) 0%,
            rgba(11, 7, 4, 0.84) 24%,
            rgba(11, 7, 4, 0.38) 44%,
            rgba(11, 7, 4, 0.00) 62%);
    }
}
/* The canvas ELEMENT is what read as a pasted-on box: a hard rectangle, and no
   amount of fog or vignetting inside it can help, because both stop at the same
   four edges. So the element itself is feathered — the canvas fades to fully
   transparent at its edges and the page shows through. Since the page behind it
   is the same colour the fog and the clear buffer resolve to, there is nothing
   to see a boundary against.

   This replaced a radial vignette that was trying to do the same job from
   inside. Two edge treatments fought each other and made the lamps impossible
   to tune, so there is now exactly one.

   12% on all four edges, and the portrait framing was opened up to suit rather
   than the feather trimmed to fit: the figure's feet used to sit at 95% of the
   band, well inside the bottom fade, so the mask was rubbing them out. The
   figure now spans roughly 17%-87% of the band and the lamps sit well inside
   the side fades. */
.hero__stage canvas {
    display: block;
    width: 100%;
    height: 100%;
    opacity: 0;
    transition: opacity 1200ms var(--ease);
    -webkit-mask-image:
        linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%),
        linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
    mask-image:
        linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%),
        linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
    -webkit-mask-repeat: no-repeat;
    mask-repeat: no-repeat;
    -webkit-mask-size: 100% 100%;
    mask-size: 100% 100%;
    /* Both axes must apply, so the two masks intersect rather than stack.
       WebKit spells this `source-in`; the standard property is `intersect`. */
    -webkit-mask-composite: source-in;
    mask-composite: intersect;
}
.hero__stage.is-ready canvas { opacity: 1; }

.hero__copy {
    position: relative;
    z-index: 2;
    /* No align-self here. It used to read `center`, which meant VERTICAL
       centring while the hero grid was this element's parent. Once .hero__col
       became a column-direction flexbox on desktop, the same property switched
       to the horizontal axis and quietly indented the copy 69px inside its own
       column, out of line with the buttons below it. Vertical centring is the
       column's job now (justify-content), so this is left to the default. */
    max-width: 38rem;
}

.hero__mark {
    font-family: var(--font-display);
    font-weight: 400;
    font-size: min(
        clamp(1.75rem, 4.6vw, 3.5rem),
        calc((100vw - 2 * var(--gutter) - 28px) / 13.2)
    );
    line-height: 1.05;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--cream-00);
    white-space: nowrap;
    display: inline-block;
}

/* Sized by script to match the title's measure exactly, on one line. */
.hero__sub {
    display: inline-block;
    white-space: nowrap;
    font-size: 0.6875rem;
    line-height: 1.6;
    color: var(--brown-20);
    margin-top: var(--s3);
}

.hero__title {
    font-family: var(--font-display);
    font-weight: 400;
    /* Guarded so the longest line can never out-run the gutters. */
    font-size: min(
        clamp(2.25rem, 6.5vw, 4.5rem),
        calc((100vw - 2 * var(--gutter) - 28px) / 6.6)
    );
    line-height: 1.04;
    letter-spacing: 0.02em;
    color: var(--cream-00);
    margin-top: var(--s5);
}
.hero__title span { display: block; }

.hero__lead {
    margin-top: var(--s6);
    font-size: clamp(1.0625rem, 1.6vw, 1.1875rem);
    line-height: 1.7;
    color: var(--cream-20);
    max-width: 50ch;
}

/* On mobile this dissolves so copy, stage and actions are all direct children
   of the hero grid; on desktop it becomes the centred type column. */
.hero__col { display: contents; }

.hero__actions {
    position: relative;
    z-index: 2;
    margin-top: var(--s6);
    display: flex;
    /* Never stack. The pair is a single row at every width — below they share
       the row and the type steps down instead of wrapping. */
    flex-wrap: nowrap;
    gap: var(--s4);
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Touch target floor, independent of the type size. */
    min-height: 44px;
    white-space: nowrap;
    font-size: 0.75rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    text-decoration: none;
    padding: var(--s3) var(--s5);
    border: 1px solid var(--brown-50);
    color: var(--cream-00);
    transition: border-color var(--t-micro) var(--ease),
                background-color var(--t-micro) var(--ease),
                color var(--t-micro) var(--ease);
}
.btn:hover { border-color: var(--orange-40); color: var(--orange-40); }

.btn--solid {
    background-color: var(--cream-00);
    border-color: var(--cream-00);
    color: var(--brown-90);
}
.btn--solid:hover {
    background-color: var(--orange-40);
    border-color: var(--orange-40);
    color: var(--brown-90);
}

/* --------------------------- carousel controls --------------------------- */
.hero__controls {
    position: relative;
    z-index: 2;
    display: flex;
    align-items: center;
    gap: var(--s4);
    flex-wrap: wrap;
}

.ctrl {
    width: 40px;
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: 1px solid var(--brown-50);
    color: var(--cream-20);
    cursor: pointer;
    transition: border-color var(--t-micro) var(--ease),
                color var(--t-micro) var(--ease);
}
.ctrl svg {
    width: 16px; height: 16px;
    fill: none; stroke: currentColor; stroke-width: 1.5;
    stroke-linecap: round; stroke-linejoin: round;
}
.ctrl:hover { border-color: var(--orange-40); color: var(--orange-40); }

.dots { display: flex; gap: var(--s3); }
.dots li {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background-color: rgba(18, 12, 7, 0.35);
    /* They sit over the lit platform, so they carry their own contrast. */
    border: 1px solid var(--brown-20);
    cursor: pointer;
    transition: background-color var(--t-micro) var(--ease),
                border-color var(--t-micro) var(--ease);
}
.dots li:hover { border-color: var(--cream-20); }
.dots li[data-active="true"] {
    background-color: var(--orange-40);
    border-color: var(--orange-40);
}

.hero__look {
    font-family: var(--font-display);
    font-size: 0.9375rem;
    letter-spacing: 0.04em;
    color: var(--cream-20);
    /* It sits over the lit platform, so it carries its own contrast. */
    text-shadow: 0 1px 8px rgba(18, 12, 7, 0.95);
    margin-left: auto;
}

@media (min-width: 900px) {
    .hero {
        /* The staging has moved right, so the type column takes the space it
           gave up. */
        grid-template-columns: 1.18fr 0.82fr;
        grid-template-rows: 1fr auto;
        padding-top: calc(72px + var(--s7));
    }
    /* Type and buttons centre as ONE block spanning the full hero height.
       Previously the copy was pinned to the end of row 1 and the buttons to the
       start of row 2, which parked the whole group on the row boundary — low in
       the frame.

       `justify-content: center` centres within the CONTENT box, and the hero's
       top padding is 72px greater than its bottom (nav clearance), so the block
       would land 36px low. The correction is the FULL 72px difference, not half
       of it: a negative top margin also makes the box 72px taller, so its
       centre only travels half the distance. */
    .hero__col {
        display: flex;
        flex-direction: column;
        justify-content: center;
        grid-column: 1;
        grid-row: 1 / 3;
        margin-top: -72px;
    }
    .hero__controls { grid-column: 2; grid-row: 2; justify-content: flex-start; }
}

@media (max-width: 899px) {
    /* Portrait is a stacked composition with the stage as a real row, not an
       overlay: copy above, figure in the middle, CTAs and controls below. That
       is what guarantees nothing ever sits over the model. */
    .hero {
        /* minmax(0, 1fr), not the implicit `auto`. An auto column sizes to its
           MAX-CONTENT, and the subtitle is a nowrap line at a script-set size —
           at 320 that made the column 329px inside a 272px hero, so every item
           in it, buttons included, overflowed and was cut off by the hero's
           own overflow:hidden. Capping the column at the container width is
           what lets the buttons shrink to fit. */
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: auto minmax(198px, 1fr) auto auto;
        align-content: stretch;
        gap: var(--s3);
        padding-bottom: var(--s4);
    }
    .hero__stage {
        /* A real grid row, not an overlay. The canvas inside is absolute so it
           fills the row rather than dictating its height — with height:100% on
           an auto-sized row the two size each other in a circle and the row
           ends up taller than the viewport. */
        position: relative;
        inset: auto;
        grid-row: 2;
        height: auto;
        min-height: 0;
        /* Full bleed. A rectangle with the page's gutters down either side
           reads as a panel dropped onto the page; one that runs off both edges
           reads as space the page happens to be showing part of. The hero
           clips its own overflow, so the negative margins cost no scrollbar. */
        width: calc(100% + 2 * var(--gutter));
        margin-inline: calc(-1 * var(--gutter));
    }
    .hero__stage canvas {
        position: absolute;
        inset: 0;
    }
    .hero__copy     { grid-row: 1; align-self: start; }

    /* The two buttons share the row equally rather than wrapping, so they stay
       side by side however narrow the phone is. min-width:0 overrides the
       min-width:auto every flex item carries, which would otherwise pin each
       button at its label's full width and push the pair off-screen. */
    .hero__actions  { grid-row: 3; justify-content: center; margin-top: var(--s4); gap: var(--s3); }
    .hero__actions .btn { flex: 1 1 0; min-width: 0; padding-inline: var(--s3); }

    .hero__controls { grid-row: 4; justify-content: center; }

    .hero__title  { margin-top: var(--s4); }
    .hero__lead   { margin-top: var(--s4); font-size: 1rem; line-height: 1.6; max-width: 38ch; }
    .hero__look { margin-left: 0; width: 100%; text-align: center; }
}

/* Phones only: no navigation bar. The page is four linear sections, so nothing
   is stranded, and the hero reclaims the room it was reserving to clear it.
   Tablets in portrait (640-899px) keep the bar. */
/* 639.98 not 639: at exactly 639px Chrome evaluates this boundary as false
   (sub-pixel viewport width), which left the bar showing on the last phone
   size. The fractional bound closes that gap. */
@media (max-width: 639.98px) {
    /* The nav is hidden site-wide at this width — that rule lives in site.css,
       because every page needs it, not just this one. The hero simply reclaims
       the room the bar was leaving. */
    .hero { padding-top: var(--s8); }
}

/* Below these widths the labels, not the layout, give way — the buttons stay on
   one row and the type steps down to keep both inside the gutters. The 44px
   touch target is set on .btn and is unaffected by any of this. */
@media (max-width: 479px) {
    .hero__actions .btn { font-size: 0.6875rem; letter-spacing: 0.09em; padding-inline: var(--s2); }
}
/* 320-class phones. "Explore Journey" is the longer label; at 11px with this
   tracking it needs 109px of the 132px each button gets at 320, so the pair
   still clears the gutters without going under 11px. */
@media (max-width: 339px) {
    .hero__actions { gap: var(--s2); }
    .hero__actions .btn { letter-spacing: 0.07em; padding-inline: var(--s1); }
}

