/* =============================================================================
   Module: hero  (modules/hero.php)
   -----------------------------------------------------------------------------
   The opening image of a page: a full-width band, the photograph darkened by a
   veil, the claim and the RPU mark centred over it. A Leistungen page opens on
   the same band with the field's letter mark instead of a photograph - see
   .hero--letter near the foot of this file. Everything above it is shared:
   both kinds are the same geometry, the same parallax and the same claim.

   Width. Always the full window, at every size - the band bleeds past every
   container on the site. That is what the explicit `width: 100%` below is for:
   with an aspect ratio and an automatic width, --hero-max-height would clamp
   the WIDTH as well to keep the ratio, and the band would come up short of the
   right-hand edge on a wide monitor. A definite width settles the ratio in one
   direction only, so the cap can shorten the band without ever narrowing it.

   Height. The band is an aspect ratio, not a fixed height - --hero-ratio opens
   up with the viewport so the photograph never turns into a letterbox strip on
   a phone. --hero-max-height keeps it off a full screen on a wide monitor and
   --hero-min-height keeps the claim off the edges on a small one. Both caps win
   over the ratio, which is why it is a starting point rather than a promise.

   Parallax. .hero__media is inset by --hero-parallax at top and bottom, and a
   percentage inset resolves against the section's own height - so the layer
   overhangs the band by exactly the distance it may travel, with nothing to
   measure. assets/js/modules/hero.js then sets --hero-shift within that range
   while the section crosses the viewport. It sets nothing else: without
   JavaScript, or with reduced motion asked for, the shift stays 0 and the
   photograph is simply centred.

   TRAVEL in that script repeats --hero-parallax as a number. Change both
   together, or the layer will move further than it overhangs and show an edge.
   ============================================================================= */

/* --- Geometry ----------------------------------------------------------------
   On :root, not on .hero, because modules/header.php has to know how tall the
   band will be: the action bar rests near its foot on the home page and travels
   up into the header on scroll. --hero-height states in one expression what
   aspect-ratio plus min-height/max-height resolve to further down, so the
   header can read the answer instead of guessing at it.

   --hero-ratio-n repeats --hero-ratio as a plain number, because a division
   needs one. Change both together. 100vw counts the scrollbar and the band
   does not, so on a scrollbar-drawing platform --hero-height is a few pixels
   generous - at that width the band is capped by --hero-max-height anyway.
   -------------------------------------------------------------------------- */
:root {
    --hero-ratio: 4 / 5;
    --hero-ratio-n: 0.8;
    --hero-min-height: 26rem;    /* 416px - room for the claim on a phone      */
    --hero-max-height: 76vh;

    --hero-height: clamp(
        var(--hero-min-height),
        100vw / var(--hero-ratio-n),
        var(--hero-max-height)
    );
}

@media (min-width: 768px) {
    :root {
        --hero-ratio: 16 / 9;
        --hero-ratio-n: 1.7778;
        --hero-max-height: 80vh;
    }
}

@media (min-width: 1024px) {
    :root {
        --hero-ratio: 21 / 10;
        --hero-ratio-n: 2.1;
    }
}

.hero {

    /* How far the photograph may travel, up and down, as a share of the band's
       height. Repeated in assets/js/modules/hero.js. */
    --hero-parallax: 12%;
    --hero-shift: 0px;

    /* --- Claim ------------------------------------------------------------- */

    /* The mark is about twice the height of the text: 36 -> 56px. Not a token -
       no other place on the site sizes a logo against a headline. */
    --hero-logo-height: clamp(2.25rem, 1.6rem + 2.6vw, 3.5rem);

    /* Two layers: a tight white core that keeps the letters legible over a
       light coat, and a wide accent halo that carries the glow. */
    --hero-glow: 0 0 1.25rem rgba(var(--rgb-white), 0.35),
                 0 0 2.75rem rgba(var(--rgb-blue-light), 0.30);
    --hero-glow-strong: 0 0 1rem rgba(var(--rgb-white), 0.55),
                        0 0 3.5rem rgba(var(--rgb-blue-light), 0.55);

    --hero-ease: cubic-bezier(0.22, 1, 0.36, 1);

    position: relative;
    display: flex;
    align-items: center;
    overflow: hidden;
    width: 100%;                 /* never narrowed by the cap - see above */
    aspect-ratio: var(--hero-ratio);
    min-height: var(--hero-min-height);
    max-height: var(--hero-max-height);
    background-color: var(--color-primary);
    color: var(--color-text-inverse);
}

