/* ==========================================================================
   UniFluent - scroll-driven cinematic hero
   --------------------------------------------------------------------------
   SCROLL MODEL
   The rig is a sticky, full-height layer that keeps its place in the flow; the
   panels are then pulled up over it with a negative top margin. The page
   scrolls normally (nothing is pinned or frozen) but the phone stays on screen
   for the sequence.

     .uf-hero
       .uf-hero__rig      sticky, 100svh, in flow      <- phone + atmosphere
       .uf-hero__panels   margin-top: -100svh          <- runway, overlays rig

   Keeping the rig's height reserved is what makes it release exactly one
   viewport before the hero ends, so the phone scrolls cleanly away instead of
   being sliced in half by the next section.
   ========================================================================== */

.uf-hero {
    --uf-ink: #0a0a0b;
    --uf-indigo: #5557e8;
    --uf-indigo-soft: #8b8dff;
    --uf-violet: #7b3fa8;
    --uf-lime: #c8f45d;
    --uf-paper: #ceced7;

    --uf-text: #f4f4f7;
    --uf-text-dim: rgba(206, 206, 215, 0.66);
    --uf-text-faint: rgba(206, 206, 215, 0.42);
    --uf-hairline: rgba(206, 206, 215, 0.14);

    /* Half the body thickness, tracking the phone width (~10% of it) */
    --uf-half: clamp(13px, 1.1vw, 16px);

    --uf-serif: 'Fraunces', 'Times New Roman', serif;
    --uf-sans: 'Inter', 'Segoe UI', system-ui, -apple-system, sans-serif;
    /* Same face the flow sections below use (--flow-display), so the hero's
       statement type and the rest of the page speak one language. */
    --uf-display: 'Poppins', 'Inter', -apple-system, sans-serif;

    position: relative;
    background: var(--uf-ink);
    color: var(--uf-text);
    font-family: var(--uf-sans);
    overflow-x: clip;
    /* Contain the layer stack so later sections cannot paint into the middle
       of the still-sticky rig */
    isolation: isolate;
}

/* --------------------------------------------------------------------------
   Sticky rig
   -------------------------------------------------------------------------- */

.uf-hero__rig {
    position: sticky;
    top: 0;
    z-index: 2;
    height: 100svh;
    overflow: hidden;
    pointer-events: none;
}

/* Two sticky layers, one scroll geometry. A single rig had to sit under the
   panels (z 3) because it carries the opaque atmosphere - which forced the
   copy to paint on top of the phone, so a headline crossing the device slid
   OVER it like a caption. Splitting the rig lets the copy sit between the
   layers: backdrop (1) < words (3) < device (4), and the phone now occludes
   the words when they meet, the way an object in front of them should.

   The device layer is pulled up a full screen to overlay the atmosphere,
   exactly as the panels then overlay both in turn. Every child is
   pointer-events:none, so the copy's links stay clickable through it. */
.uf-hero__rig--atmos {
    z-index: 1;
}

.uf-hero__rig--device {
    z-index: 4;
    margin-top: -100svh;
}

/* The rig stays flat on purpose: the phone carries its own
   transformPerspective, so the glass cards can sit in front of it by z-index
   instead of being sorted behind it in a shared 3D space. */
.uf-hero__rig-inner {
    position: relative;
    z-index: 2;
    height: 100%;
    max-width: 1440px;
    margin: 0 auto;
    padding: 0 clamp(1.5rem, 4vw, 4.5rem);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
}

/* --------------------------------------------------------------------------
   Atmosphere
   -------------------------------------------------------------------------- */

