/* ============================================================
   LAYOUT — the stage, the environment, the chrome
   ------------------------------------------------------------
   The document scrolls; the composition does not. Everything you
   see lives in one fixed stage, and the scroll position is read as
   a timeline. That is what lets a chapter leave the page and come
   back to it without the layout ever jumping.
   ============================================================ */

.stage {
  position: fixed;
  inset: 0;
  z-index: var(--z-stage);
  overflow: hidden;
  /* A static ground. The chapter colour is painted by `.env__field`,
     which covers this completely; making the stage itself depend on
     `--env-base` would mean writing that property onto an element with
     six hundred descendants on every frame of a cross-fade. */
  background: var(--color-bg-void);
}

/* the scroll track: invisible, and only there to give length */
.track { position: relative; z-index: 0; pointer-events: none; }
.act { display: block; width: 100%; }

/* ============================================================
   ENVIRONMENT
   Five stacked layers. None of them is ever completely still,
   and all of them shift colour between chapters.
   ============================================================ */

.env { position: absolute; inset: 0; pointer-events: none; }

/* ---- 1 · THE FIELD ----
   Ground, haze and vignette as three background layers on ONE element
   instead of three stacked elements. It carries no key light: that
   moves every frame and lives on its own compositor layer below, so
   this repaints only when the chapter's colours change. */
.env__fields { position: absolute; inset: 0; }
.env__field {
  /* a canvas painted once per palette (environment.js paintField) — the
     five gradients this used to carry are drawn into it */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

/* ---- 1b · THE SET (Phase 5.1) ----
   Where the volume is kept. Static; its opacity only (environment.js). */
.env__set { position: absolute; inset: 0; will-change: opacity; contain: strict; }
/* the horizon of a polished floor, low, and the floor catching light */
.env__floor {
  position: absolute;
  left: 0;
  right: 0;
  top: 71%;
  bottom: 0;
  border-top: 1px solid rgb(190 150 96 / 0.10);
  background:
    radial-gradient(60% 55% at 50% 0%, rgb(190 140 84 / 0.07), rgb(190 140 84 / 0) 70%),
    linear-gradient(180deg, rgb(24 20 16 / 0.55), rgb(8 7 6 / 0) 80%);
}
/* the hall's slots, far off: warm hairlines with a haze round them,
   standing on the horizon; their reflections run down into the floor */
.env__far {
  position: absolute;
  bottom: 29%;
  width: 2px;
  margin-left: -1px;
  background: linear-gradient(to top, rgb(255 206 150 / 0.2), rgb(255 214 164 / 0.75) 10%, rgb(255 224 180 / 0.6) 90%, rgb(255 206 150 / 0));
  box-shadow: 0 0 18px 3px rgb(255 170 96 / 0.16);
}
.env__far::after {
  content: '';
  position: absolute;
  left: 0;
  top: 100%;
  width: 2px;
  height: 70%;
  background: linear-gradient(180deg, rgb(255 206 150 / 0.32), rgb(255 206 150 / 0));
  filter: blur(1px);
}
/* a beam from high above, onto the volume */
.env__beam {
  position: absolute;
  left: 50%;
  top: -10%;
  width: 70vmin;
  height: 110%;
  margin-left: -35vmin;
  background: linear-gradient(180deg, rgb(255 222 176 / 0.05), rgb(255 222 176 / 0.015) 70%, rgb(255 222 176 / 0));
  clip-path: polygon(38% 0, 62% 0, 100% 100%, 0 100%);
  /* painted once: the blur softens the cone's edges into air */
  filter: blur(22px);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 30%, #000 70%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 30%, #000 70%, transparent);
}
/* the pool of light the volume stands in */
.env__pool {
  position: absolute;
  left: 50%;
  top: 88%;
  width: 70vmin;
  height: 14vmin;
  margin: -7vmin 0 0 -35vmin;
  background: radial-gradient(closest-side, rgb(255 196 128 / 0.16), rgb(255 196 128 / 0.05) 55%, rgb(255 196 128 / 0));
}
@media (max-width: 720px) {
  .env__far:nth-of-type(n) { display: none; }
  .env__floor { top: 76%; }
}

/* ---- 2 · THE KEY LIGHT ----
   One promoted layer. JS moves it with a transform and dims it with an
   opacity; it never repaints. No blend mode: this is warm light on a
   near-black field, where plain alpha reads the same as screen and does
   not force the compositor to read back what is underneath it. */
.env__key {
  position: absolute;
  left: 50%;
  top: 50%;
  /* only the lit part of the light (Phase 6.0): the gradient was clear
     beyond 70 % of a 120vmax square, and the GPU drew all of it, every
     frame the light drifted — half the layer's area was nothing */
  width: 84vmax;
  height: 84vmax;
  margin: -42vmax 0 0 -42vmax;
  will-change: transform, opacity;
  contain: strict;
}
/* one per palette, painted once; the key light's colour change between
   chapters is a cross-fade of two of these */
.env__tint {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    closest-side,
    rgb(var(--env-glow) / 0.2) 0%,
    rgb(var(--env-glow) / 0.06) 54%,
    rgb(255 255 255 / 0) 100%
  );
}