/* Shorter band for the pages below the home page. It overrides the geometry on
   itself, so the :root values - and with them --hero-height, which the header
   reads - keep describing the full band of the home page. */
.hero--slim {
    --hero-ratio: 3 / 2;
    --hero-min-height: 20rem;
    --hero-max-height: 56vh;
}

@media (min-width: 768px) {
    .hero--slim {
        --hero-ratio: 3 / 1;
        --hero-max-height: 52vh;
    }
}

@media (min-width: 1024px) {
    .hero--slim {
        --hero-ratio: 32 / 9;
    }
}

/* --- The photograph ----------------------------------------------------------
   Overhangs the band top and bottom by --hero-parallax, so there is room to
   move without an edge coming into view.
   -------------------------------------------------------------------------- */
.hero__media {
    position: absolute;
    top: calc(var(--hero-parallax) * -1);
    right: 0;
    bottom: calc(var(--hero-parallax) * -1);
    left: 0;
    z-index: 0;
    transform: translate3d(0, var(--hero-shift), 0);
}

/* Only once the script is actually moving it - a permanent will-change on a
   layer that never moves costs memory for nothing. */
.hero.is-parallax .hero__media {
    will-change: transform;
}

.hero__image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

.hero__veil {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 1;
    background-image: linear-gradient(to bottom,
        rgba(var(--rgb-black), 0.30) 0%,
        rgba(var(--rgb-blue), 0.30) 55%,
        rgba(var(--rgb-black), 0.44) 100%);
}

/* --- The claim ------------------------------------------------------------ */

.hero__inner {
    position: relative;
    z-index: 2;
    display: flex;
    justify-content: center;
    padding-block: var(--space-xl);
    text-align: center;
}

/* Sized to its content rather than to the row, so the hover reaches only the
   claim itself and not the whole width of the band. */
.hero__claim {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: clamp(var(--space-sm), 2vw, var(--space-lg));
    margin: 0;
}

.hero__title {
    font-family: var(--font-heading);
    font-size: var(--font-size-h3);
    font-weight: var(--font-weight-bold);
    line-height: var(--line-height-heading);
    letter-spacing: var(--letter-spacing-wide);
    text-transform: uppercase;
    text-shadow: var(--hero-glow);
    transition: text-shadow var(--transition-base);
}

.hero__logo {
    width: auto;
    height: var(--hero-logo-height);
    /* The same glow as the text - drop-shadow, because the mark is an external
       SVG and a box-shadow would trace its box instead of its letters. */
    filter: drop-shadow(0 0 1.25rem rgba(var(--rgb-white), 0.35))
            drop-shadow(0 0 2.75rem rgba(var(--rgb-blue-light), 0.30));
    transition: filter var(--transition-base);
}

.hero__claim:hover .hero__title {
    text-shadow: var(--hero-glow-strong);
}

.hero__claim:hover .hero__logo {
    filter: drop-shadow(0 0 1rem rgba(var(--rgb-white), 0.55))
            drop-shadow(0 0 3.5rem rgba(var(--rgb-blue-light), 0.55));
}

/* --- The letter band ---------------------------------------------------------
   What a Leistungen page opens on: a flat colour with the field's mark drawn
   very large and faint on it, and the claim over the middle of it.

   The mark is the SAME FILE the tiles on the home page use - assets/images/
   icons/rpu_<letter>.svg, a hairline outline in the accent blue. On this band
   it has to be white, and CSS cannot reach into an external SVG to recolour
   it. brightness(0) crushes the outline to black whatever it was, invert(1)
   turns that white; the two together are a recolour to white that needs no
   second file. It works precisely because the mark is one flat colour.

   It sits inside .hero__media, which is what the parallax moves - so the
   letter drifts against the band with no script of its own.
   -------------------------------------------------------------------------- */