.uf-hero__atmos {
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background:
        radial-gradient(80% 65% at 72% 30%, #1b1c3d 0%, transparent 58%),
        radial-gradient(70% 60% at 10% 85%, #14122a 0%, transparent 58%),
        linear-gradient(180deg, #050508 0%, #0a0b16 55%, #0e0f1c 100%);
}

.uf-hero__orb {
    position: absolute;
    border-radius: 50%;
    filter: blur(100px);
    will-change: transform;
}

.uf-hero__orb--indigo {
    width: 46vw;
    height: 46vw;
    top: -14%;
    right: -4%;
    background: radial-gradient(circle, rgba(85, 87, 232, 0.5) 0%, rgba(85, 87, 232, 0) 70%);
}

.uf-hero__orb--violet {
    width: 38vw;
    height: 38vw;
    bottom: -18%;
    left: -8%;
    background: radial-gradient(circle, rgba(123, 63, 168, 0.42) 0%, rgba(123, 63, 168, 0) 70%);
}

.uf-hero__orb--lime {
    width: 20vw;
    height: 20vw;
    top: 58%;
    right: 40%;
    background: radial-gradient(circle, rgba(200, 244, 93, 0.14) 0%, rgba(200, 244, 93, 0) 70%);
}

.uf-hero__grid {
    position: absolute;
    inset: -10%;
    background-image:
        linear-gradient(to right, rgba(255, 255, 255, 0.04) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(255, 255, 255, 0.04) 1px, transparent 1px);
    background-size: 92px 92px;
    mask-image: radial-gradient(72% 62% at 55% 45%, #000 0%, transparent 76%);
    -webkit-mask-image: radial-gradient(72% 62% at 55% 45%, #000 0%, transparent 76%);
    will-change: transform;
}

.uf-hero__noise {
    position: absolute;
    inset: 0;
    opacity: 0.045;
    mix-blend-mode: overlay;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}

.uf-hero__vignette {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(95% 80% at 55% 42%, transparent 38%, rgba(3, 3, 8, 0.72) 100%),
        linear-gradient(to bottom, rgba(5, 5, 8, 0.4) 0%, transparent 18%, transparent 76%, rgba(5, 5, 8, 0.8) 100%);
}

/* --------------------------------------------------------------------------
   Panels - the scroll runway, left column
   -------------------------------------------------------------------------- */

/* Pulled up over the rig so panel 1 sits at the top of the hero */
.uf-hero__panels {
    position: relative;
    z-index: 3;
    margin-top: -100svh;

    /* The pace of the whole opening, in one place: how much scroll one beat of
       the device costs. 125svh was the original - 1.25 screens per beat, which
       read as hurried against how much each beat does.

       There is a ceiling on this, and it is lower than it looks. The device is
       the only thing moving during a beat, so the longer a beat is the more the
       page reads as frozen rather than slow: at 1250svh a single pose change
       took 12.5 screens of scrolling, over which the phone crept a fraction of
       the way across and the words did not move at all. That is a stall, not a
       slower animation.

       175svh keeps the deliberate pace - 40% longer per beat than the original,
       about 8 screens for the whole sequence - while every beat still visibly
       progresses as it is scrolled. */
    --uf-runway: 175svh;
}

/* Taller than a screen: the extra runway slows the sequence down, which is
   most of what makes the motion feel deliberate rather than hurried.
   js/hero-scroll.js measures the master scrub off this height, so one beat
   stays exactly one panel of scroll whatever it is set to. */
.uf-hero__panel {
    min-height: var(--uf-runway);
    display: flex;
    align-items: center;
    pointer-events: none;
}

/* Everything in here is scoped to match exactly when js/hero-scroll.js builds
   the scroll rig at all: the script stamps .uf-rig on <html> as it boots, so
   these rules follow the rig itself rather than guessing at it from viewport
   or pointer. Reduced-motion and no-WebGL-touch visitors never get the class
   and keep the static fallback layout, where each panel is its content's own
   height and sticky has nowhere to travel. */
@media (prefers-reduced-motion: no-preference) {
    /* Each headline sticks for the length of its beat.

       Without this the copy simply scrolls through, which puts it on screen
       for one viewport plus its own height and no longer - so with a runway of
       several hundred svh a headline was gone for the last stretch of its own
       beat and the reader scrolled through nothing. Sticking decouples how
       long a headline is readable from how much runway the device needs, which
       is what lets the runway above be tuned for the pace of the device.

       Stretch, not centre: sticky needs room to move inside its containing
       block, so panel-inner has to fill the panel's full height rather than
       collapsing to the height of the copy.

       Two classes deep deliberately. The centre beat sets its own
       align-items further down this file, and at equal specificity that
       would win and leave that one panel unstretched - its copy then has
       nowhere to stick and it alone keeps the blank gap. */
    :root.uf-rig .uf-hero__panels .uf-hero__panel {
        align-items: stretch;
    }

    :root.uf-rig .uf-hero__panel-inner {
        align-items: start;
    }

    :root.uf-rig .uf-hero__copy {
        position: sticky;
        /* Roughly centres a headline block in the viewport. Not exactly, since
           the blocks differ in height, but consistently placed beats read
           better here than each one centring to its own measure. */
        top: 35svh;
    }

    /* The centre beat is the one where the device is directly underneath the
       copy rather than beside it: it sits dead centre, oversized and pushed
       down out of the bottom of the frame, with the words stacked above. So it
       is the only panel where the shared 35svh collides - it put the copy 173px
       into the top of the device. Pinned at the same offset as this panel's own
       resting padding below, which is what the stacked layout was designed
       around, it clears the device's top edge by ~80px. */
    :root.uf-rig .uf-hero__panel--centre .uf-hero__copy {
        top: clamp(5.5rem, 11vh, 8rem);
    }

    /* Panel 1 is the exception, and deliberately does not stick.

       It is the one headline already on screen before any scrolling happens,
       and it opens at exactly the offset sticky would pin it to - so sticking
       it means the reader's first scroll gesture moves nothing at all. The
       device is under way from that same gesture (the master scrub starts on
       the hero's top edge), so the phone was seen spinning and crossing to the
       left over a page that looked frozen. Letting this one scroll away
       normally puts the words and the device in motion together, which is what
       tells the reader the sequence is theirs to drive.

       The others can stick because they arrive mid-scroll: by the time one
       pins, the reader has already watched it travel up the screen. */
    :root.uf-rig .uf-hero__panel:first-of-type .uf-hero__copy {
        position: static;
    }

    /* The opening screen is a corner composition, not a column: it spans the
       full width and starts near the top edge, the way the reference does. */
    :root.uf-rig .uf-hero__panel:first-of-type .uf-hero__panel-inner {
        grid-template-columns: minmax(0, 1fr);
        padding-top: clamp(1.5rem, 4vh, 2.75rem);
    }

    /* The final beat needs no trailing runway - the last pose lands on this
       panel's top edge, so a full runway here would just be a long empty
       scroll before the handoff. One screen is enough to hold the headline
       while that last pose arrives.

       Inside the media query because :last-of-type outranks the plain-class
       min-height:0 that the narrow and reduced-motion fallbacks use, so left
       outside it this reserves empty space on exactly the layouts that have
       no runway at all. */
    :root.uf-rig .uf-hero__panel:last-of-type {
        min-height: 100svh;
    }
}

.uf-hero__outro {
    height: 35svh;
}

.uf-hero__panel-inner {
    width: 100%;
    max-width: 1440px;
    margin: 0 auto;
    padding: 0 clamp(1.5rem, 4vw, 4.5rem);
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}

.uf-hero__copy {
    grid-column: 1;
    max-width: 32rem;
    will-change: transform, opacity;
    pointer-events: auto;
}

/* The copy changes sides to meet the travelling device */
.uf-hero__panel--right .uf-hero__copy {
    grid-column: 2;
    justify-self: end;
}

/* Centre beat: copy stacked above the oversized device */
.uf-hero__panel--centre {
    align-items: flex-start;
}

.uf-hero__panel--centre .uf-hero__panel-inner {
    grid-template-columns: minmax(0, 1fr);
    padding-top: clamp(5.5rem, 11vh, 8rem);
}

.uf-hero__panel--centre .uf-hero__copy {
    grid-column: 1;
    max-width: 40rem;
    margin: 0 auto;
    text-align: center;
}

.uf-hero__panel--centre .uf-hero__actions,
.uf-hero__panel--centre .uf-hero__proof {
    justify-content: center;
}

.uf-hero__panel--centre .uf-hero__sub {
    margin-left: auto;
    margin-right: auto;
}

/* Flowty statement type: one enormous geometric sans in a single near-white,
   no eyebrow tags above it and no italic serif accent inside it - the words
   alone carry the beat. Poppins at 400 reads deliberately light at this
   scale, which is what keeps 6vw of type from shouting. */
.uf-hero__headline {
    margin: 0 0 1.6rem;
    font-family: var(--uf-display);
    font-weight: 400;
    font-size: clamp(2.9rem, 6.6vw, 6.4rem);
    line-height: 1.04;
    letter-spacing: -0.02em;
    color: var(--uf-text);
}

.uf-hero__headline--sm {
    font-size: clamp(2.4rem, 5.5vw, 5.2rem);
}

.uf-hero__line {
    display: block;
}

.uf-hero__sub {
    margin: 0 0 1.8rem;
    max-width: 30rem;
    font-size: clamp(1rem, 1.25vw, 1.2rem);
    line-height: 1.55;
    color: var(--uf-text-dim);
}

.uf-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    margin-bottom: 1.5rem;
}

/* --------------------------------------------------------------------------
   Opening screen composition

   The first viewport is laid out on its corners rather than as a column:
   headline top-left, wordmark top-right, lede + actions bottom-left, the
   philosophy card bottom-right, with the sticky device rig showing through
   the middle. Three grid rows - head, a flexible gap the device occupies,
   foot - so the two edges stay pinned however tall the viewport is.
   -------------------------------------------------------------------------- */

.uf-hero__opening {
    display: grid;
    /* Two rows, two children: the head sizes to its content and the foot
       takes the rest and sits at its bottom edge. The device shows through
       the space between them. */
    grid-template-rows: auto 1fr;
    max-width: none;
    min-height: calc(100svh - 2rem);
    /* The dock floats over the bottom of every screen, so the foot row stops
       above it rather than sliding underneath. */
    padding-bottom: clamp(5rem, 10vh, 7rem);
    /* The composition owns the whole frame, so it must not swallow clicks
       aimed at anything under it; the interactive corners opt back in. */
    pointer-events: none;
}

.uf-hero__opening-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 2rem;
}

.uf-hero__headline--display {
    margin: 0;
    /* Both lines hold one row with room to spare against a late font swap.
       The measure matters here because of where the device sits: the first
       line runs behind the phone the way the old headline did, while the
       second carries the wordmark and stops just short of it. That second
       line is the tight one, so it is the one to re-measure if the copy
       changes. A longer translation wraps to a third row rather than running
       deeper behind the device, which is the safer of the two failures. */
    max-width: 16ch;
}

.uf-hero__opening-foot {
    align-self: end;
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: clamp(1.5rem, 4vw, 4rem);
    padding-top: 2rem;
}

.uf-hero__lede {
    /* Viewport-relative below ~1280px: the lede, the device and the card
       share one row, and a fixed 32rem left the phone nowhere to stand on a
       narrow laptop. */
    max-width: min(32rem, 40vw);
    pointer-events: auto;
}

.uf-hero__lede .uf-hero__sub {
    margin-bottom: 1.6rem;
    /* A step down from the shared hero sub: on the opening screen this sits
       under a very large headline and beside the card, and at the full size
       it competed with both. */
    font-size: clamp(0.9rem, 1vw, 1rem);
}

/* Actions: one filled pill and the two store squares beside it, the
   reference's shape. The pill and the first square are both the App Store -
   the pill carries the words, the squares carry the marks.

   The reference's pill is a soft grey rather than a bright white - next to
   the two dark squares a pure white block reads as a highlight instead of a
   button, and the grey is what lets the phone stay the brightest thing on
   the screen. Geometric face to match the display type above it. */
.uf-hero__cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    height: 58px;
    padding: 0 1.9rem;
    /* Squared off to the same corner as the store squares beside it, so the
       row reads as one set rather than a pill next to two tiles. */
    border-radius: 16px;
    background: #cbcbd4;
    color: #101014;
    font-family: var(--uf-display);
    font-size: 0.9rem;
    font-weight: 500;
    letter-spacing: -0.01em;
    white-space: nowrap;
    text-decoration: none;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
                background-color 0.35s ease;
}

.uf-hero__cta:hover,
.uf-hero__cta:focus-visible {
    transform: translateY(-2px);
    background: #e3e3ea;
}

.uf-hero__iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 58px;
    height: 58px;
    border: 1px solid rgba(255, 255, 255, 0.09);
    /* Squircle, not a circle: 28% of the box, as in the reference. */
    border-radius: 16px;
    /* Near-black with a lit top edge: the gloss is a single highlight sweep
       over a flat near-black, plus an inset hairline along the top, which is
       what gives the reference's tiles their glassy dome without any of it
       being a real gradient of the background colour. */
    background:
        linear-gradient(157deg, rgba(255, 255, 255, 0.11) 0%, rgba(255, 255, 255, 0) 46%),
        #08080b;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10),
                0 10px 24px rgba(0, 0, 0, 0.45);
    color: var(--uf-text);
    font-size: 1rem;
    text-decoration: none;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
                border-color 0.35s ease,
                box-shadow 0.35s ease;
}

.uf-hero__iconbtn:hover,
.uf-hero__iconbtn:focus-visible {
    transform: translateY(-2px);
    border-color: rgba(255, 255, 255, 0.22);
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18),
                0 14px 30px rgba(0, 0, 0, 0.5);
}

