/**
 * Single Work layout — hero cover + title reveal + parallax.
 *
 * Matches react-src/components/works/single WorkCover / WorkTitle /
 * WorkSummary. Colors follow the ACF `color` field through the
 * `--work-color` custom property set inline on the article.
 */

.work {
    --work-color: #ffffff;
}

/* ---------- Hero cover ----------
 * Iso react-src/components/works/single (WorkCoverContainer):
 * `position: relative; height: 100vh` (in flow) with a JS-driven
 * `transform: translate3d(0, scrollY × 0.7, 0)` on the cover ITSELF
 * (not just the inner media). Net visual movement = scrollY × −0.3,
 * so the whole hero — video + title + metadata — scrolls up at 30%
 * of the page rate. The white opaque .work-content below is a sibling
 * later in the DOM, so it paints on top once they overlap, masking
 * the hero progressively from below — that's the "passe sous la page".
 *
 * `width: 100vw + margin-left: calc(50% - 50vw)` breaks out of the
 * body's --page-gutter padding for full-bleed.
 */
.work-cover {
    position: relative;
    width: 100vw;
    margin-left: calc(50% - 50vw);
    height: 100vh;
    overflow: hidden;
    background-color: #000;
    color: var(--work-color);
}

/* Parallax — native scroll-driven CSS animation. The cover translates
 * 70vh down while the page scrolls from 0 to 100vh, so combined with
 * the natural -scrollY flow it visibly travels at 30% of the page rate.
 * Entirely off main thread, GPU-composited by the browser — no JS scroll
 * listener, no rAF, no style writes per frame. Fixes the mobile stutter
 * we used to get from the JS-driven approach.
 *
 * Uses `scroll(root block)` (not `view()`) because the hero starts at the
 * top of the document — explicit `animation-range: 0 100vh` matches the
 * old JS formula `scrollY × 0.7` exactly, with no ambiguity about which
 * phase the timeline is currently in.
 *
 * Browsers without `animation-timeline` (Safari iOS < 18, Firefox without
 * flag) just see the hero scroll at 1× with the page — better than a
 * half-working JS shim on those engines. */
@supports (animation-timeline: scroll()) {
    .work-cover {
        animation: work-cover-parallax linear both;
        animation-timeline: scroll(root block);
        animation-range: 0 100vh;
        will-change: transform;
    }

    @media (prefers-reduced-motion: reduce) {
        .work-cover {
            animation: none;
            will-change: auto;
        }
    }
}

@keyframes work-cover-parallax {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(0, 70vh, 0); }
}

.work-cover__media {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
}

.work-cover__video,
.work-cover__image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ---------- Summary overlay (title + metadata) ----------
 * Iso react-src (components/works/WorkSummary). Numbers come straight
 * from common/units.js — sm.margin = 6.03, md.horizontalMargin = 3.02,
 * md.verticalMargin = 1.84 (all vw). Anything that looks like a
 * weird literal (9.648, 1.206, 0.368, …) is `multiplier * unit`.
 */

.work-cover__summary {
    position: absolute;
    inset: 0;
    pointer-events: none;
    color: var(--work-color);
    font-size: 5vw;
}

/* ---------- Title (= WorkSummaryLeft + WorkTitleContainer) ---------- */

.work-title {
    /* WorkSummaryLeft mobile: bottom 9.648vw, padding 0 6.03vw, full width.
     * The 9.648vw is relative to WorkSummaryWrapper's content box, which
     * has padding-bottom: 12.06vw on mobile (= 2 × sm.margin). We don't
     * have that wrapper, so we collapse both offsets into a single
     * `bottom` value here: 9.648 + 12.06 = 21.708vw.
     *
     * Same compensation horizontally: wrapper padding-left/right 6.03vw
     * pushes the containing block inward by 6.03vw on each side, then
     * WorkSummaryLeft adds its own 6.03vw padding. We collapse the outer
     * shift into `left`/`right` here and keep the inner `padding` below. */
    position: absolute;
    bottom: 21.708vw;
    left: 6.03vw;
    right: 6.03vw;
    /* WorkTitleContainer: padding-top ~~(6.03/3) = 2vw + WorkSummaryLeft H padding */
    padding: 2vw 6.03vw 0;
    margin: 0;
    font-family: var(--wp--preset--font-family--sharp-grotesk, "sharp-grotesk", Arial, Helvetica, sans-serif);
    font-weight: 500;
    /* WorkTitleContainer mobile */
    font-size: 10.2vw;
    line-height: 1.2;
    color: inherit;
    /* react-src used `white-space: break-spaces` — preserves multiple spaces
     * but otherwise wraps as normal. word-break is safer for very long words. */
    word-break: break-word;
}

