/* The secondary-page experience sections.
 *
 * Two shapes generated by tools/growth.py, sharing one set of route cards:
 *
 *   .gx-cinematic  Projects and Capabilities. One tall section with a sticky
 *                  stage: a scroll-driven scene, three chapters of copy, the
 *                  documented figures, then the three routes.
 *   .gx-editorial  Products, Articles, Careers and Contact. One photograph,
 *                  the question, the three routes. Nothing pinned, because a
 *                  visitor there is searching, reading, applying or sending an
 *                  enquiry and should not be waiting on a sequence.
 *
 * Progressive enhancement is the rule the rest of this file is built around:
 * NOTHING here is hidden, pinned, stacked or faded unless the script has put
 * data-gx-enhanced on the section. Read with JavaScript off, a cinematic
 * section is an ordinary heading, photograph, three chapters and three links,
 * all in normal document flow. The only things the stylesheet hides on its
 * own are the two decorative pieces that carry no information -- the giant
 * background word and the scene's tinted halo -- because losing those costs
 * a visitor nothing.
 *
 * main > section carries padding-left/right:8% !important from site.css, so
 * the full-bleed sections say !important back rather than pretending to
 * out-specify it; the gutter then lives on the inner wrappers instead.
 *
 * Brand pages (brands/*) and four article pages load this file for the
 * .growth-faq and .gx-reading rules at the end and nothing else.
 */

/* --- Why the sticky stage would otherwise not stick ------------------------
 *
 * site.css has `main { overflow: hidden }` to stop a wide child pushing the
 * page sideways. But `overflow: hidden` makes an element a SCROLL CONTAINER,
 * and position:sticky sticks inside the nearest scroll container rather than
 * to the viewport -- so inside that <main> a sticky section behaves like
 * position:relative and simply scrolls away. `overflow: clip` clips exactly
 * the same way WITHOUT creating a scroll container, which is what that rule
 * always wanted.
 *
 * It lives here rather than in site.css so it ships with this stylesheet's
 * own cache version: changing site.css would leave every visitor holding a
 * cached copy of it with a redesign that depends on the change. This file is
 * loaded after site.css on every page that has it, so the later declaration
 * wins; a browser too old to know `clip` ignores this rule and keeps the
 * behaviour it has today. */
main { overflow: clip; }

/* --- Shared ---------------------------------------------------------------
   --gx-header is the real site header: 84px, 72px under the 768px breakpoint
   in site.css. The sticky stage is measured against it, so it can never sit
   under the header or leave a strip of the previous section showing above
   itself. */
.gx-experience, .gx-brief {
    --gx-accent: var(--c-accent);
    --gx-header: 84px;
    color: var(--c-ink);
}
.gx-projects { --gx-accent: #29747c; }
.gx-capabilities { --gx-accent: #5962a4; }
.gx-careers { --gx-accent: #a64b26; }

.gx-eyebrow {
    margin: 0 0 .9rem;
    font-family: 'IBM Plex Mono', monospace;
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--gx-accent);
}
/* site.css sets font-family, font-weight and colour on every heading and a
   size on h2, all with !important. Specificity does not beat !important, so
   this says it back rather than writing rules that silently do nothing --
   the same convention assets/vx.css already documents. */
.gx-experience h2, .gx-brief h2 {
    margin: 0;
    max-width: 22ch;
    font-family: 'Space Grotesk', Inter, Arial, sans-serif;
    font-size: clamp(2rem, 4.4vw, 3.4rem) !important;
    line-height: 1.06 !important;
    letter-spacing: -.035em;
}
.gx-instruction { margin: 1.1rem 0 0; color: var(--c-sub); font-size: .95rem; }

/* --- Route cards ----------------------------------------------------------
   The heading holds two labels: a button revealed by script, and a plain
   span that is what a visitor without JavaScript reads. One of them is
   always visible, and the description and the link below never depend on
   either. */
.gx-routes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1rem; }
.gx-route {
    padding: 1.35rem;
    border: 1px solid var(--c-line);
    border-radius: 14px;
    background: var(--c-surface);
    transition: border-color .25s ease, background .25s ease;
}
.gx-route.is-selected { border-color: var(--gx-accent); background: var(--c-band); }
.gx-route h3 { margin: 0 0 .85rem; font-size: 1.05rem; letter-spacing: -.01em; }
.gx-choice {
    width: 100%;
    min-height: 44px;
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-weight: 650;
    text-align: left;
    cursor: pointer;
}
.gx-choice > span, .gx-jump > span:first-child {
    margin-right: .6rem;
    font-family: 'IBM Plex Mono', monospace;
    font-size: .7rem;
    color: var(--gx-accent);
}
.gx-route p { margin: 0 0 1rem; color: var(--c-sub); font-size: .92rem; line-height: 1.7; }
.gx-route a {
    display: inline-block;
    padding-block: 6px;
    color: var(--c-ink);
    font-size: .87rem;
    line-height: 1.6;
    text-underline-offset: 4px;
}

/* --- Editorial ------------------------------------------------------------
   A photograph already on the site, the question, then the routes. The only
   enhancement is the crop below, which is why this shape can go on the
   catalogue, the articles index, careers and -- after the form -- contact. */
.gx-editorial {
    max-width: 1280px;
    margin-inline: auto;
    padding-block: clamp(2.5rem, 6vw, 4.5rem);
}
.gx-editorial-head {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(1.5rem, 4vw, 3.5rem);
    margin-bottom: clamp(1.75rem, 4vw, 2.75rem);
}
.gx-media { margin: 0; }
.gx-media__frame {
    display: block;
    overflow: hidden;
    aspect-ratio: 16 / 10;
    border: 1px solid var(--c-line);
    border-radius: 16px;
    background: var(--c-band);
}
.gx-media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* --gx-crop is written by the script from the section's own position in
       the viewport; unset it is 0, which is a still photograph. */
    transform: scale(calc(1 + var(--gx-crop, 0) * .06));
    transform-origin: 50% 45%;
}
/* The contact photograph is the only portrait one in the set, and the part
   worth seeing -- the flange face and its connectors -- sits below centre, so
   a centred crop of a 16:10 frame cuts it in half. */