/* ---- 3 · DUST ----
   Dots, each on its own tiny layer; see environment.js initMotes(). */
.env__motes { position: absolute; inset: 0; contain: strict; }
.env__mote {
  position: absolute;
  left: 0;
  top: 0;
  border-radius: 50%;
  background: currentColor;
  opacity: 0;
  /* moved by a Web Animation with plain-number keyframes (environment.js),
     which the compositor runs by itself (Phase 6.0) */
  will-change: transform, opacity;
}
@media (prefers-reduced-motion: reduce) {
  .env__motes { display: none; }
}

/* ---- 4 · GRAIN ----
   A pre-tinted tile, so no blend mode, drifting on a compositor-only
   animation rather than a transform written every frame. */
.env__grain {
  position: absolute;
  /* the window, not 220px beyond it: the bleed was for a drift that is
     gone, and it made this the largest layer on the page (Phase 5.7) */
  inset: 0;
  background-image: var(--grain-fine);
  background-size: 128px 128px;
  opacity: 0.05;
  /* Still. The drift was a 14-second keyframe loop on a layer at 5 %
     opacity — imperceptible, and the performance trace showed it ticking
     the main thread on every single frame (142 of them in a short run).
     Grain on film does not slide across the frame anyway. */
}

/* The opening darkness. It sits above the whole composition — the
   book, the chapters and the chrome — because at the start there is
   nothing to see yet, and that has to be true of everything. */
.blackout {
  position: fixed;
  inset: 0;
  z-index: 85;
  background: #000;
  opacity: var(--blackout, 1);
  pointer-events: none;
}

/* ---------- WHAT IS LEFT OF THE VOLUME ----------

   When a chapter takes the screen the book withdraws and is dropped out
   of the scene, because drawing a blurred, near-transparent 3D book
   behind an opaque chapter is pure cost. But if nothing at all remains,
   the experience stops being a volume you are reading out of and becomes
   a website with a book on the first screen.

   So the volume does not leave the room — it goes under the frame. What
   stays is the head of the open block along the bottom edge, the light
   lying across it, and the shadow it throws into the floor. The chapter
   then reads as type lifted off the page rather than as a new document.

   One element, three gradients, no 3D, no blur, and driven entirely off
   `--recede`, which the bookstage is already writing. Nothing here is
   ever written by JavaScript. */
.bookstage__ledge {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: clamp(58px, 11vh, 132px);
  z-index: 1;
  pointer-events: none;
  /* arrives as the volume goes, and is gone before it comes back */
  opacity: clamp(0, calc((var(--recede, 0) - 0.55) * 2.4), 1);
  background-image:
    /* the light lying along the head of the block, brightest where the
       key light is, falling away to either side */
    linear-gradient(180deg,
      rgb(233 225 210 / 0) 0 62%,
      rgb(233 225 210 / 0.4) 62% calc(62% + 1px),
      rgb(233 225 210 / 0) calc(62% + 1px)),
    /* the paper of the block: a sliver, in perspective, so it reads as
       the top edge of something thick rather than as a line */
    linear-gradient(180deg,
      rgb(0 0 0 / 0) 0 63%,
      rgb(169 155 131 / 0.34) 63%,
      rgb(90 80 64 / 0.3) 72%,
      rgb(0 0 0 / 0) 86%),
    /* and the shade under it — below the lit edge only. It used to start
       at full strength at the top of this element, a hard-edged dark band
       a hundred pixels above the page edge that read as a footer bar
       across every chapter and cut into its last lines (Phase 4.8 audit). */
    linear-gradient(180deg,
      rgb(0 0 0 / 0) 0 58%,
      rgb(0 0 0 / 0.5) 66%,
      rgb(0 0 0 / 0) 100%);
  /* the block is narrower than the window: fade the edges so it reads as
     an object below the frame, not as a band across the screen */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 16%, #000 84%, transparent);
}