/* Philosophy card - bottom-right companion panel */

.uf-hero__phil {
    /* The device layer sits above the panels (z 4) so headlines pass behind
       the phone. A panel sliced in half by it reads as a mistake rather than
       depth, so this one card comes forward and lets its glass blur the
       device instead. */
    position: relative;
    z-index: 5;
    flex: none;
    width: min(21rem, 27vw);
    padding: 1.15rem 1.15rem 1.3rem;
    border: 1px solid rgba(255, 255, 255, 0.14);
    border-radius: 26px;
    /* Real glass, not a flat tint: the sheet is brightest at the top-left
       corner the light comes from and falls away across the face, so the
       panel has an orientation instead of reading as grey film. */
    background:
        linear-gradient(152deg,
            rgba(255, 255, 255, 0.115) 0%,
            rgba(255, 255, 255, 0.035) 46%,
            rgba(255, 255, 255, 0.06) 100%);
    /* Saturate as well as blur: an unsaturated blur of the indigo atmosphere
       behind it turns grey, which is what made the old card look like fog. */
    backdrop-filter: blur(26px) saturate(150%);
    -webkit-backdrop-filter: blur(26px) saturate(150%);
    /* Lit top edge, faint floor, and a shadow that lifts the whole sheet off
       the device passing behind it. */
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.22),
        inset 0 -1px 0 rgba(255, 255, 255, 0.05),
        0 30px 60px -34px rgba(0, 0, 0, 0.9);
    pointer-events: auto;
}

/* Specular highlight across the top-left corner. Its own layer so it sits
   over the backdrop blur but under the content. */