@media (min-width: 769px) {
    .work-title {
        /* WorkSummaryLeft desktop: top 60%, width 55%; bottom 9.648vw stays
         * (WorkSummaryLeft never unsets it).
         *
         * react-src nests WorkSummaryLeft inside a WorkSummaryWrapper with
         * `padding: 6.18vw 3.02vw 3.02vw 3.02vw` desktop. That padding
         * shifts the containing block:
         *   left:  shift by 3.02vw (matches WorkSummaryWrapper padding-left)
         *   width: 0.55 × (100vw − 6.04vw) = 55% − 3.32vw
         *   bottom: 9.648vw + 3.02vw padding = 12.668vw absolute from cover bottom
         * Without these, the title sits in the wrong place compared to prod. */
        top: 60%;
        bottom: 12.668vw;
        left: 3.02vw;
        right: auto;
        width: calc(55% - 3.32vw);
        /* WorkTitleContainer desktop */
        font-size: 5.4vw;
        line-height: 1;
    }
}

.work-title__word {
    display: inline-block;
    overflow: hidden;
    vertical-align: bottom;
    /* Room for descenders (g, y, p) so overflow:hidden doesn't crop them
     * when the inner sits at translateY(0). */
    padding-bottom: 0.15em;
}

.work-title__inner {
    display: inline-block;
    transform: translate3d(0, 110%, 0);
    transition: transform 0.6s cubic-bezier(0.26, 1.04, 0.54, 1);
    transition-delay: calc(var(--i, 0) * 150ms + 1400ms);
    will-change: transform;
}

.work-cover.is-revealed .work-title__inner {
    transform: translate3d(0, 0, 0);
}

/* ---------- Metadata (= WorkSummaryRight + WorkSummaryAttribute) ----------
 * react-src renders each attribute as 3 stacked divs:
 *   <Label>-</Label>  <Label>{label}</Label>  <Value>{value}</Value>
 * Labels are uppercase + expanded font + weight 500. Value has NO style
 * (just inherits from the WorkSummaryRight font-size/family/color/line-h).
 * Both label and value are the SAME size — the visual differentiation
 * comes purely from caps + font-stretch. We map our DOM:
 *   <dt class="work-meta__label">  ↔ second AttributeLabel
 *   <dd class="work-meta__value">  ↔ AttributeValue
 *   ::before                       ↔ first AttributeLabel ("-")
 */

.work-meta {
    /* WorkSummaryRight mobile.
     * `top` AND `left` values come from react-src + the WorkSummaryWrapper
     * padding shift:
     *   - Wrapper padding-top mobile = 2 × sm.margin + sm.menuHeight
     *                                = 2 × 6.03 + 7.72 = 19.78vw
     *   - WorkSummaryRight `top: 6.03vw` is relative to the wrapper's
     *     content box, so absolute top = 19.78 + 6.03 = 25.81vw.
     *   - Same logic on `left`: wrapper padding-left 6.03vw shifts the
     *     containing block 6.03vw right, plus react-src's own `left: 55vw`. */
    position: absolute;
    top: 25.81vw;
    left: calc(55vw + 6.03vw);
    margin: 0;
    padding: 0;
    font-family: var(--wp--preset--font-family--sharp-grotesk, "sharp-grotesk", Arial, Helvetica, sans-serif);
    font-size: 3vw;
    line-height: 1.2;
    color: inherit;
    pointer-events: auto;
}

@media (min-width: 769px) {
    .work-meta {
        /* WorkSummaryRight desktop */
        top: 60%;
        left: calc(70vw + 3.02vw);
        font-size: 0.8vw;
        line-height: 1.3;
    }
}

.work-meta__row {
    /* WorkSummaryAttributeContainer: only margin-top; mobile 0.2 * 6.03 */
    margin: 0;
    margin-top: 1.206vw;
    /* Reveal animation (theme-side; react-src used framer-motion variants). */
    opacity: 0;
    transform: translate3d(0, 0.5em, 0);
    transition:
        opacity 0.5s cubic-bezier(.165, .84, .44, 1),
        transform 0.5s cubic-bezier(.165, .84, .44, 1);
    transition-delay: calc(var(--i, 0) * 120ms + 1800ms);
}