/* The pool of light that finds the volume. Transparent where the key
   light falls, opaque everywhere else, and it lifts as the light
   grows — so the book is revealed by lighting rather than by a fade. */
.bookstage__reveal {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  opacity: calc(1 - var(--reveal, 0));
  background: radial-gradient(
    62% 56% at var(--env-key-x) var(--env-key-y),
    rgb(0 0 0 / 0) 0%,
    rgb(0 0 0 / 0.42) 30%,
    rgb(0 0 0 / 0.88) 58%,
    rgb(0 0 0 / 0.98) 80%
  );
}

/* ============================================================
   ESCAPE LAYERS — where a chapter leaves the page
   ============================================================ */

.escapes { position: absolute; inset: 0; z-index: var(--z-escape); pointer-events: none; }

/* `will-change` is declared only while a chapter is live. Leaving it on
   all eight kept eight viewport-sized compositor layers alive at once,
   which measured ~35ms a frame for layers that were not even visible. */
.escape {
  position: absolute;
  inset: 0;
  display: grid;
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.escape.is-live { visibility: visible; will-change: opacity, transform; }
.escape.is-interactive { pointer-events: auto; }

.escape__inner {
  position: relative;
  width: 100%;
  height: 100%;
  /* the left inset clears the chapter rail, which lives in the same
     column of the screen and must never be typed over */
  padding:
    clamp(64px, 9vh, 120px)
    var(--gutter)
    clamp(60px, 8vh, 104px)
    calc(var(--gutter) + var(--rail-w, 0px));
  display: grid;
  overflow: hidden;
}

/* ============================================================
   CHROME — masthead, chapter rail, progress, folio
   ============================================================ */

.chrome {
  position: fixed;
  inset: 0;
  z-index: var(--z-chrome);
  pointer-events: none;
}
.chrome > * { pointer-events: auto; }

.masthead {
  opacity: var(--chrome-on, 1);
  /* no transition: the value is already smoothed per frame in JS; a CSS transition on top restarts every frame and ticks on the main thread */
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-5);
  padding: clamp(18px, 2.6vh, 32px) var(--gutter);
}

.masthead__mark {
  display: flex;
  align-items: baseline;
  gap: 0.72em;
  font-family: var(--font-meta);
  font-size: var(--t-meta);
  font-weight: 600;
  letter-spacing: var(--track-meta-wide);
  text-transform: uppercase;
  color: var(--color-text-primary);
}
.masthead__mark b { font-weight: 600; }
.masthead__mark i {
  font-style: normal;
  color: var(--color-accent-deep);
  font-size: 0.86em;
  letter-spacing: var(--track-meta);
}

.masthead__now {
  display: flex;
  align-items: baseline;
  gap: 0.8em;
  overflow: hidden;
}
/* A running head, as a printed volume sets one: the chapter's title,
   quiet, at the head of the page. The chapter number is already on the
   index at the left and the folio at the foot — a third copy here was
   the one true duplicate in the chrome (Phase 4.8 audit). The element
   stays in the page: it is the polite live region that announces the
   chapter, and the title alone is what should be announced. */
.masthead__now .n { display: none; }
.masthead__now .n--kept {
  font-family: var(--font-meta);
  font-size: var(--t-meta);
  letter-spacing: 0.16em;
  color: var(--color-accent-base);
  font-variant-numeric: tabular-nums;
}
.masthead__now .t {
  font-family: var(--font-display);
  font-size: 0.96rem;
  font-style: italic;
  letter-spacing: 0.01em;
  color: var(--color-text-secondary);
  display: inline-block;
  transition: transform var(--dur-ui) var(--ease-arrive), opacity var(--dur-ui) linear;
}
.masthead__now.is-swapping .t { transform: translateY(-110%); opacity: 0; }