.gx-contact .gx-media img { object-position: 50% 62%; }
.gx-media figcaption {
    margin-top: .75rem;
    color: var(--c-sub);
    font-family: 'IBM Plex Mono', monospace;
    font-size: .68rem;
    letter-spacing: .06em;
    line-height: 1.6;
}

/* --- Cinematic: the readable base ----------------------------------------
   Everything below applies with or without JavaScript. The section is a
   full-bleed dark slab -- the same near-black slab site.css already uses for
   an inverted band -- with the stage laid out as an ordinary two-column
   grid. The enhanced block after this one is what pins it. */
.gx-cinematic {
    padding-inline: 0 !important;
    background: var(--c-inkband);
    color: #f0f2f4;
    --gx-accent: #a8c96b;
    --gx-stage-sub: #a6acb5;
    --gx-stage-line: rgba(255, 255, 255, .14);
    border-bottom-color: transparent;
}
.gx-cinematic .gx-eyebrow { color: var(--gx-accent); }
.gx-scroll { position: relative; }
.gx-stage {
    position: relative;
    display: grid;
    /* The object gets the larger share. This section exists to show a piece
       of engineering; the copy is there to explain it, not to share the
       stage equally with it. */
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    align-items: center;
    gap: clamp(1.5rem, 4vw, 4rem);
    max-width: 1280px;
    margin-inline: auto;
    padding: clamp(2.5rem, 6vw, 4.5rem) max(6%, 1.25rem);
}
.gx-word {
    display: none;                /* decorative only; see the file header */
    position: absolute;
    z-index: 0;
    /* Behind the object, not behind the copy: at 4.5% white it cannot hurt
       legibility either way, but a word that sits under the headline reads
       as a mistake rather than as a backdrop. */
    inset-inline-end: max(3%, .75rem);
    inset-block-end: -.08em;
    margin: 0;
    text-align: end;
    font-family: 'Space Grotesk', Inter, Arial, sans-serif;
    font-size: clamp(5rem, 15vw, 13rem);
    font-weight: 700;
    letter-spacing: -.05em;
    line-height: 1;
    color: rgba(255, 255, 255, .035);
    pointer-events: none;
    user-select: none;
}
.gx-visual { position: relative; z-index: 1; order: 2; min-width: 0; }
.gx-canvas {
    position: relative;
    overflow: hidden;
    aspect-ratio: 16 / 10;
    border-radius: 18px;
    background: rgba(255, 255, 255, .03);
}
/* Absolutely positioned on purpose. The renderer sizes the drawing buffer
   from the container's client box, and the <canvas> element's intrinsic size
   IS that buffer -- so leaving it in flow inside a flex column makes the two
   chase each other and the panel grows without bound. Out of flow, the grid
   decides the container's height and the buffer follows it. */