.uf-hero__phil::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    background: radial-gradient(120% 90% at 0% 0%,
        rgba(255, 255, 255, 0.16) 0%,
        rgba(255, 255, 255, 0) 58%);
    pointer-events: none;
}

/* --- The essays, one page at a time -------------------------------------
   A featured-essay pager rather than a drifting list: counter, title, and
   the first thought of the dek hold still long enough to be read, then the
   next essay slides through left to right. No inner tile and no edge mask -
   the glass is the surface, and overflow clipping is the only frame.

   Fraunces for the titles, not the UI sans - these are essay titles, and
   the serif is the voice the philosophy pages already use. */

.uf-hero__phil-stream {
    position: relative;
    margin-bottom: 1.1rem;
    overflow: hidden;
    /* The track is a flex row of eight slides, so its natural width is eight
       cards wide. Below 900px the card and its ancestors are shrink-to-fit,
       and that intrinsic width leaked upwards and pushed the whole copy
       column off the side of the phone. Containment tells the layout that
       this element's width never depends on what is inside it, which is
       exactly true here: the slides are sized from the card, not the other
       way round. */
    contain: inline-size;
}

.uf-hero__phil-track {
    display: flex;
    margin: 0;
    padding: 0;
    list-style: none;
    /* Sixteen keyframe stops: eight holds of ~6s and eight 0.7s slides. The
       easing applies per segment, so each slide gets the hero's signature
       settle while the holds sit still. */
    animation: uf-phil-page 52s cubic-bezier(0.16, 1, 0.3, 1) infinite;
}

.uf-hero__phil-track li {
    flex: none;
    width: 100%;
    padding-inline: 0.45rem;
}

.uf-hero__phil-count {
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    color: var(--uf-text-faint);
}

.uf-hero__phil-title {
    margin: 0.55rem 0 0.5rem;
    font-family: var(--uf-serif);
    font-size: 1.28rem;
    font-weight: 500;
    line-height: 1.3;
    color: var(--uf-text);
}

.uf-hero__phil-dek {
    margin: 0;
    font-size: 0.8rem;
    line-height: 1.55;
    color: var(--uf-text-dim);
}

/* Hovering the card is a reading gesture: hold the current essay still. */
.uf-hero__phil:hover .uf-hero__phil-track {
    animation-play-state: paused;
}

/* The track runs from -800% up to 0, so the motion is left to right and the
   essays are laid out in reverse DOM order (see index.html). Position 8 is
   essay 1 and position 0 is its clone: the cycle ends on the same pixels it
   started on, so the reset is invisible. */
@keyframes uf-phil-page {
    0%      { transform: translateX(-800%); }
    11.15%  { transform: translateX(-800%); }
    12.5%   { transform: translateX(-700%); }
    23.65%  { transform: translateX(-700%); }
    25%     { transform: translateX(-600%); }
    36.15%  { transform: translateX(-600%); }
    37.5%   { transform: translateX(-500%); }
    48.65%  { transform: translateX(-500%); }
    50%     { transform: translateX(-400%); }
    61.15%  { transform: translateX(-400%); }
    62.5%   { transform: translateX(-300%); }
    73.65%  { transform: translateX(-300%); }
    75%     { transform: translateX(-200%); }
    86.15%  { transform: translateX(-200%); }
    87.5%   { transform: translateX(-100%); }
    98.65%  { transform: translateX(-100%); }
    100%    { transform: translateX(0); }
}

@media (prefers-reduced-motion: reduce) {
    /* With no animation the track sits at translateX(0): the first child,
       which is the essay 1 clone, so the static card still leads with the
       first essay. */
    .uf-hero__phil-track { animation: none; }
}

/* A hairline, not a border: the pager and the link are two halves of one
   surface, divided by a rule rather than boxed apart. The link reads as a
   quiet text link rather than a button - the essay above it is the pitch,
   so the footer only has to say where it goes. */
.uf-hero__phil-link {
    padding-top: 1rem;
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    display: flex;
    align-items: center;
    gap: 0.6rem;
    /* Matches the slides' inset, so essay and link share one left edge. */
    padding-inline: 0.45rem;
    font-family: var(--uf-sans);
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--uf-text);
    text-decoration: none;
}

.uf-hero__phil-arrow {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    font-size: 0.8rem;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.uf-hero__phil-link:hover .uf-hero__phil-arrow,
.uf-hero__phil-link:focus-visible .uf-hero__phil-arrow {
    transform: translateX(4px);
}

.uf-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.55rem;
    padding: 0.9rem 1.5rem;
    border-radius: 100px;
    font-family: var(--uf-sans);
    font-size: 0.92rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
    border: 1px solid transparent;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
                background-color 0.35s ease,
                border-color 0.35s ease;
}

.uf-btn--primary {
    background: var(--uf-paper);
    color: #101018;
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5) inset,
                0 14px 34px -14px rgba(0, 0, 0, 0.8);
}

.uf-btn--primary:hover {
    transform: translateY(-2px);
    background: #fff;
}

.uf-btn--ghost {
    background: rgba(255, 255, 255, 0.06);
    border-color: var(--uf-hairline);
    color: var(--uf-text);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
}

.uf-btn--ghost:hover {
    transform: translateY(-2px);
    background: rgba(255, 255, 255, 0.12);
    border-color: rgba(255, 255, 255, 0.24);
}

/* Still used by the closing panel's universities line; the starred App Store
   rating that also lived in here has been retired. */
.uf-hero__proof {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.55rem 0.8rem;
    padding-top: 1.3rem;
    border-top: 1px solid var(--uf-hairline);
    font-size: 0.76rem;
    color: var(--uf-text-faint);
}

/* --------------------------------------------------------------------------
   Phone - right column of the rig
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   WebGL stage
   Fills the rig and sits between the atmosphere and the copy, so the device is
   lit and moved in scene space. The CSS phone stays in the layout when WebGL
   takes over - hidden, but still measured, because its wrapper defines how far
   the device is allowed to travel.
   -------------------------------------------------------------------------- */

.uf-hero__stage {
    position: absolute;
    inset: 0;
    z-index: 2;
    pointer-events: none;
}

.uf-hero__canvas {
    display: block;
    width: 100%;
    height: 100%;
}

.uf-hero.is-webgl .uf-hero__device,
.uf-hero.is-webgl .uf-hero__contact-shadow {
    visibility: hidden;
}