/* ---------- the reading progress: a thread down the page edge ---------- */
.thread {
  opacity: var(--chrome-on, 1);
  /* no transition: the value is already smoothed per frame in JS; a CSS transition on top restarts every frame and ticks on the main thread */
  position: absolute;
  right: calc(var(--gutter) * 0.42);
  top: 22vh;
  bottom: 22vh;
  width: 1px;
  background: var(--color-border-faint);
}
/* Fill and bead move by transform. They were `height` and `top` driven by
   a value that changes on almost every scrolling frame: a layout and a
   repaint of a glowing element per frame. The trace counted 641 layout
   invalidations on the fill in one pass down the volume. */
.thread__fill {
  position: absolute;
  inset: 0;
  transform: scaleY(var(--read, 0));
  transform-origin: 50% 0;
  will-change: transform;
  background: linear-gradient(180deg, var(--color-accent-light), var(--color-accent-deep));
  box-shadow: 0 0 14px rgb(207 174 99 / 0.55);
}
.thread__bead {
  position: absolute;
  left: 50%;
  top: 0;
  /* the thread runs from 22vh to 78vh: 56vh long */
  transform: translate3d(0, calc(var(--read, 0) * 56vh), 0);
  will-change: transform;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: var(--color-accent-bright);
  box-shadow: 0 0 12px 2px rgb(228 205 142 / 0.6);
}

/* ---------- folio: the page number, bottom-left ---------- */
.folio-mark {
  opacity: var(--chrome-on, 1);
  /* no transition: the value is already smoothed per frame in JS; a CSS transition on top restarts every frame and ticks on the main thread */
  position: absolute;
  left: var(--gutter);
  bottom: clamp(18px, 2.6vh, 30px);
  display: flex;
  align-items: baseline;
  gap: 0.7em;
  font-family: var(--font-meta);
  font-size: var(--t-meta);
  letter-spacing: 0.18em;
  color: var(--color-text-faint);
  font-variant-numeric: tabular-nums;
}
.folio-mark .cur { color: var(--color-accent-base); }
.folio-mark .sep { width: 34px; height: 1px; background: var(--color-border-mid); display: inline-block; }

/* ---------- scroll invitation, opening only ---------- */
.invite {
  position: absolute;
  left: 50%;
  bottom: clamp(24px, 4vh, 48px);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  opacity: var(--invite, 0);
  /* no transition: the value is already smoothed per frame in JS; a CSS transition on top restarts every frame and ticks on the main thread */
}
.invite__line {
  width: 1px;
  height: 46px;
  background: linear-gradient(180deg, transparent, var(--color-accent-deep));
  transform-origin: top;
  animation: inviteDraw 2600ms var(--ease-cinematic) infinite;
  animation-play-state: paused;
}
.invite.is-on .invite__line { animation-play-state: running; }
@keyframes inviteDraw {
  0%, 100% { transform: scaleY(0.24); opacity: 0.25; }
  45% { transform: scaleY(1); opacity: 0.9; }
}

/* ============================================================
   RAIL — the chapter navigation
   ============================================================ */

.rail {
  position: absolute;
  width: var(--rail-w, auto);
  left: var(--gutter);
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 2px;
  opacity: var(--rail-on, 0);
  transition: opacity var(--dur-chapter) var(--ease-editorial);
}

.rail__item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 0;
  color: var(--color-text-faint);
  transition: color var(--dur-micro) var(--ease-editorial);
}
.rail__num {
  font-family: var(--font-meta);
  font-size: var(--t-micro);
  letter-spacing: 0.16em;
  font-variant-numeric: tabular-nums;
  width: 1.8em;
}
/* The rule is always 30px wide and shown at 14, 26 or 30 by a scale — it
   used to animate `width`, a layout on every frame of the change. The
   label is set back by the 16px the rule no longer takes up, so every
   label sits exactly where it did. */