@media (min-width: 769px) {
    .work-meta__row {
        /* 0.2 * 1.84 = 0.368 */
        margin-top: 0.368vw;
    }
}

.work-cover.is-revealed .work-meta__row {
    opacity: 1;
    transform: translate3d(0, 0, 0);
}

/* First child of each attribute in react-src: <Label>-</Label> */
.work-meta__row::before {
    content: "-";
    display: block;
    font-family: var(--wp--preset--font-family--sharp-grotesk-expanded, "sharp-grotesk-expanded", Arial, Helvetica, sans-serif);
    text-transform: uppercase;
    font-weight: 500;
}

.work-meta__label {
    margin: 0;
    /* AttributeLabel: expanded + uppercase + weight 500. No size override —
     * inherits from WorkSummaryRight (0.8vw desktop / 3vw mobile). */
    font-family: var(--wp--preset--font-family--sharp-grotesk-expanded, "sharp-grotesk-expanded", Arial, Helvetica, sans-serif);
    text-transform: uppercase;
    font-weight: 500;
}

.work-meta__value {
    /* AttributeValue: empty in react-src, just inherits from parent. */
    margin: 0;
}

/* ---------- Content area below the hero ----------
 * In flow, sibling of .work-cover. Two things matter:
 *   - opaque `background-color: #fff` so when the page scrolls and
 *     this section overlaps the hero (whose parallax keeps it lingering
 *     at the top), the hero is visually masked from below.
 *   - DOM order — being AFTER .work-cover in the article means we
 *     paint over it where they overlap (no z-index needed).
 */

.work-content {
    /* Stays in normal flow inside body's --page-gutter padding, so
     * paragraphs sit at the same horizontal position as content on
     * /about, /works/, the home — body padding is the single source of
     * truth for inline alignment.
     *
     * Full-bleed white background that masks the parallaxing hero is
     * delegated to ::before: it stretches `--page-gutter` past each side
     * to cover the body gutter without the element itself breaking out
     * (which would force us to re-implement body padding here and risk
     * drift, as it did before).
     *
     * `z-index: 0` creates a stacking context so ::before z-index: -1
     * paints below the work content but ABOVE the hero (.work-cover is
     * an earlier sibling, so it sits below this stacking context). */
    position: relative;
    z-index: 0;
    padding-block: calc(2 * var(--page-gutter-vertical));
    padding-inline: 0;
}

.work-content::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: calc(-1 * var(--page-gutter));
    right: calc(-1 * var(--page-gutter));
    background-color: #fff;
    z-index: -1;
}

@media (max-width: 768px) {
    .work-content {
        padding-block: calc(2 * var(--page-gutter));
    }
}

/* ---------- Next / previous navigation ----------
 * Layout/typography come from site-rail.css (.site-rail / --left / --right
 * / __content). This file only adds:
 *   - The arrow SVG sizing + per-direction rotation (composed on top of
 *     the .site-rail__content -90deg so prev points left, next right).
 *   - The hover press.
 *   - Flex+gap inside the link so arrow and text sit side by side
 *     before the rotation.
 * Background and text colors are passed via inline custom properties
 * --site-rail-bg / --site-rail-color, derived per rail from the linked
 * Work's ACF color (see the wp_footer hook in single-works.php).
 */

.work-nav__link {
    /* Smooth in/out alongside hover on the rotated content. */
    transition: background-color 0.4s ease;
}

.work-nav__link a {
    display: inline-flex;
    align-items: center;
    /* react-src SideLinkText: padding-left: 1vw on @md (= text-height) */
    gap: 1em;
    transition: transform 0.7s cubic-bezier(0.26, 1.04, 0.54, 1);
}

.work-nav__link a:hover {
    transform: rotate(-90deg) scale(1.05);
}

.work-nav__arrow {
    /* react-src ArrowContainer: height = font-size on each breakpoint
       (3vw / 1.5vw / 1vw). Using 1em mirrors that 1:1 with text-height. */
    width: 1em;
    height: 1em;
    flex: 0 0 auto;
    fill: currentColor;
    transform-origin: center center;
}

.work-nav__link--prev .work-nav__arrow { transform: rotate(-90deg); }
.work-nav__link--next .work-nav__arrow { transform: rotate(90deg); }

/* ---------- Reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
    .work-cover__media,
    .work-title__inner,
    .work-meta__row,
    .work-nav a {
        transition: none !important;
        transform: none !important;
    }
}