/* Spans both columns and centres, so GSAP can drive the device to either side */
.uf-hero__phone-wrap {
    position: relative;
    grid-column: 1 / -1;
    justify-self: center;
    width: clamp(258px, 22vw, 330px);
}

.uf-hero__phone {
    position: relative;
    z-index: 2;
    width: 100%;
    transform-style: preserve-3d;
    /* The device's rotateX/Y/Z live on the child, so the viewing frustum has
       to be declared here - a transformPerspective on this element only ever
       applied to its own translate/scale, which left the CSS fallback's
       rotations rendering flat while the WebGL device had real depth. Same
       number as EYE in js/device-model.js. */
    perspective: 6400px;
    will-change: transform, opacity, filter;
}

/* Idle float for the static fallback (narrow viewports / no GSAP). The
   scripted devices get the same drift from their motion loops, so this class
   is only ever added by js/hero-scroll.js's static path. */
@media (prefers-reduced-motion: no-preference) {
    .uf-hero__phone--float {
        animation: uf-phone-float 8.5s ease-in-out infinite;
    }
}

@keyframes uf-phone-float {
    0%, 100% { transform: translate3d(0, 0, 0) rotateZ(0deg); }
    30%      { transform: translate3d(2px, -9px, 0) rotateZ(-0.5deg); }
    70%      { transform: translate3d(-2px, 4px, 0) rotateZ(0.4deg); }
}

.uf-hero__phone-bloom {
    position: absolute;
    inset: -26% -36%;
    border-radius: 50%;
    background: radial-gradient(circle, rgba(85, 87, 232, 0.55) 0%, rgba(85, 87, 232, 0) 68%);
    filter: blur(50px);
    transform: translateZ(-80px);
    opacity: 0;
    will-change: opacity, transform;
}

/* ---- Device body --------------------------------------------------------
   Geometry follows an iPhone 15/16 Pro: corner radius is ~16% of the body
   width, the titanium rail is a thin bright band, and the black bezel inside
   it is only ~1.5% of the width.

   The body is a real solid: front and back faces sit half a thickness apart
   with their backfaces hidden, and two slabs close the long edges. A rotateY
   sweep therefore shows the actual back shell, not a mirrored screen.

   Keep filters off the device and everything above it - a filter forces a
   preserve-3d subtree to flatten, collapsing the two faces into one plane.
   Depth comes from box-shadow and the separate contact shadow instead. */

.uf-hero__device {
    position: relative;
    transform-style: preserve-3d;
}

.uf-hero__face {
    border-radius: 16% / 7.4%;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    transform-style: preserve-3d;
    background:
        /* brushed titanium rail */
        linear-gradient(115deg,
            #7f8295 0%, #3f424f 10%, #262833 22%,
            #5f6274 35%, #303340 49%,
            #1e2029 63%, #545769 79%, #2c2e37 91%, #6e7183 100%);
    box-shadow:
        0 0 0 1px rgba(255, 255, 255, 0.16),
        0 55px 100px -38px rgba(0, 0, 0, 0.95),
        0 20px 44px -18px rgba(0, 0, 0, 0.8),
        inset 0 1px 1px rgba(255, 255, 255, 0.26),
        inset 0 -1px 1px rgba(255, 255, 255, 0.1);
}

/* Front stays in flow so the screen's aspect ratio sizes the whole device */
.uf-hero__face--front {
    position: relative;
    padding: 1.45%;
    transform: translateZ(var(--uf-half));
}

.uf-hero__face--back {
    position: absolute;
    inset: 0;
    padding: 1.45%;
    transform: rotateY(180deg) translateZ(var(--uf-half));
}

/* Static builds (touch devices, reduced motion, no GSAP) hold the resting
   tilt forever, so the rear shell and edge slabs can never legitimately
   show. They stay in the DOM for the scripted sweeps, but here they are
   only a liability: WebKit's depth sorting inside nested preserve-3d
   paints the hidden back face over the screen, which put the BACK of the
   phone on every real iPhone. js/hero-scroll.js adds this class on its
   static path. */
.uf-hero__phone--flat .uf-hero__face--back,
.uf-hero__phone--flat .uf-hero__slab {
    display: none;
}

/* Belt and braces: touch devices only ever get the static pose (the scrub
   rig is gated off touch in js/hero-scroll.js), so drop the rear geometry
   there unconditionally too - the fix must not depend on a script running. */
@media (hover: none), (pointer: coarse) {
    .uf-hero__face--back,
    .uf-hero__slab {
        display: none;
    }
}

/* ---- Back shell --------------------------------------------------------- */

.uf-hero__shell {
    position: relative;
    height: 100%;
    border-radius: 14.6% / 6.6%;
    overflow: hidden;
    /* Matte frosted glass. The stage's indigo and violet orbs are baked in as
       soft reflections so the shell picks up its surroundings instead of
       reading as flat black. */
    background:
        radial-gradient(90% 55% at 18% 6%, rgba(139, 141, 255, 0.3) 0%, transparent 62%),
        radial-gradient(80% 60% at 88% 82%, rgba(123, 63, 168, 0.28) 0%, transparent 66%),
        radial-gradient(140% 90% at 50% 45%, rgba(255, 255, 255, 0.05) 0%, transparent 70%),
        linear-gradient(158deg, #43454f 0%, #2a2c35 26%, #34363f 52%, #1d1f27 78%, #14151c 100%);
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.09),
        inset 0 1px 0 rgba(255, 255, 255, 0.14),
        inset 0 0 60px rgba(0, 0, 0, 0.5);
}

/* Long diagonal highlight, the way a glass back catches a key light */
.uf-hero__shell-sheen {
    position: absolute;
    inset: 0;
    background: linear-gradient(112deg,
        rgba(255, 255, 255, 0.13) 0%,
        rgba(255, 255, 255, 0.03) 22%,
        transparent 42%,
        transparent 63%,
        rgba(255, 255, 255, 0.06) 84%,
        rgba(255, 255, 255, 0.14) 100%);
}

/* Camera module, upper left as on a real iPhone viewed from behind. The face's
   own 180deg cancels the device's, so by the time the back is facing us its net
   rotation is near zero and this layout is not mirrored. */
.uf-hero__camera {
    position: absolute;
    top: 2.6%;
    left: 5.5%;
    width: 39%;
    aspect-ratio: 1;
    border-radius: 27%;
    background:
        linear-gradient(150deg, rgba(255, 255, 255, 0.12) 0%, rgba(255, 255, 255, 0.02) 40%, rgba(0, 0, 0, 0.28) 100%);
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.1),
        0 4px 14px rgba(0, 0, 0, 0.5);
}