.gx-canvas canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.gx-still {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: opacity .6s ease;
}
/* Set by the script only once a frame has actually been drawn, so a failed
   import, a blocked module or a machine without WebGL keeps the photograph
   rather than showing an empty box. */
.gx-canvas.is-live { background: none; border-radius: 0; }
.gx-canvas.is-live .gx-still { opacity: 0; }
.gx-note {
    margin: .85rem 0 0;
    max-width: 46ch;
    color: var(--gx-stage-sub);
    font-family: 'IBM Plex Mono', monospace;
    font-size: .64rem;
    letter-spacing: .05em;
    line-height: 1.7;
    text-transform: uppercase;
}
.gx-cinematic .gx-copy { position: relative; z-index: 1; order: 1; min-width: 0; }
.gx-cinematic h2 { color: #fff !important; }

.gx-chapters {
    margin: clamp(1.5rem, 3vw, 2.25rem) 0 0;
    padding: 0;
    list-style: none;
}
.gx-chapter { margin: 0 0 1.5rem; max-width: 46ch; }
.gx-chapter:last-child { margin-bottom: 0; }
.gx-chapter__index {
    margin: 0 0 .35rem;
    font-family: 'IBM Plex Mono', monospace;
    font-size: .68rem;
    letter-spacing: .16em;
    color: var(--gx-accent);
}
.gx-chapter h3 {
    margin: 0 0 .5rem;
    font-family: 'Space Grotesk', Inter, Arial, sans-serif;
    font-size: 1.2rem;
    letter-spacing: -.015em;
    color: #fff !important;
}
.gx-chapter__text { margin: 0; color: var(--gx-stage-sub); font-size: 1rem; line-height: 1.75; }

.gx-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem 2.25rem;
    margin-top: clamp(1.5rem, 3vw, 2.25rem);
    padding-top: 1.5rem;
    border-top: 1px solid var(--gx-stage-line);
}
.gx-facts div { min-width: 0; }
.gx-facts strong {
    display: block;
    font-family: 'Space Grotesk', Inter, Arial, sans-serif;
    font-size: clamp(1.5rem, 3vw, 2.1rem);
    font-weight: 700;
    letter-spacing: -.03em;
    color: #fff;
}
.gx-facts small { font-size: .5em; font-weight: 500; letter-spacing: 0; }
.gx-facts span {
    display: block;
    margin-top: .3rem;
    max-width: 18ch;
    color: var(--gx-stage-sub);
    font-family: 'IBM Plex Mono', monospace;
    font-size: .66rem;
    letter-spacing: .05em;
    line-height: 1.6;
}

/* The controls exist in the markup but are hidden until the script reveals
   them: a pause button that pauses nothing and a progress bar that tracks
   nothing would be worse than no controls at all. */
/* order:3 because .gx-copy and .gx-visual carry orders of their own to put
   the text above the object on a narrow screen; without one of its own the
   controls would sort to the front of both. */
.gx-controls { grid-column: 1 / -1; order: 3; display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1.25rem; }
.gx-jumps { display: flex; flex-wrap: wrap; gap: .5rem; }
.gx-jump, .gx-motion {
    display: inline-flex;
    align-items: center;
    gap: .1rem;
    min-height: 40px;
    padding: .5rem .9rem;
    border: 1px solid var(--gx-stage-line);
    border-radius: 999px;
    background: rgba(255, 255, 255, .04);
    color: #f0f2f4;
    font-family: 'IBM Plex Mono', monospace;
    font-size: .68rem;
    letter-spacing: .08em;
    text-transform: uppercase;
    cursor: pointer;
    transition: background .2s ease, border-color .2s ease, color .2s ease;
}
.gx-jump:hover, .gx-motion:hover { background: rgba(255, 255, 255, .1); }
/* State is carried by the border and the fill as well as by the text, so it
   does not depend on colour alone. */