.rail__dash {
  width: 30px;
  height: 1px;
  background: currentColor;
  opacity: 0.5;
  transform: scaleX(0.4667);
  transform-origin: 0 50%;
  transition: transform var(--dur-ui) var(--ease-arrive), opacity var(--dur-ui) linear;
}
.rail__label {
  font-family: var(--font-meta);
  font-size: var(--t-meta);
  font-weight: 500;
  letter-spacing: var(--track-meta);
  text-transform: uppercase;
  opacity: 0.55;
  transform: translateX(-20px);
  transition:
    opacity var(--dur-ui) var(--ease-editorial),
    transform var(--dur-ui) var(--ease-arrive),
    color var(--dur-ui) linear;
}
.rail__item:hover,
.rail__item:focus-visible { color: var(--color-text-primary); }
.rail__item:hover .rail__dash,
.rail__item:focus-visible .rail__dash { transform: scaleX(0.8667); opacity: 1; }
.rail__item:hover .rail__label,
.rail__item:focus-visible .rail__label { opacity: 1; transform: translateX(-4px); }

.rail__item.is-current { color: var(--color-accent-light); }
/* The current chapter's rule is an empty groove that fills in gold as the
   chapter is read; chapters behind the reader stay filled, dimmer. */
.rail__dash { position: relative; overflow: hidden; }
.rail__fill {
  position: absolute;
  inset: 0;
  background: var(--color-accent-base);
  transform: scaleX(0);
  transform-origin: 0 50%;
}
.rail__item.is-current .rail__dash { transform: none; opacity: 1; background: rgb(207 174 99 / 0.28); }
.rail__item.is-read .rail__fill { transform: scaleX(1); opacity: 0.45; }
.rail__item.is-current .rail__label { opacity: 1; transform: translateX(0); }

/* ============================================================
   PAGE-TURN TRANSITION VEIL
   A sheet of paper passes across the screen between chapters —
   the same gesture as the book, at the scale of the window.
   ============================================================ */

.veil {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  pointer-events: none;
  overflow: hidden;
  opacity: 0;
}
.veil.is-active { opacity: 1; }

.veil__sheet {
  position: absolute;
  inset: -4% -2%;
  transform-origin: left center;
  transform: translate3d(102%, 0, 0) rotate(0.6deg);
  background:
    linear-gradient(90deg, rgb(0 0 0 / 0.34), rgb(0 0 0 / 0) 18%),
    linear-gradient(162deg, var(--color-paper-leaf), var(--color-paper-fold) 54%, var(--color-paper-deep));
  box-shadow: -40px 0 90px rgb(0 0 0 / 0.6);
}
.veil__sheet::after {
  content: '';
  position: absolute;
  inset: 0;
  background-image: var(--grain-paper);
  background-size: 140px 140px;
  opacity: 1;
}

.veil__ink {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  opacity: 0;
}
.veil__ink .n {
  font-family: var(--font-display);
  font-size: clamp(4rem, 16vw, 14rem);
  color: var(--color-ink-strong);
  opacity: 0.14;
  letter-spacing: -0.04em;
}

/* ============================================================
   LOADER — the darkness before the light
   ============================================================ */

.boot {
  position: fixed;
  inset: 0;
  z-index: 150;
  background: #000;
  display: grid;
  place-items: center;
  transition: opacity var(--dur-cinematic) var(--ease-cinematic);
}
.boot.is-done { opacity: 0; pointer-events: none; }
/* a copy of the first portrait, drawn above the complete curtain for a
   few frames so the GPU meets its effects before the reader does
   (app.js, warmEffects). 0.002 over black is below one level of 8-bit
   brightness. */
.warmkit {
  position: fixed;
  left: 50%;
  top: 50%;
  width: 180px;
  transform: translate(-50%, -50%);
  z-index: 151;
  opacity: 0.002;
  pointer-events: none;
}
.warmkit .person__frame { max-height: none; transition: none; }
.boot__mark {
  font-family: var(--font-meta);
  font-size: var(--t-micro);
  letter-spacing: var(--track-meta-wide);
  text-transform: uppercase;
  color: var(--color-text-faint);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
.boot__bar { width: 110px; height: 1px; background: rgb(255 255 255 / 0.12); overflow: hidden; }
.boot__bar i {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--color-accent-base);
  transform: scaleX(var(--boot, 0));
  transform-origin: left;
  transition: transform 500ms var(--ease-editorial);
}