.uf-hero__lens {
    position: absolute;
    width: 37%;
    aspect-ratio: 1;
    border-radius: 50%;
    background:
        radial-gradient(circle at 34% 28%, #4c5570 0%, #14161d 42%, #05060a 100%);
    box-shadow:
        0 0 0 2px rgba(120, 124, 140, 0.5),
        inset 0 0 6px rgba(0, 0, 0, 0.9);
}

/* Lens ring highlight and the blue-green coating glint */
.uf-hero__lens::after {
    content: '';
    position: absolute;
    inset: 26%;
    border-radius: 50%;
    background: radial-gradient(circle at 32% 26%, rgba(120, 200, 255, 0.5) 0%, rgba(20, 30, 60, 0.6) 45%, #04050a 100%);
}

.uf-hero__lens--1 { top: 6%;  left: 6%; }
.uf-hero__lens--2 { top: 6%;  right: 6%; }
.uf-hero__lens--3 { bottom: 6%; left: 6%; }

.uf-hero__flash {
    position: absolute;
    bottom: 15%;
    right: 13%;
    width: 17%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: radial-gradient(circle at 40% 35%, #fff8e6 0%, #d8c9a2 45%, #6b6350 100%);
    box-shadow: 0 0 8px rgba(255, 245, 220, 0.35);
}

.uf-hero__mic {
    position: absolute;
    bottom: 34%;
    right: 15%;
    width: 11%;
    aspect-ratio: 1;
    border-radius: 50%;
    background: #0a0b11;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);
}

/* ---- Long edges ---------------------------------------------------------
   Each slab is centred on the body edge and turned 90 degrees, so it spans the
   full thickness and keeps the silhouette solid through the revolution. */

.uf-hero__edge {
    position: absolute;
    top: 5.5%;
    height: 89%;
    width: calc(var(--uf-half) * 2);
    border-radius: 3px;
    transform: rotateY(90deg);
    background: linear-gradient(180deg,
        #6f7285 0%, #3a3d49 14%, #55586a 32%,
        #2b2d37 54%, #5f6274 76%, #33353f 92%, #71748a 100%);
    box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.55);
}

.uf-hero__edge--left  { left: calc(var(--uf-half) * -1); }
.uf-hero__edge--right { right: calc(var(--uf-half) * -1); }

/* Antenna seams on the rail */
.uf-hero__rail-line {
    position: absolute;
    width: 1.5px;
    height: 3px;
    background: rgba(255, 255, 255, 0.3);
    border-radius: 2px;
}

.uf-hero__rail-line--t1 { top: 15%; left: -0.4px; }
.uf-hero__rail-line--t2 { bottom: 15%; right: -0.4px; }

/* Black bezel + screen aperture */
.uf-hero__glass {
    position: relative;
    border-radius: 14.6% / 6.6%;
    background: #000;
    overflow: hidden;
    box-shadow:
        inset 0 0 0 1.5px #05050a,
        inset 0 0 12px rgba(0, 0, 0, 0.9);
}

.uf-hero__screens {
    position: relative;
    aspect-ratio: 601 / 1300;
    overflow: hidden;
    background: #fff;
    isolation: isolate;
}

.uf-hero__screen {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0;
    will-change: opacity, transform;
}

.uf-hero__screen.is-active {
    opacity: 1;
}

/* Dynamic Island */
.uf-hero__island {
    position: absolute;
    top: 1.65%;
    left: 50%;
    transform: translateX(-50%);
    width: 27%;
    height: 2.35%;
    min-height: 10px;
    border-radius: 100px;
    background: #000;
    box-shadow: inset 0 0 2px rgba(255, 255, 255, 0.12);
    z-index: 8;
}

.uf-hero__island::after {
    /* front camera lens */
    content: '';
    position: absolute;
    top: 50%;
    right: 14%;
    width: 22%;
    aspect-ratio: 1;
    transform: translateY(-50%);
    border-radius: 50%;
    background: radial-gradient(circle at 35% 30%, #1b2033 0%, #05060a 65%);
}

/* Screen gloss - a soft diagonal reflection on the glass */
.uf-hero__gloss {
    position: absolute;
    inset: 0;
    z-index: 9;
    pointer-events: none;
    background: linear-gradient(115deg,
        rgba(255, 255, 255, 0.16) 0%,
        rgba(255, 255, 255, 0.05) 22%,
        transparent 42%,
        transparent 62%,
        rgba(255, 255, 255, 0.07) 88%,
        rgba(255, 255, 255, 0.14) 100%);
    opacity: 0.75;
    will-change: transform, opacity;
}

/* ---- Side buttons ------------------------------------------------------- */

/* Buttons lie on the side planes and stand slightly proud of them, so they
   read correctly as the body turns edge-on. */
.uf-hero__btn {
    position: absolute;
    width: calc(var(--uf-half) * 1.45);
    border-radius: 2px;
    background: linear-gradient(180deg, #9497a8 0%, #4c4f5e 40%, #2a2c37 100%);
    box-shadow: 0 0 2px rgba(0, 0, 0, 0.75);
}

/* left side: action button, then the volume pair */
.uf-hero__btn-action,
.uf-hero__btn-volup,
.uf-hero__btn-voldown {
    left: calc(var(--uf-half) * -0.725);
    transform: rotateY(90deg) translateZ(-2px);
}

.uf-hero__btn-action  { top: 17.5%; height: 5%; }
.uf-hero__btn-volup   { top: 26%;   height: 8%; }
.uf-hero__btn-voldown { top: 35.5%; height: 8%; }

/* right side: power */
.uf-hero__btn-power {
    right: calc(var(--uf-half) * -0.725);
    top: 29%;
    height: 12%;
    transform: rotateY(90deg) translateZ(2px);
}

/* Ground shadow */
.uf-hero__contact-shadow {
    position: absolute;
    left: 50%;
    bottom: -5%;
    width: 76%;
    height: 34px;
    transform: translateX(-50%);
    background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0) 72%);
    filter: blur(10px);
    will-change: transform, opacity;
}

/* --------------------------------------------------------------------------
   Floating cards
   -------------------------------------------------------------------------- */

/* Wider than the device so each card only clips the phone's outer edge */
.uf-hero__cards {
    position: absolute;
    inset: -6% -58%;
    z-index: 3;
    pointer-events: none;
}

.uf-hero__card {
    position: absolute;
    display: flex;
    align-items: center;
    gap: 0.7rem;
    margin: 0;
    padding: 0.72rem 0.95rem;
    width: max-content;
    max-width: 14rem;
    border-radius: 14px;
    background: rgba(16, 17, 32, 0.6);
    border: 1px solid rgba(255, 255, 255, 0.12);
    backdrop-filter: blur(18px) saturate(140%);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
    box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.9),
                0 1px 0 rgba(255, 255, 255, 0.07) inset;
    opacity: 0;
    will-change: transform, opacity;
}

.uf-hero__card i {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    border-radius: 9px;
    background: rgba(85, 87, 232, 0.22);
    color: var(--uf-indigo-soft);
    font-size: 0.8rem;
}

.uf-hero__card figcaption {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    line-height: 1.3;
}

.uf-hero__card strong {
    font-size: 0.8rem;
    font-weight: 600;
    color: #fff;
}

.uf-hero__card span {
    font-size: 0.7rem;
    color: var(--uf-text-faint);
}

.uf-hero__card--a { top: 11%;   left: 0; }
.uf-hero__card--b { top: 31%;   right: 0; }
.uf-hero__card--c { bottom: 22%; left: 3%; }
.uf-hero__card--d { bottom: 6%;  right: 2%; }

/* --------------------------------------------------------------------------
   In-screen overlays
   -------------------------------------------------------------------------- */

.uf-hero__tap {
    position: absolute;
    z-index: 7;
    top: var(--tap-y, 50%);
    left: var(--tap-x, 50%);
    width: 76px;
    height: 76px;
    margin: -38px 0 0 -38px;
    border-radius: 50%;
    border: 2px solid rgba(85, 87, 232, 0.85);
    background: radial-gradient(circle, rgba(85, 87, 232, 0.3) 0%, rgba(85, 87, 232, 0) 68%);
    opacity: 0;
    transform: scale(0.3);
    pointer-events: none;
    will-change: transform, opacity;
}

.uf-hero__focus {
    position: absolute;
    z-index: 7;
    top: var(--focus-y, 40%);
    left: 5%;
    width: 90%;
    height: var(--focus-h, 12%);
    border-radius: 14px;
    border: 1.5px solid rgba(200, 244, 93, 0.9);
    box-shadow: 0 0 0 3px rgba(200, 244, 93, 0.16),
                0 0 26px rgba(200, 244, 93, 0.28);
    opacity: 0;
    pointer-events: none;
    will-change: transform, opacity;
}

.uf-hero__sheet {
    position: absolute;
    z-index: 7;
    left: 4%;
    right: 4%;
    bottom: 3%;
    padding: 1rem 1rem 1.1rem;
    border-radius: 18px;
    background: rgba(10, 11, 22, 0.93);
    border: 1px solid rgba(255, 255, 255, 0.14);
    backdrop-filter: blur(20px);
    -webkit-backdrop-filter: blur(20px);
    box-shadow: 0 -18px 50px -18px rgba(0, 0, 0, 0.9);
    transform-origin: 50% 100%;
    opacity: 0;
    pointer-events: none;
    will-change: transform, opacity;
}

.uf-hero__sheet-grab {
    display: block;
    width: 30px;
    height: 3px;
    margin: 0 auto 0.7rem;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.25);
}

.uf-hero__sheet p { margin: 0; }

.uf-hero__sheet-kicker {
    font-size: 0.5rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--uf-indigo-soft);
    margin-bottom: 0.35rem !important;
}

