/* ============================================================
   Layout — container, 12-column grid, section rhythm,
   overlap, asymmetry helpers, reveal animation.
   ============================================================ */

.container {
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

.container--narrow {
    max-width: 52rem;
}

/* ---------- 12-column grid ----------
   Desktop-first spans; responsive.css re-maps columns
   intentionally at each breakpoint (never just shrinks). */

.grid {
    display: grid;
    grid-template-columns: repeat(var(--grid-cols), 1fr);
    gap: var(--grid-gap);
}

.col-1  { grid-column: span 1; }
.col-2  { grid-column: span 2; }
.col-3  { grid-column: span 3; }
.col-4  { grid-column: span 4; }
.col-5  { grid-column: span 5; }
.col-6  { grid-column: span 6; }
.col-7  { grid-column: span 7; }
.col-8  { grid-column: span 8; }
.col-9  { grid-column: span 9; }
.col-10 { grid-column: span 10; }
.col-11 { grid-column: span 11; }
.col-12 { grid-column: span 12; }

/* Intentional asymmetry: content pushed off-centre */
.offset-1 { grid-column-start: 2; }
.offset-2 { grid-column-start: 3; }
.offset-3 { grid-column-start: 4; }

/* ---------- Section rhythm ---------- */

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

.section--tight  { padding-block: var(--space-5); }
.section--roomy  { padding-block: var(--space-7); }

/* Section pulled up over the previous one (panel over hero) */
.section--overlap {
    margin-top: calc(-1 * var(--space-7));
    padding-top: 0;
    position: relative;
    z-index: 2;
}

.section__head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-3);
    flex-wrap: wrap;
    margin-bottom: var(--space-4);
}

.section__heading { max-width: 22ch; }

/* ---------- Stack & cluster helpers ---------- */

.stack > * + *        { margin-top: var(--space-2); }
.stack--loose > * + * { margin-top: var(--space-3); }

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

/* ---------- Reveal on scroll (activated by main.js) ----------

   Elements start displaced and transparent, then settle when the
   observer adds .is-visible. Only opacity and transform animate, so
   the compositor handles every frame and nothing triggers layout.

   Direction is chosen with an attribute value:
     data-reveal            fade up      (default)
     data-reveal="left"     slide in from the left
     data-reveal="right"    slide in from the right
     data-reveal="scale"    settle down from slightly larger
     data-reveal="fade"     opacity only, no movement

   The same values work on data-reveal-group, where children then
   cascade one after another.                                        */

[data-reveal],
[data-reveal-group] > * {
    opacity: 0;
    transform: translate3d(0, var(--reveal-shift), 0) scale(var(--reveal-scale));
    filter: blur(var(--reveal-blur));
    transition:
        opacity var(--duration-reveal) var(--ease-reveal),
        transform var(--duration-reveal) var(--ease-reveal),
        filter var(--duration-reveal) var(--ease-reveal);
}

/* No will-change here, deliberately.

   Setting it on every reveal element promotes dozens of compositor
   layers at first paint — before anything has moved — which costs
   memory and makes scrolling worse on phones, the opposite of the
   intent. Browsers already composite plain opacity and transform
   transitions without the hint. */

/* Directional variants */
[data-reveal="left"],
[data-reveal-group="left"] > * {
    transform: translate3d(calc(var(--reveal-shift) * -1.6), 0, 0) scale(var(--reveal-scale));
}

[data-reveal="right"],
[data-reveal-group="right"] > * {
    transform: translate3d(calc(var(--reveal-shift) * 1.6), 0, 0) scale(var(--reveal-scale));
}

[data-reveal="scale"],
[data-reveal-group="scale"] > * {
    transform: scale(1.04);
}

/* Opacity only — for dense text blocks and legal copy, where blurring
   and sliding body text is distracting rather than refined. */
[data-reveal="fade"],
[data-reveal-group="fade"] > * {
    transform: none;
    filter: none;
}

/* Settled state — one rule covers every variant. */
[data-reveal].is-visible,
[data-reveal-group].is-visible > * {
    opacity: 1;
    transform: translate3d(0, 0, 0) scale(1);
    filter: blur(0);
}

/* Filter removed outright once the animation is done — see reveal()
   in main.js. blur(0) is not the same as none: it still pins a
   compositor layer and creates a containing block. */
[data-reveal].is-clear,
[data-reveal-group].is-clear > * {
    filter: none;
}

/* Cascade children of a group. Generated rather than hand-written so
   long grids (nine design cards) keep flowing instead of arriving at
   once after the fifth item. Capped at 12 — beyond that the last card
   would wait over a second and a half, which reads as broken. */
[data-reveal-group].is-visible > :nth-child(1)  { transition-delay: 0s; }
[data-reveal-group].is-visible > :nth-child(2)  { transition-delay: calc(var(--stagger) * 1); }
[data-reveal-group].is-visible > :nth-child(3)  { transition-delay: calc(var(--stagger) * 2); }
[data-reveal-group].is-visible > :nth-child(4)  { transition-delay: calc(var(--stagger) * 3); }
[data-reveal-group].is-visible > :nth-child(5)  { transition-delay: calc(var(--stagger) * 4); }
[data-reveal-group].is-visible > :nth-child(6)  { transition-delay: calc(var(--stagger) * 5); }
[data-reveal-group].is-visible > :nth-child(7)  { transition-delay: calc(var(--stagger) * 6); }
[data-reveal-group].is-visible > :nth-child(8)  { transition-delay: calc(var(--stagger) * 7); }
[data-reveal-group].is-visible > :nth-child(9)  { transition-delay: calc(var(--stagger) * 8); }
[data-reveal-group].is-visible > :nth-child(10) { transition-delay: calc(var(--stagger) * 9); }
[data-reveal-group].is-visible > :nth-child(11) { transition-delay: calc(var(--stagger) * 10); }
[data-reveal-group].is-visible > :nth-child(n+12) { transition-delay: calc(var(--stagger) * 11); }

/* Slower, longer reveal for hero-scale or full-width blocks. */
[data-reveal-slow] {
    transition-duration: var(--duration-reveal-slow);
}

/* No-JS / no-observer fallback: everything visible, immediately. */
.no-observer [data-reveal],
.no-observer [data-reveal-group] > * {
    opacity: 1;
    transform: none;
    filter: none;
}