.hero--letter {

    /* Height of the mark as a share of the band. Not the width: the marks are
       full-bleed in their own viewBox and differ in width from letter to
       letter, so height is the only measure that keeps A, B and O looking the
       same size. */
    --hero-letter-size: 64%;

    /* Faint enough to stay a watermark and not a second headline. The claim
       runs straight across it. */
    --hero-letter-opacity: 0.22;
}

/* A letter band stops widening where a photograph band carries on: past about
   three to one the mark runs out of height and the band reads as an empty
   stripe with a word on it. Below 768px .hero--slim keeps its taller ratio -
   this only replaces the two wide steps, which is why it is inside a query
   rather than on the block. It comes after them in the file, and that is what
   settles it: the two selectors weigh the same. */
@media (min-width: 768px) {
    .hero--letter {
        --hero-ratio: 3 / 1;
    }
}

/* The tone. A photograph band keeps the primary blue underneath, which is what
   shows before the image has loaded. The light blue is too pale for white text
   (2.4:1), so the claim turns dark blue (4.9:1) and the glow, which exists to
   lift white letters off a dark ground, stays out of it until hover - where a
   white halo reads as light on light instead of as a smudge. The mark stays
   white: it is a watermark, and on this band white is the fainter of the two. */
.hero--accent {
    --hero-glow: none;
    --hero-glow-strong: 0 0 1.5rem rgba(var(--rgb-white), 0.75);
    --hero-letter-opacity: 0.35;

    background-color: var(--color-surface-accent);
    color: var(--color-heading);
}

/* Centred in the media layer, and the media layer is symmetric about the band,
   so this is centred in the band as well - at every point of the parallax. */
.hero--letter .hero__media {
    display: flex;
    align-items: center;
    justify-content: center;
}

.hero__letter {
    display: block;
    width: auto;
    height: var(--hero-letter-size);
    opacity: var(--hero-letter-opacity);
    filter: brightness(0) invert(1);
}

/* --- Arrival -----------------------------------------------------------------
   Three steps, back to front: the mark settles out of a slow scale, then the
   claim rises, then the RPU logo behind it. `both` holds the opening frame, so
   nothing is visible before its own animation starts.

   The mark is given the longest run and the least distance, so it reads as a
   thing coming to rest rather than as a thing arriving - by the time the claim
   is legible the letter is nearly still.
   -------------------------------------------------------------------------- */
@keyframes hero-rise {
    from {
        opacity: 0;
        transform: translate3d(0, 0.75rem, 0);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

@keyframes hero-letter-in {
    from {
        opacity: 0;
        transform: scale(1.14);
    }
    to {
        opacity: var(--hero-letter-opacity);
        transform: none;
    }
}

.hero__title,
.hero__logo {
    animation: hero-rise 900ms var(--hero-ease) both;
}

.hero__title {
    animation-delay: 120ms;
}

.hero__logo {
    animation-delay: 260ms;
}

.hero__letter {
    animation: hero-letter-in 1600ms var(--hero-ease) both;
}

/* The claim opens out of a tighter track as it rises. Two properties on one
   element, so it is one gesture: the words spread into place. letter-spacing
   is not a compositor property, but this is a single line of text that runs
   once on load - it is not worth a second element to keep it off the main
   thread. */
@keyframes hero-track-out {
    from {
        letter-spacing: -0.02em;
    }
    to {
        letter-spacing: var(--letter-spacing-wide);
    }
}

.hero--letter .hero__title {
    animation: hero-rise 900ms var(--hero-ease) 120ms both,
               hero-track-out 1400ms var(--hero-ease) 120ms both;
}

@media (prefers-reduced-motion: reduce) {
    .hero__title,
    .hero--letter .hero__title,
    .hero__logo,
    .hero__letter {
        animation: none;
    }

    /* animation: none drops the `both` that was holding the end frame, so the
       mark falls back to the opacity declared on it - which is the end frame.
       Nothing to restore. */

    /* The script already stands still under reduced motion; this covers a
       shift that was set before the setting changed. */
    .hero__media {
        transform: none;
    }
}