.uf-hero__sheet-title {
    font-family: var(--uf-serif);
    font-size: 0.78rem;
    line-height: 1.25;
    color: #fff;
    margin-bottom: 0.45rem !important;
}

.uf-hero__sheet-body {
    font-size: 0.6rem;
    line-height: 1.5;
    color: rgba(255, 255, 255, 0.66);
    margin-bottom: 0.7rem !important;
}

.uf-hero__sheet-body s { color: rgba(255, 120, 110, 0.85); }

.uf-hero__sheet-body mark {
    background: rgba(200, 244, 93, 0.2);
    color: var(--uf-lime);
    padding: 0 0.2em;
    border-radius: 3px;
}

.uf-hero__sheet-meter {
    height: 3px;
    border-radius: 3px;
    background: rgba(255, 255, 255, 0.12);
    overflow: hidden;
    margin-bottom: 0.45rem;
}

.uf-hero__sheet-fill {
    display: block;
    height: 100%;
    width: 100%;
    border-radius: 3px;
    background: linear-gradient(90deg, var(--uf-indigo), var(--uf-lime));
    transform: scaleX(0);
    transform-origin: 0 50%;
    will-change: transform;
}

.uf-hero__sheet-score {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 0.55rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--uf-text-faint);
}

.uf-hero__sheet-score strong {
    font-size: 0.7rem;
    color: var(--uf-lime);
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 1180px) {
    .uf-hero__cards { inset: -6% -34%; }
    .uf-hero__card span { display: none; }
    .uf-hero__phone-wrap { width: clamp(230px, 24vw, 290px); }
}

/* Rig mode on narrow viewports: the same choreography as desktop, laid out
   for portrait. Copy owns the top of the frame and the device performs in
   the lower two-thirds; the beats, poses and screen swaps are identical -
   only the geometry changes. */