/* ============================================================
   EMBEDDED — the experience inside a host page's box
   ------------------------------------------------------------
   On the standalone page the stage and the chrome are fixed to the
   window, because the experience owns the window. Embedded, it owns only
   the box it was given: everything that was fixed is positioned in that
   box instead, and in 'element' mode the box scrolls itself — the
   composition sits in a sticky viewport at the top of its own scroller,
   so wheel and touch scroll it natively with no forwarding.
   ============================================================ */
.ad-embedded { position: relative; overflow: hidden; isolation: isolate; }
.ad-embedded:focus { outline: none; }
.ad-scroller {
  position: absolute;
  inset: 0;
  overflow-x: hidden;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: none;
}
.ad-scroller::-webkit-scrollbar { display: none; }
.ad-viewport { position: relative; height: var(--ad-h, 100%); overflow: hidden; }
.ad-element .ad-viewport { position: sticky; top: 0; z-index: 1; }
.ad-element .track { margin-top: calc(-1 * var(--ad-h, 100%)); }
.ad-controlled .ad-viewport { position: absolute; inset: 0; height: auto; }
.ad-embedded .stage,
.ad-embedded .chrome,
.ad-embedded .blackout,
.ad-embedded .veil,
.ad-embedded .cursor { position: absolute; }

/* ============================================================
   THE WORLD INSIDE THE VOLUME
   The hall is drawn over the book and under the chapters. Its canvas
   is only in the scene while its act is playing.
   ============================================================ */
/* above the book's stage (its shadow and ledge must not print on the
   hall) and below the chapters */
.world { position: absolute; inset: 0; z-index: calc(var(--z-book) + 5); pointer-events: none; opacity: 0; }
.world__gl { position: absolute; inset: 0; display: block; }

/* ---------- the direct way to the firm (Phase 5.3) ----------
   One quiet button at the head of the page: a brass hairline, small
   capitals, a light that crosses it on hover, the arrow leaning on. */
.masthead__right {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.2vw, 32px);
}
.masthead__cta {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px 10px 18px;
  overflow: hidden;
  font-family: var(--font-meta);
  font-size: var(--t-micro);
  font-weight: 600;
  letter-spacing: var(--track-meta-wide);
  text-transform: uppercase;
  color: var(--color-text-primary);
  background: linear-gradient(180deg, rgb(255 232 196 / 0.07), rgb(255 232 196 / 0.015));
  border: 1px solid rgb(201 160 96 / 0.55);
  box-shadow: inset 0 1px 0 rgb(255 236 204 / 0.08), 0 8px 24px -14px rgb(0 0 0 / 0.8);
  cursor: pointer;
  transition: border-color var(--dur-ui) var(--ease-editorial), background var(--dur-ui) var(--ease-editorial);
}
.masthead__cta::before {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, rgb(255 226 176 / 0) 30%, rgb(255 226 176 / 0.22) 50%, rgb(255 226 176 / 0) 70%);
  transform: translateX(-110%);
  transition: transform 900ms var(--ease-editorial);
  pointer-events: none;
}
.masthead__cta-a {
  display: inline-block;
  color: var(--color-accent-light, #d9b77e);
  transition: transform var(--dur-ui) var(--ease-arrive);
}
.masthead__cta:hover,
.masthead__cta:focus-visible {
  border-color: rgb(226 188 124 / 0.95);
  background: linear-gradient(180deg, rgb(255 232 196 / 0.12), rgb(255 232 196 / 0.03));
}
.masthead__cta:hover::before,
.masthead__cta:focus-visible::before { transform: translateX(110%); }
.masthead__cta:hover .masthead__cta-a,
.masthead__cta:focus-visible .masthead__cta-a { transform: translateX(4px); }
.masthead__cta:focus-visible { outline: 1px solid var(--color-accent-light, #d9b77e); outline-offset: 3px; }
.masthead__cta.is-here { opacity: 0.45; pointer-events: none; }
@media (max-width: 720px) {
  .masthead__cta { padding: 8px 12px 8px 13px; gap: 8px; }
}

/* where idle ambience is off (Firefox, low tier: see motion.js) the
   invitation draws its line a couple of times and rests */
[data-still] .invite__line { animation-iteration-count: 2; }