.gx-jump.is-active { border-color: var(--gx-accent); background: rgba(168, 201, 107, .16); color: #fff; }
.gx-motion[aria-pressed="true"] { border-color: var(--gx-accent); background: rgba(168, 201, 107, .16); }
.gx-progress {
    flex: 1 1 8rem;
    min-width: 6rem;
    height: 2px;
    background: var(--gx-stage-line);
    border-radius: 2px;
}
.gx-progress > span {
    display: block;
    width: 0;
    height: 100%;
    background: var(--gx-accent);
    border-radius: 2px;
}

.gx-route-wrap {
    max-width: 1280px;
    margin-inline: auto;
    padding: 0 max(6%, 1.25rem) clamp(2.5rem, 6vw, 4.5rem);
}
.gx-route-label {
    margin: 0 0 1rem;
    font-family: 'IBM Plex Mono', monospace;
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--gx-stage-sub);
}
.gx-cinematic .gx-route { border-color: var(--gx-stage-line); background: rgba(255, 255, 255, .04); }
.gx-cinematic .gx-route.is-selected { border-color: var(--gx-accent); background: rgba(255, 255, 255, .09); }
.gx-cinematic .gx-route h3 { color: #fff !important; }
.gx-cinematic .gx-route p { color: var(--gx-stage-sub); }
.gx-cinematic .gx-route a { color: #f0f2f4; }

/* --- Cinematic: the enhanced state ---------------------------------------
   Applied only under [data-gx-enhanced], which the script sets after it has
   found the section, measured it and attached its listeners. The scroll
   distance is deliberately short of the prototype's: two and a half screens
   is enough to read three chapters and still leave the page navigable. */
.gx-cinematic[data-gx-enhanced] .gx-word { display: block; }
.gx-cinematic[data-gx-enhanced] .gx-scroll { height: 260vh; }
.gx-cinematic[data-gx-enhanced] .gx-stage {
    position: sticky;
    top: var(--gx-header);
    height: calc(100svh - var(--gx-header));
    min-height: 34rem;
    /* An explicit row for the scene and one for the controls. Without it the
       row is only as tall as the copy beside it, and the object -- the thing
       this section exists to show -- ends up the smaller half of the stage. */
    grid-template-rows: minmax(0, 1fr) auto;
    align-content: stretch;
    padding-block: clamp(1.25rem, 3vh, 2.5rem);
}
.gx-cinematic[data-gx-enhanced] .gx-visual {
    align-self: stretch;
    display: flex;
    flex-direction: column;
    justify-content: center;
    min-height: 0;
}
/* Capped rather than filled. The subjects are wide and flat, so the camera
   fits them to the panel's WIDTH; in a tall panel that leaves the object
   floating in empty space. Holding a 4:3 box -- and letting it go wider when
   the row is short -- keeps the object as the thing filling the frame. */
.gx-cinematic[data-gx-enhanced] .gx-canvas {
    flex: 0 1 auto;
    width: 100%;
    aspect-ratio: 4 / 3;
    max-height: 100%;
    min-height: 0;
}

/* The chapters stack on one another and the active one is brought forward.
   grid-area rather than display:none, so the text stays in the accessibility
   tree and in the document for anything reading the page rather than
   scrolling it; the script marks the inactive ones aria-hidden. */
.gx-cinematic[data-gx-enhanced] .gx-chapters { display: grid; }
.gx-cinematic[data-gx-enhanced] .gx-chapter {
    grid-area: 1 / 1;
    margin: 0;
    opacity: 0;
    transform: translateY(14px);
    pointer-events: none;
    transition: opacity .5s cubic-bezier(.22, 1, .36, 1), transform .5s cubic-bezier(.22, 1, .36, 1);
}
.gx-cinematic[data-gx-enhanced] .gx-chapter.is-active { opacity: 1; transform: none; pointer-events: auto; }
/* The figures belong to the last chapter: they are the evidence the sequence
   arrives at, not decoration to run underneath it. */
.gx-cinematic[data-gx-enhanced] .gx-facts {
    opacity: 0;
    transform: translateY(14px);
    transition: opacity .5s cubic-bezier(.22, 1, .36, 1), transform .5s cubic-bezier(.22, 1, .36, 1);
}
.gx-cinematic[data-gx-enhanced][data-gx-chapter="2"] .gx-facts { opacity: 1; transform: none; }

/* --- The lighter band, on service and project detail pages ----------------
   Direction B and C at a smaller scale: one band, never pinned, with the
   page's own headings beside the visual and the page's real content directly
   under it. A visitor came here to read a service or a case study, so the
   band is something they pass, not something they wait for. */
.gx-brief {
    padding-inline: 0 !important;
    background: var(--c-inkband);
    color: #f0f2f4;
    --gx-accent: #a8c96b;
    --gx-stage-sub: #a6acb5;
    --gx-stage-line: rgba(255, 255, 255, .14);
    border-bottom-color: transparent;
}
.gx-brief__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: clamp(1.5rem, 4vw, 3.5rem);
    max-width: 1280px;
    margin-inline: auto;
    padding: clamp(2.25rem, 5vw, 3.75rem) max(6%, 1.25rem);
}
.gx-brief .gx-eyebrow { color: var(--gx-accent); }
.gx-brief h2 { color: #fff !important; font-size: clamp(1.7rem, 3.4vw, 2.6rem) !important; }
.gx-brief .gx-copy { order: 1; min-width: 0; }
.gx-brief .gx-visual { order: 2; }
.gx-brief__lead { margin: 1.1rem 0 0; max-width: 44ch; color: var(--gx-stage-sub); font-size: 1rem; line-height: 1.75; }
.gx-brief .gx-media figcaption { color: var(--gx-stage-sub); }
/* Two of the three project photographs are portrait; 4:3 keeps the subject
   in a landscape frame instead of slicing it. */
.gx-brief .gx-media__frame { aspect-ratio: 4 / 3; border-color: var(--gx-stage-line); background: rgba(255, 255, 255, .04); }
.gx-brief .gx-controls { grid-column: 1 / -1; order: 3; }

.gx-points { display: grid; gap: .8rem; margin: clamp(1.25rem, 3vw, 1.75rem) 0 0; padding: 0; list-style: none; }
.gx-point {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: .15rem .8rem;
    padding-top: .8rem;
    border-top: 1px solid var(--gx-stage-line);
}
.gx-point__index {
    grid-row: span 2;
    font-family: 'IBM Plex Mono', monospace;
    font-size: .68rem;
    letter-spacing: .14em;
    line-height: 1.6;
    color: var(--gx-accent);
}
.gx-point b { color: #fff; font-size: .98rem; }
.gx-point > span:last-child { color: var(--gx-stage-sub); font-size: .9rem; line-height: 1.65; }
/* Staggered on entry, and only once the script has said so. */
.gx-brief[data-gx-enhanced][data-gx-motion="on"] .gx-point {
    opacity: 0;
    transform: translateY(12px);
    transition: opacity .6s cubic-bezier(.22, 1, .36, 1), transform .6s cubic-bezier(.22, 1, .36, 1);
}
.gx-brief[data-gx-enhanced][data-gx-motion="on"] .gx-point.is-in { opacity: 1; transform: none; }

@media (max-width: 900px) {
    .gx-brief__inner { grid-template-columns: 1fr; }
}

/* --- Preserved: article and brand page rules -----------------------------
   These pre-date the redesign and are loaded by pages that have no
   experience section at all. They are unchanged. */
.growth-faq details { border-bottom: 1px solid var(--c-line); padding: 1rem 0; }
.growth-faq summary { cursor: pointer; font-weight: 600; padding: .4rem 0; color: var(--c-ink); }
.growth-faq details p { margin-top: 1rem; }
.gx-reading {
    padding: 1.5rem 8%;
    background: var(--c-band);
    border-block: 1px solid var(--c-line);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem 1.75rem;
}
.gx-reading p { flex-basis: 100%; margin: 0; font-size: .72rem; font-weight: 650; letter-spacing: .1em; text-transform: uppercase; color: var(--c-sub); }
.gx-reading a { color: var(--c-ink); font-size: .9rem; text-underline-offset: 4px; padding-block: .5rem; }

/* One focus ring for everything in here, and it stays visible on the dark
   stage as well as on the light sections. */
.gx-choice:focus-visible,
.gx-route a:focus-visible,
.gx-jump:focus-visible,
.gx-motion:focus-visible,
.growth-faq summary:focus-visible,
.gx-reading a:focus-visible {
    outline: 3px solid var(--gx-accent, var(--c-accent));
    outline-offset: 4px;
    border-radius: 3px;
}

/* --- Narrower viewports ---------------------------------------------------
   Text above the object, as agreed: on a phone the copy has to be readable
   before the scene means anything. The scene keeps a 4:3 share of the screen
   so it is still large enough to read as an aircraft or an enclosure. */
@media (max-width: 980px) {
    .gx-stage, .gx-editorial-head { grid-template-columns: 1fr; }
    .gx-visual { order: 2; }
    .gx-cinematic .gx-copy { order: 1; }
    .gx-cinematic[data-gx-enhanced] .gx-scroll { height: 240vh; }
    .gx-cinematic[data-gx-enhanced] .gx-stage {
        grid-template-rows: auto minmax(0, 1fr) auto;
        gap: 1rem;
    }
    /* No floor on the panel here. One screen has to hold the heading, a
       chapter, the figures, the controls AND the object; a min-height on the
       object is what pushes the total past the viewport and starts the
       overflow, so the object takes what is left and the copy above is what
       gets tightened instead. */
    .gx-cinematic[data-gx-enhanced] .gx-canvas { min-height: 0; }
    .gx-cinematic .gx-chapters { margin-top: 1.1rem; }
    .gx-word { font-size: clamp(3.5rem, 20vw, 7rem); }
}
@media (max-width: 768px) {
    .gx-experience { --gx-header: 72px; }
}
/* A phone has one screenful to spend on the whole stage, so every part of
   the copy above the object is measured rather than merely scaled: a smaller
   heading, a tighter chapter, the figures in two columns instead of a wrapping
   row, and the controls on one line with the progress bar under them. What
   that buys is a panel big enough to read the object in. */
@media (max-width: 700px) {
    .gx-routes { grid-template-columns: 1fr; }
    .gx-experience h2, .gx-brief h2 { font-size: clamp(1.5rem, 6.4vw, 2rem) !important; }
    .gx-cinematic .gx-eyebrow { margin-bottom: .6rem; }
    .gx-cinematic .gx-chapters { margin-top: .9rem; }
    .gx-chapter h3 { font-size: 1.05rem; }
    .gx-chapter__text { font-size: .92rem; line-height: 1.6; }
    .gx-facts {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: .7rem 1rem;
        margin-top: 1rem;
        padding-top: 1rem;
    }
    .gx-facts strong { font-size: 1.25rem; }
    .gx-facts span { margin-top: .15rem; font-size: .6rem; max-width: none; }
    .gx-note { font-size: .56rem; line-height: 1.55; }
    .gx-cinematic[data-gx-enhanced] .gx-stage { min-height: 28rem; }
    /* The chapter names are in the copy directly above; on the buttons they
       are what makes the row wrap onto a second line. */
    .gx-jump__name { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }
    .gx-jump, .gx-motion { min-height: 36px; padding: .4rem .7rem; }
    .gx-controls { gap: .5rem .5rem; }
    .gx-progress { flex-basis: 100%; }
}

/* --- Motion preference ----------------------------------------------------
   There is one static presentation and one selector for it,
   data-gx-motion="off", which the script writes: on load when the system
   asks for reduced motion, and whenever the visitor presses Pause. Routing
   the system preference through the script rather than through a second
   @media copy of these rules is what lets Resume actually resume -- a
   visitor who wants to watch the sequence can opt in without editing an OS
   setting, and one who never touches the button keeps the setting they
   already chose.
   Reduced motion here is a different presentation, not a degraded one: the
   section stops being pinned, and every chapter and every figure is shown at
   once rather than waiting behind a scroll position.
   The @media block below is for the case the script never reaches. Nothing
   is pinned without data-gx-enhanced anyway, so it only has to stop things
   moving. */
@media (prefers-reduced-motion: reduce) {
    .gx-experience *, .gx-experience *::before, .gx-experience *::after {
        transition-duration: .01ms !important;
        animation-duration: .01ms !important;
    }
    .gx-media img { transform: none; }
    html { scroll-behavior: auto; }
}
.gx-cinematic[data-gx-motion="off"] .gx-scroll { height: auto; }
.gx-cinematic[data-gx-motion="off"] .gx-stage { position: static; height: auto; min-height: 0; padding-block: clamp(2.5rem, 6vw, 4.5rem); }
.gx-cinematic[data-gx-motion="off"] .gx-chapters { display: block; }
.gx-cinematic[data-gx-motion="off"] .gx-chapter { opacity: 1; transform: none; pointer-events: auto; margin-bottom: 1.5rem; }
.gx-cinematic[data-gx-motion="off"] .gx-chapter:last-child { margin-bottom: 0; }
.gx-cinematic[data-gx-motion="off"] .gx-facts { opacity: 1; transform: none; }
.gx-cinematic[data-gx-motion="off"] .gx-visual { display: block; }
.gx-cinematic[data-gx-motion="off"] .gx-canvas { aspect-ratio: 16 / 10; }
/* Both track a scroll position that no longer exists once the stage is
   unpinned: a bar that cannot move and jumps that would land on text
   already fully on the page. */
.gx-cinematic[data-gx-motion="off"] .gx-jumps,
.gx-cinematic[data-gx-motion="off"] .gx-progress { display: none; }
.gx-editorial[data-gx-motion="off"] .gx-media img { transform: none; }