@media (max-width: 900px) {
    :root.uf-rig .uf-hero__rig-inner {
        grid-template-columns: minmax(0, 1fr);
        padding: 0 1.25rem;
    }

    :root.uf-rig .uf-hero__phone-wrap {
        width: min(52vw, 220px);
        justify-self: center;
        /* Sit the resting poses in the lower half so the sticky copy above
           mostly clears the device; crossings still sweep behind the words,
           which is the desktop behaviour. */
        margin-top: 30svh;
    }

    :root.uf-rig .uf-hero__panel-inner {
        grid-template-columns: minmax(0, 1fr);
        padding: 0 1.25rem;
    }

    /* Every beat's copy reads from the same place: full width, top of the
       frame. The side-to-side alternation is the device's job here - at this
       width there is no second column for the words to cross to. */
    :root.uf-rig .uf-hero__copy,
    :root.uf-rig .uf-hero__panel--right .uf-hero__copy {
        grid-column: 1;
        justify-self: start;
        max-width: 30rem;
        top: 10svh;
    }

    :root.uf-rig .uf-hero__panel--centre .uf-hero__copy {
        top: 10svh;
    }

    :root.uf-rig .uf-hero__cards {
        inset: -4% -18%;
    }

    /* Opening beat: the corner composition stacks - headline, lede, actions,
       philosophy card - and the device rests to its right edge. */
    :root.uf-rig .uf-hero__opening {
        display: block;
        min-height: 0;
        pointer-events: auto;
    }

    :root.uf-rig .uf-hero__opening-head,
    :root.uf-rig .uf-hero__opening-foot {
        display: block;
    }

    :root.uf-rig .uf-hero__headline--display,
    :root.uf-rig .uf-hero__lede {
        max-width: none;
    }

    :root.uf-rig .uf-hero__phil {
        width: 100%;
        max-width: 30rem;
    }

    :root.uf-rig .uf-hero__outro {
        height: 20svh;
    }
}

/* Below 900px WITHOUT the rig (reduced motion, no WebGL on touch, no GSAP):
   the phone sits inline under the copy and the whole hero becomes a single,
   normally scrolling block. */
@media (max-width: 900px) {
    :root:not(.uf-rig) .uf-hero__rig {
        position: relative;
        height: auto;
        /* No navbar to clear any more - the dock is at the bottom - so this
           is just the hero's own top breathing room. */
        padding: 2rem 0 0;
    }

    /* The atmosphere layer stops being a screen-high sticky sheet and
       becomes the hero's backdrop: absolute over the whole section, under
       everything. The device layer keeps the rig's relative flow but must
       shed the desktop pull-up, or it would climb a full screen over the
       navbar. */
    :root:not(.uf-rig) .uf-hero__rig--atmos {
        position: absolute;
        inset: 0;
        height: auto;
        padding: 0;
    }

    :root:not(.uf-rig) .uf-hero__rig--device {
        margin-top: 0;
    }

    :root:not(.uf-rig) .uf-hero__rig-inner {
        grid-template-columns: 1fr;
        padding: 0 1.25rem;
    }

    :root:not(.uf-rig) .uf-hero__atmos {
        position: absolute;
        inset: 0;
        height: auto;
    }

    /* Stack the device above its cards, and keep it small enough that the
       headline below still lands inside the first screenful. */
    :root:not(.uf-rig) .uf-hero__phone-wrap {
        grid-column: 1;
        width: min(212px, 50vw);
        display: flex;
        flex-direction: column;
        align-items: center;
    }

    :root:not(.uf-rig) .uf-hero__phone {
        order: 1;
    }

    :root:not(.uf-rig) .uf-hero__cards {
        order: 2;
        position: static;
        inset: auto;
        width: max-content;
        max-width: calc(100vw - 2.5rem);
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: 0.5rem;
        margin-top: 1.1rem;
    }

    :root:not(.uf-rig) .uf-hero__card {
        position: static;
        opacity: 1 !important;
        transform: none !important;
    }

    .uf-hero__card--c,
    :root:not(.uf-rig) .uf-hero__card--d {
        display: none;
    }

    :root:not(.uf-rig) .uf-hero__panels {
        margin-top: 1.75rem;
    }

    :root:not(.uf-rig) .uf-hero__panel {
        min-height: 0;
        padding: 0 0 3rem;
    }

    :root:not(.uf-rig) .uf-hero__panel-inner {
        grid-template-columns: 1fr;
        padding: 0 1.25rem;
    }

    :root:not(.uf-rig) .uf-hero__copy {
        max-width: 34rem;
        margin: 0 auto;
        text-align: center;
        opacity: 1 !important;
        transform: none !important;
    }

    .uf-hero__actions,
    :root:not(.uf-rig) .uf-hero__proof {
        justify-content: center;
    }

    /* The opening's corner composition collapses into the same centred
       column as every other beat: head, lede, card, one under the other. */
    :root:not(.uf-rig) .uf-hero__opening {
        display: block;
        min-height: 0;
        pointer-events: auto;
    }

    .uf-hero__opening-head,
    :root:not(.uf-rig) .uf-hero__opening-foot {
        display: block;
    }

    :root:not(.uf-rig) .uf-hero__headline--display {
        max-width: none;
    }

    :root:not(.uf-rig) .uf-hero__lede {
        max-width: none;
    }

    :root:not(.uf-rig) .uf-hero__actions {
        margin-bottom: 1.6rem;
    }

    :root:not(.uf-rig) .uf-hero__phil {
        width: 100%;
        max-width: 34rem;
        margin: 0 auto;
        text-align: left;
    }

    :root:not(.uf-rig) .uf-hero__sub {
        margin-left: auto;
        margin-right: auto;
    }

    :root:not(.uf-rig) .uf-hero__outro {
        display: none;
    }

}

@media (max-width: 560px) {
    .uf-hero__headline {
        font-size: clamp(2rem, 9vw, 2.7rem);
    }

    /* The pill goes full width and the two squares sit under it as a row,
       rather than three stacked full-width blocks. */
    .uf-hero__actions {
        justify-content: center;
    }

    .uf-btn,
    .uf-hero__cta {
        width: 100%;
    }

    .uf-hero__cta,
    .uf-hero__iconbtn {
        height: 52px;
    }

    .uf-hero__iconbtn { width: 52px; }

    .uf-hero__phil {
        padding: 1.2rem 1.2rem 1.1rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .uf-hero__rig {
        position: relative;
        height: auto;
        padding: calc(84px + 2rem) 0 0;
    }

    /* Mirror of the narrow layout above: atmosphere becomes the section's
       backdrop, device layer sheds the desktop pull-up. */
    .uf-hero__rig--atmos {
        position: absolute;
        inset: 0;
        height: auto;
        padding: 0;
    }

    .uf-hero__rig--device {
        margin-top: 0;
    }

    .uf-hero__panels {
        margin-top: 0;
    }

    .uf-hero__panel {
        min-height: 0;
        padding-bottom: 3rem;
    }

    .uf-hero__outro {
        display: none;
    }

    .uf-hero__copy,
    .uf-hero__card {
        opacity: 1 !important;
        transform: none !important;
    }

    .uf-hero__phone-bloom { opacity: 0.55; }
}
