/* ==========================================================================
   RSVP Atelier — design tokens
   ========================================================================== */
:root {
  --bg: #07070b;
  --bg-soft: #0d0d15;
  --bg-elevated: #131320;
  --panel: rgba(255, 255, 255, 0.05);
  --panel-strong: rgba(255, 255, 255, 0.08);
  --panel-border: rgba(255, 255, 255, 0.09);
  --ink: #f4f0e6;
  --ink-dim: rgba(244, 240, 230, 0.64);
  --ink-faint: rgba(244, 240, 230, 0.38);
  --gold: #c9a86a;
  --gold-bright: #e8c893;
  --gold-deep: #8a6d3b;
  --wine: #6e3b4f;
  --shadow-soft: 0 20px 60px -25px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 40px 100px -30px rgba(0, 0, 0, 0.7);
  --shadow-gold: 0 20px 50px -15px rgba(201, 168, 106, 0.35);
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft: cubic-bezier(0.22, 1, 0.36, 1);
  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --container: min(1280px, 92vw);
  --radius-lg: 28px;
  --radius-md: 18px;
  --radius-sm: 10px;
}

/* ==========================================================================
   Reset & base
   ========================================================================== */
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
body.no-scroll { overflow: hidden; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button, input, select { font-family: inherit; color: inherit; }
h1, h2, h3, p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

/*
 * Calm mode is a *dialling down*, never a blanket off switch.
 *
 * There used to be a `* { animation-duration: 0.001ms !important }` rule here. Because
 * Windows enables prefers-reduced-motion whenever "Animation effects" is off — very common —
 * that one line silently flattened every animation and transition on the site for a large
 * share of visitors, including the gentler calm-mode entrances written further down that
 * could never win against its !important. Anything genuinely uncomfortable (cursor-chained
 * parallax, the force field, large travel) is switched off at its own definition instead.
 */
html[data-motion="calm"] { scroll-behavior: auto; }

/* ==========================================================================
   Cinematic silk background layer (js/background.js)
   Sits behind all content via a negative z-index, so no existing element needs
   to change. The body background still paints behind it.
   ========================================================================== */
#silk-bg {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  display: block;
}

/* Subtle film-grain texture reused across dark sections */
.hero__grain {
  position: absolute; inset: 0; pointer-events: none; opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ==========================================================================
   Preloader
   ========================================================================== */
.preloader {
  position: fixed; inset: 0; z-index: 9999;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  background: var(--bg);
  transition: opacity 0.7s var(--ease), visibility 0.7s var(--ease);

  /*
   * One knob for the whole sequence. Every duration and delay below is a multiple of --lt,
   * so calm mode retimes the entire animation by changing this single value rather than
   * overriding a dozen rules.
   *
   * --loader-beats is where the sequence ends, counted in those same units. main.js reads
   * both and multiplies, so a fast `load` can't cut the animation off mid-flap.
   *
   * Deliberately two plain values rather than one calc(): getPropertyValue() hands back the
   * raw token for an unregistered custom property, so a `calc(...)` here reaches JS as the
   * literal string "calc(100ms * 39)" and parseFloat gives NaN.
   */
  --lt: 100ms;
  --loader-beats: 44;
}
.preloader.is-hidden { opacity: 0; visibility: hidden; pointer-events: none; }

/* Fixed box so the bar and label never shift as the envelope animates inside it. */
.preloader__stage {
  position: relative;
  width: 320px; height: 300px;
  display: flex; align-items: center; justify-content: center;
}

.preloader__mark {
  font-family: var(--font-display); font-size: 42px; color: var(--gold);
  width: 72px; height: 72px; border: 1px solid var(--panel-border); border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  /* Placed on the risen card's optical centre, not the stage's — the card ends high in the
     stage, and centring here would make the logo jump downward at the handoff. */
  position: absolute; top: 30%; left: 50%; margin: -36px 0 0 -36px;
  opacity: 0;
  animation:
    markIn calc(var(--lt) * 5) var(--ease-soft) calc(var(--lt) * 40) both,
    pulse-mark 2.2s ease-in-out calc(var(--lt) * 45) infinite;
}
@keyframes pulse-mark { 0%, 100% { box-shadow: 0 0 0 0 rgba(201,168,106,0.25); } 50% { box-shadow: 0 0 0 14px rgba(201,168,106,0); } }

/* The card hands off to the mark: same centre, same gold, so the swap reads as one object
   resolving rather than two elements crossfading. */
@keyframes markIn {
  from { opacity: 0; transform: scale(0.82); }
  to   { opacity: 1; transform: scale(1); }
}

/* --------------------------------------------------------------------------
   Preloader envelope

   Construction follows a real envelope, because that is what makes it read as one:
   a back panel, a dark interior, the card, a front pocket whose top edge is a
   downward V where the two side flaps meet, and a triangular flap hinged at the
   top with a wax seal at its tip. An earlier version drew the front as a plain
   rectangle and the whole thing read as two stacked shapes.

   Only transform and opacity are animated, so the sequence stays on the compositor.
   -------------------------------------------------------------------------- */
.envelope {
  position: absolute; left: 50%; bottom: 16px;
  width: 268px; height: 176px; margin-left: -134px;
  /*
   * Perspective lives here, and this element is deliberately NOT preserve-3d. Inside a
   * preserve-3d context children sort by 3D position and z-index stops working, which let
   * the opened flap paint over the card. Flat here keeps stacking predictable; the flap
   * carries its own preserve-3d for its two faces.
   */
  perspective: 1400px;
  opacity: 0;
  /*
   * Exit passes are `forwards`, never `both`. `both` back-fills an animation's `from` state
   * from time zero, so a delayed exit silently overrides the entrance for its whole delay.
   */
  animation:
    envIn  calc(var(--lt) * 8) var(--ease-soft) calc(var(--lt) * 1)  both,
    envOut calc(var(--lt) * 5) var(--ease)      calc(var(--lt) * 38) forwards;
}
@keyframes envIn {
  from { opacity: 0; transform: translateY(18px) scale(0.93); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes envOut {
  from { opacity: 1; transform: translateY(0) scale(1); }
  to   { opacity: 0; transform: translateY(-10px) scale(0.96); }
}

/*
 * Ivory stock. Grain is two opposing low-contrast repeating gradients — enough to break up
 * the fill under the sheen, no image asset, effectively free.
 */
.envelope__back,
.envelope__front,
.envelope__flap-face,
.envelope__card {
  background-color: #eae1d0;
  background-image:
    repeating-linear-gradient(58deg,  rgba(122, 98, 60, 0.04) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-52deg, rgba(122, 98, 60, 0.032) 0 1px, transparent 1px 4px),
    linear-gradient(152deg, #f8f2e6 0%, #ebe2d0 48%, #d9cdb6 100%);
}

/*
 * The flap and the body must NOT share a tone.
 *
 * When they did, the closed envelope read as a single lit rectangle with a circle on it —
 * there was no visible flap at all. A flap is a separate sheet lying on top of the body, so
 * it catches more light and casts a shadow along its two diagonal edges. That tonal step and
 * that shadow are the entire reason the eye recognises an envelope.
 */
.envelope__flap-face {
  background-image:
    repeating-linear-gradient(58deg,  rgba(122, 98, 60, 0.035) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-52deg, rgba(122, 98, 60, 0.028) 0 1px, transparent 1px 4px),
    linear-gradient(163deg, #fdf8ee 0%, #f4ecdc 55%, #e6dbc4 100%);
}
.envelope__front {
  background-image:
    repeating-linear-gradient(58deg,  rgba(110, 88, 52, 0.05) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(-52deg, rgba(110, 88, 52, 0.04) 0 1px, transparent 1px 4px),
    linear-gradient(160deg, #e6dcc7 0%, #dbd0b8 46%, #c8bb9f 100%);
}

.envelope__back {
  position: absolute; inset: 0;
  z-index: 1;
  border-radius: 3px;
  /* Warm rim light from below-left, matching the reference's lighting. */
  box-shadow:
    0 30px 66px rgba(0, 0, 0, 0.7),
    0 0 46px rgba(201, 168, 106, 0.1),
    0 0 0 1px rgba(201, 168, 106, 0.24);
}

/* The shadowed inside, seen through the pocket's V once the flap lifts. Sits above the back
   and below the card, so the card reads as sitting *in* the envelope. */
.envelope__interior {
  position: absolute; inset: 0;
  z-index: 2;
  border-radius: 3px;
  background: linear-gradient(178deg, #241d13 0%, #15110b 46%, #0d0a06 100%);
  box-shadow: inset 0 10px 22px rgba(0, 0, 0, 0.75);
}

/* The invitation. Below the front (z 3 vs 4), so only what clears the pocket is visible. */
.envelope__card {
  position: absolute; left: 7%; bottom: 8px;
  width: 86%; height: 150px;
  z-index: 3;
  border-radius: 2px;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
  padding-top: 15px; gap: 7px;
  box-shadow: 0 -8px 20px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(201, 168, 106, 0.34);
  transform: translateY(0);
  animation:
    cardRise calc(var(--lt) * 11) var(--ease-soft) calc(var(--lt) * 28) both,
    cardOut  calc(var(--lt) * 5)  var(--ease)      calc(var(--lt) * 39) forwards;
}
/* Foil rule just inside the card's edge — the detail that reads as letterpress. */
.envelope__card::before {
  content: ''; position: absolute; inset: 6px;
  border: 1px solid rgba(160, 128, 72, 0.32);
  border-radius: 1px;
}
/*
 * Rise, settle, then tilt — all in ONE animation. Separate rise and tilt animations would
 * not compose: the later `transform` simply replaces the earlier one rather than adding to
 * it, so the card would snap back to untilted before turning.
 */
@keyframes cardRise {
  0%   { transform: translateY(0) rotateY(0deg) rotateZ(0deg); }
  68%  { transform: translateY(-70%) rotateY(0deg) rotateZ(0deg); }
  100% { transform: translateY(-72%) rotateY(-11deg) rotateZ(-3.5deg); }
}
/* Starts exactly where cardRise ends, or the card jumps before it dissolves. */
@keyframes cardOut {
  from { opacity: 1; transform: translateY(-72%) rotateY(-11deg) rotateZ(-3.5deg) scale(1); }
  to   { opacity: 0; transform: translateY(-78%) rotateY(-11deg) rotateZ(-3.5deg) scale(0.93); }
}

.envelope__mono {
  font-family: var(--font-display);
  font-size: 34px; line-height: 1;
  color: #9a7a42;
}
.envelope__cardname {
  font-size: 8px; letter-spacing: 3.4px; text-transform: uppercase;
  color: rgba(122, 96, 52, 0.82);
}
.envelope__botanical {
  width: 46px; height: 26px; margin-top: 2px;
  stroke: rgba(160, 128, 72, 0.6);
  stroke-width: 1.1;
  stroke-linecap: round;
  fill: none;
}

/*
 * Front pocket. The V-shaped top edge is the single most important detail here — it is what
 * the eye reads as "envelope". With a straight top edge this is just a rectangle.
 */
.envelope__front {
  position: absolute; inset: 0;
  z-index: 4;
  clip-path: polygon(0 0, 50% 43%, 100% 0, 100% 100%, 0 100%);
  border-radius: 0 0 3px 3px;
  box-shadow:
    inset 0 0 0 1px rgba(201, 168, 106, 0.2),
    /* Vignette: paper falls off toward the lower corners instead of sitting evenly lit. */
    inset 0 -22px 34px rgba(86, 66, 34, 0.2),
    inset 0 26px 30px rgba(60, 44, 20, 0.14);
}
/* The two side-flap seams, as shadow rather than highlight — on ivory a white seam is
   invisible, which is why the earlier version showed no construction at all. */
.envelope__front::before,
.envelope__front::after {
  content: ''; position: absolute; top: 0; width: 50%; height: 100%;
}
.envelope__front::before {
  left: 0;
  background: linear-gradient(to bottom right, rgba(96, 74, 38, 0.3), transparent 54%);
}
.envelope__front::after {
  right: 0;
  background: linear-gradient(to bottom left, rgba(96, 74, 38, 0.3), transparent 54%);
}

/*
 * Flap. Hinged on its top edge, swung back past vertical but stopped short of flat so it
 * keeps some foreshortening and still reads as paper folded into depth.
 */
.envelope__flap {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 52%;
  z-index: 5;
  transform-style: preserve-3d;
  transform-origin: 50% 0;
  transform: rotateX(0deg);
  animation: flapOpen calc(var(--lt) * 8) var(--ease-soft) calc(var(--lt) * 21) both;
}
/* Past vertical the flap has folded behind the envelope, so it drops beneath every other
   layer. Only z-index steps at the midpoint; transform is declared at the ends alone so it
   still interpolates smoothly across the swing. */
@keyframes flapOpen {
  from { transform: rotateX(0deg); z-index: 5; }
  49%  { z-index: 5; }
  50%  { z-index: 0; }
  to   { transform: rotateX(-154deg); z-index: 0; }
}
.envelope__flap-face {
  position: absolute; inset: 0;
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  backface-visibility: hidden;
  /*
   * drop-shadow, not box-shadow: box-shadow draws around the element's border box and would
   * outline a rectangle, ignoring the clip entirely. drop-shadow follows the clipped
   * triangle, so the flap's two diagonal edges finally cast onto the body — which, with the
   * tonal step above, is what separates flap from envelope when it's closed.
   *
   * It sits on the faces rather than on .envelope__flap because `filter` forces
   * transform-style back to flat, which would destroy the two-face backface flip.
   */
  filter: drop-shadow(0 2px 2px rgba(48, 33, 12, 0.5));
}
/*
 * The lining's clip-path is mirrored vertically, and that is not cosmetic.
 *
 * This face carries rotateX(180deg) about its own CENTRE, which flips its clip-path; the
 * parent then rotates about the TOP EDGE, flipping it again. Two flips cancel, so an
 * unmirrored point-down triangle stayed point-down once the flap folded back — reading as a
 * detached triangle floating above the envelope rather than the flap's underside.
 */
.envelope__flap-face--lining {
  clip-path: polygon(0 100%, 100% 100%, 50% 0);
  transform: rotateX(180deg);
  background-color: #2a2118;
  background-image: linear-gradient(200deg, #201a12 0%, #33291d 55%, #1a150f 100%);
  box-shadow: inset 0 2px 6px rgba(0, 0, 0, 0.5);
}

/* Gold bloom behind the seal: builds, peaks as the seal gives way, then flares out.
   One animation covers both phases — two would fight over opacity and transform. */
.envelope__glow {
  position: absolute; left: 50%; top: 52%;
  width: 190px; height: 190px; margin: -95px 0 0 -95px;
  z-index: 6;
  pointer-events: none;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(232, 200, 147, 0.72) 0%, rgba(201, 168, 106, 0.34) 34%, rgba(201, 168, 106, 0) 68%);
  opacity: 0;
  animation: sealGlow calc(var(--lt) * 11) ease-out calc(var(--lt) * 11) forwards;
}
@keyframes sealGlow {
  0%   { opacity: 0;    transform: scale(0.5); }
  30%  { opacity: 0.5;  transform: scale(0.9); }
  55%  { opacity: 0.85; transform: scale(1.06); }
  64%  { opacity: 1;    transform: scale(1.16); }
  100% { opacity: 0;    transform: scale(2.4); }
}

/* Wax seal at the flap's tip. Kept out of the flap so it can break *before* the flap opens,
   as in the reference, rather than riding the rotation. */
.envelope__seal {
  position: absolute; left: 50%; top: 52%;
  width: 40px; height: 40px; margin: -20px 0 0 -20px;
  z-index: 7;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 28%, #f0d5a2 0%, #cfae70 40%, #8a6d3b 78%, #6d5329 100%);
  box-shadow:
    inset 0 1px 2px rgba(255, 246, 224, 0.62),
    inset 0 -3px 6px rgba(64, 46, 18, 0.55),
    0 4px 10px rgba(0, 0, 0, 0.5);
  animation: sealBreak calc(var(--lt) * 4) var(--ease) calc(var(--lt) * 18) forwards;
}
.envelope__seal::after {
  content: ''; position: absolute; inset: 5px;
  border-radius: 50%;
  border: 1px solid rgba(94, 70, 32, 0.45);
}
.envelope__seal-mark {
  font-family: var(--font-display);
  font-size: 19px; line-height: 1;
  color: #5c4520;
  text-shadow: 0 1px 0 rgba(255, 238, 205, 0.4);
}
@keyframes sealBreak {
  from { opacity: 1; transform: scale(1); }
  to   { opacity: 0; transform: scale(1.22); }
}

/*
 * Sheen. .envelope__gloss is a separate clipping box precisely so the envelope itself can
 * stay overflow:visible and let the card rise out of the top.
 */
.envelope__gloss {
  position: absolute; inset: 0;
  z-index: 8;
  overflow: hidden;
  border-radius: 3px;
  pointer-events: none;
}
.envelope__sheen {
  position: absolute; top: -60%; left: 0;
  width: 44%; height: 220%;
  background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,252,244,0.46) 48%, rgba(255,255,255,0) 100%);
  transform: translateX(-180%) rotate(18deg);
  animation: sheenSweep calc(var(--lt) * 9) var(--ease-soft) calc(var(--lt) * 8) both;
}
@keyframes sheenSweep {
  from { transform: translateX(-180%) rotate(18deg); opacity: 0; }
  22%  { opacity: 1; }
  78%  { opacity: 1; }
  to   { transform: translateX(320%) rotate(18deg); opacity: 0; }
}

/*
 * Calm mode retimes the whole sequence via --lt and softens the two loudest moments: the
 * seal's flare and the card's tilt. It is not switched off — the envelope opening *is* the
 * loader, so removing it would leave a blank screen rather than a calmer one.
 */
html[data-motion="calm"] .preloader { --lt: 62ms; }
html[data-motion="calm"] .envelope__sheen {
  background: linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,252,244,0.24) 48%, rgba(255,255,255,0) 100%);
}
html[data-motion="calm"] .envelope__glow { animation-name: sealGlowCalm; }
html[data-motion="calm"] .envelope__flap { animation-name: flapOpenCalm; }
html[data-motion="calm"] .envelope__card { animation-name: cardRiseCalm, cardOutCalm; }
@keyframes sealGlowCalm {
  0%   { opacity: 0;   transform: scale(0.6); }
  55%  { opacity: 0.5; transform: scale(1); }
  64%  { opacity: 0.6; transform: scale(1.06); }
  100% { opacity: 0;   transform: scale(1.5); }
}
@keyframes flapOpenCalm {
  from { transform: rotateX(0deg); z-index: 5; }
  49%  { z-index: 5; }
  50%  { z-index: 0; }
  to   { transform: rotateX(-146deg); z-index: 0; }
}
@keyframes cardRiseCalm {
  0%   { transform: translateY(0) rotateZ(0deg); }
  72%  { transform: translateY(-74%) rotateZ(0deg); }
  100% { transform: translateY(-76%) rotateZ(-1.5deg); }
}
/* Must start exactly where cardRiseCalm ends, or the card snaps before it dissolves. */
@keyframes cardOutCalm {
  from { opacity: 1; transform: translateY(-76%) rotateZ(-1.5deg) scale(1); }
  to   { opacity: 0; transform: translateY(-80%) rotateZ(-1.5deg) scale(0.95); }
}

.preloader__bar { width: 220px; height: 2px; background: var(--panel-border); border-radius: 2px; overflow: hidden; }
.preloader__bar span { display: block; height: 100%; width: 0%; background: linear-gradient(90deg, var(--gold-deep), var(--gold-bright)); transition: width 0.25s var(--ease); }
.preloader__label { font-size: 12px; letter-spacing: 3px; text-transform: uppercase; color: var(--ink-faint); }

/* ==========================================================================
   Custom cursor + scroll progress
   ========================================================================== */
/*
 * The native cursor is hidden only once main.js has added this class, so a visitor without
 * JS is never left with no pointer at all. `html.has-custom-cursor *` outscores the
 * `cursor: pointer` on buttons and pills on specificity alone — no !important needed.
 */
html.has-custom-cursor,
html.has-custom-cursor *,
html.has-custom-cursor *::before,
html.has-custom-cursor *::after { cursor: none; }

/*
 * One gold arrow, tracking the pointer exactly — no easing, so a click always lands where
 * the tip is pointing. Deliberately the whole of it: a ring, trail and ripple were built
 * here first and read as clutter over a page that already has its own motion.
 */
.cursor-arrow {
  position: fixed; top: 0; left: 0;
  pointer-events: none;
  z-index: 9999;
  opacity: 0;
  transition: opacity 0.35s var(--ease);
  will-change: transform;
}
.cursor-arrow.is-visible { opacity: 1; }
.cursor-arrow svg { display: block; width: 21px; height: 23px; overflow: visible; }
.cursor-arrow path {
  fill: #fdf4dd;
  stroke: rgba(150, 116, 54, 0.5);
  stroke-width: 0.5;
  stroke-linejoin: round;
  /* drop-shadow, not box-shadow: the bloom has to follow the arrow's silhouette, and
     box-shadow would halo a rectangle around it. Two passes give a tight core and a
     wider, softer falloff. */
  filter:
    drop-shadow(0 0 3px rgba(255, 238, 199, 0.95))
    drop-shadow(0 0 9px rgba(232, 200, 147, 0.65))
    drop-shadow(0 0 20px rgba(201, 168, 106, 0.4));
}

@media (pointer: coarse) {
  .cursor-arrow { display: none; }
}

.scroll-progress { position: fixed; top: 0; left: 0; height: 2px; width: 0%; background: linear-gradient(90deg, var(--gold-deep), var(--gold-bright)); z-index: 500; }

/* ==========================================================================
   Nav
   ========================================================================== */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 400;
  display: flex; align-items: center; justify-content: space-between;
  padding: 26px clamp(20px, 5vw, 64px);
  transition: padding 0.4s var(--ease), background 0.4s var(--ease), backdrop-filter 0.4s var(--ease);
}
.nav.is-scrolled {
  padding-top: 14px; padding-bottom: 14px;
  background: rgba(7, 7, 11, 0.7); backdrop-filter: blur(16px) saturate(140%);
  border-bottom: 1px solid var(--panel-border);
}
.nav__brand { font-family: var(--font-display); font-size: 20px; letter-spacing: 1px; }
.nav__brand span { color: var(--gold); }
.nav__links { display: flex; align-items: center; gap: clamp(16px, 3vw, 36px); font-size: 14px; }
.nav__links a { color: var(--ink-dim); transition: color 0.25s; position: relative; }
.nav__links a:hover { color: var(--ink); }
.nav__admin {
  border: 1px solid var(--panel-border); padding: 8px 18px; border-radius: 999px;
  color: var(--gold) !important;
}
.nav__admin:hover { border-color: var(--gold); }

/* ==========================================================================
   Buttons, pills, chips
   ========================================================================== */
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 15px 30px; border-radius: 999px; border: 1px solid transparent;
  font-size: 14px; font-weight: 600; letter-spacing: 0.3px; cursor: pointer;
  transition: transform 0.35s var(--ease), box-shadow 0.35s var(--ease), border-color 0.3s, background 0.3s;
}
.btn--sm { padding: 10px 20px; font-size: 13px; }
.btn--gold { background: linear-gradient(135deg, var(--gold-bright), var(--gold-deep)); color: #1a1206; }
.btn--gold:hover { transform: translateY(-2px); box-shadow: var(--shadow-gold); }
.btn--ghost { background: var(--panel); border-color: var(--panel-border); color: var(--ink); backdrop-filter: blur(10px); }
.btn--ghost:hover { border-color: var(--gold); transform: translateY(-2px); }
.btn--outline {
  background: transparent; border-color: var(--panel-border); color: var(--ink-dim);
}
.btn--outline:hover { border-color: var(--gold); color: var(--ink); transform: translateY(-2px); }

/* Arrow nudges forward on hover — a small, restrained bit of feedback. */
.btn__arrow { font-style: normal; display: inline-block; transition: transform 0.35s var(--ease); }
.btn:hover .btn__arrow { transform: translateX(4px); }

.pill {
  padding: 9px 18px; border-radius: 999px; border: 1px solid var(--panel-border);
  background: var(--panel); color: var(--ink-dim); font-size: 13px; cursor: pointer;
  transition: all 0.3s var(--ease);
}
.pill em { font-style: normal; opacity: 0.55; margin-left: 4px; }
.pill:hover { color: var(--ink); border-color: var(--gold); }
.pill.is-active { background: linear-gradient(135deg, var(--gold-bright), var(--gold-deep)); color: #1a1206; border-color: transparent; }

.chip {
  display: inline-block; padding: 5px 12px; margin: 0 6px 6px 0; border-radius: 999px;
  font-size: 11px; letter-spacing: 0.4px; text-transform: uppercase;
  background: var(--panel); border: 1px solid var(--panel-border); color: var(--ink-dim);
}

/* ==========================================================================
   Hero
   ========================================================================== */
.hero {
  position: relative; min-height: 100vh; display: flex; flex-direction: column;
  align-items: flex-start; justify-content: center; text-align: left; overflow: hidden;
  padding: 170px clamp(24px, 7vw, 104px) 70px;
}

/* Vertical "Scroll" rail down the left margin. */
.hero__rail {
  position: absolute; left: clamp(12px, 3.2vw, 46px); top: 50%; transform: translateY(-50%);
  z-index: 2; display: flex; flex-direction: column; align-items: center; gap: 16px;
}
.hero__rail-line { width: 1px; height: 92px; background: linear-gradient(var(--gold), transparent); }
.hero__rail-word {
  writing-mode: vertical-rl; font-size: 10px; letter-spacing: 4px;
  text-transform: uppercase; color: var(--ink-faint);
}
.hero__rail-dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--gold);
  box-shadow: 0 0 12px var(--gold); animation: railPulse 2.6s ease-in-out infinite;
}
@keyframes railPulse { 0%, 100% { opacity: 0.35; transform: scale(0.8); } 50% { opacity: 1; transform: scale(1); } }
.hero__aurora { position: absolute; inset: -20%; z-index: 0; filter: blur(70px); }
.blob { position: absolute; border-radius: 50%; opacity: 0.55; will-change: transform; }
.blob--1 { width: 46vw; height: 46vw; top: 5%; left: 5%; background: radial-gradient(circle, var(--gold-deep), transparent 70%); animation: drift-1 22s ease-in-out infinite; }
.blob--2 { width: 38vw; height: 38vw; bottom: 0%; right: 8%; background: radial-gradient(circle, var(--wine), transparent 70%); animation: drift-2 26s ease-in-out infinite; }
.blob--3 { width: 30vw; height: 30vw; top: 40%; left: 40%; background: radial-gradient(circle, var(--gold-bright), transparent 70%); opacity: 0.28; animation: drift-3 18s ease-in-out infinite; }
@keyframes drift-1 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(6%, 8%) scale(1.1); } }
@keyframes drift-2 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(-8%, -6%) scale(1.15); } }
@keyframes drift-3 { 0%, 100% { transform: translate(0, 0) scale(1); } 50% { transform: translate(-10%, 10%) scale(0.9); } }

/* Wax-sealed envelope — the composition's right-hand anchor. Sits at a slight angle,
   breathes on a slow loop, and leads the mouse parallax. */
.hero__seal-wrap {
  position: absolute; z-index: 1; right: clamp(-30px, 3vw, 96px); top: 50%;
  width: clamp(260px, 30vw, 420px); aspect-ratio: 440 / 480;
  transform: translateY(-50%); perspective: 1100px; pointer-events: none;
}
.hero__seal {
  width: 100%; height: 100%; transform-style: preserve-3d; will-change: transform;
  rotate: -7deg;
  filter:
    drop-shadow(0 42px 70px rgba(0, 0, 0, 0.72))
    drop-shadow(0 0 90px rgba(201, 168, 106, 0.14));
  animation: sealFloat 11s ease-in-out infinite;
}
@keyframes sealFloat {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -18px; }
}
/* The envelope keeps floating in calm mode — slower, and over a third of the distance. */
@keyframes sealFloatCalm {
  0%, 100% { translate: 0 0; }
  50% { translate: 0 -6px; }
}
html[data-motion="calm"] .hero__seal { animation: sealFloatCalm 17s ease-in-out infinite; }

.hero__content { position: relative; z-index: 2; max-width: 660px; }
.hero__eyebrow { font-size: 13px; letter-spacing: 4px; text-transform: uppercase; color: var(--gold); margin-bottom: 22px; }
.hero__title {
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(48px, 9vw, 110px); line-height: 0.98; letter-spacing: -1px;
  display: flex; flex-direction: column; gap: 4px;
}
.hero__title--script { font-style: italic; color: var(--gold-bright); }
.hero__sub { margin: 28px 0 0; max-width: 470px; color: var(--ink-dim); font-size: clamp(14.5px, 1.5vw, 16.5px); line-height: 1.75; }
.hero__cta { margin-top: 40px; display: flex; gap: 14px; flex-wrap: wrap; }

/* Stats sit in their own glass plate rather than floating loose. */
.hero__stats {
  position: relative; z-index: 2; margin-top: clamp(48px, 7vw, 82px); width: 100%;
  max-width: 720px; display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(14px, 2.4vw, 30px);
  padding: clamp(18px, 2.4vw, 28px) clamp(20px, 3vw, 36px);
  border: 1px solid var(--panel-border); border-radius: var(--radius-md);
  background: linear-gradient(135deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.015));
  backdrop-filter: blur(14px); box-shadow: var(--shadow-lg);
}
.stat { display: flex; align-items: center; gap: 13px; text-align: left; }
.stat + .stat { border-left: 1px solid var(--panel-border); padding-left: clamp(14px, 2.4vw, 30px); }
.stat__icon {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; font-size: 13px;
  color: var(--gold-bright); border: 1px solid rgba(201, 168, 106, 0.32);
  background: linear-gradient(135deg, rgba(232, 200, 147, 0.16), rgba(138, 109, 59, 0.14));
}
.stat__text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.stat__num { font-family: var(--font-display); font-size: clamp(22px, 2.6vw, 30px); line-height: 1; color: var(--gold-bright); }
.stat__label { font-size: 10px; letter-spacing: 1.4px; text-transform: uppercase; color: var(--ink-faint); line-height: 1.4; }

.hero__scroll-cue { position: absolute; bottom: 34px; left: 50%; transform: translateX(-50%); z-index: 2; }
.hero__scroll-cue span { display: block; width: 1px; height: 46px; background: linear-gradient(var(--gold), transparent); animation: cue 2s ease-in-out infinite; }
@keyframes cue { 0% { opacity: 0; transform: scaleY(0.4); transform-origin: top; } 50% { opacity: 1; } 100% { opacity: 0; transform: scaleY(1); transform-origin: bottom; } }

/* ==========================================================================
   Sections
   ========================================================================== */
.section {
  position: relative; max-width: var(--container); margin: 0 auto;
  padding: 100px clamp(24px, 7vw, 104px);
}
/* Editorial head: headings left, a single action pinned right. */
.section__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 28px; margin: 0 0 44px; flex-wrap: wrap;
}
.section__headings { max-width: 640px; }
.section__eyebrow { font-size: 11px; letter-spacing: 4px; text-transform: uppercase; color: var(--gold); margin-bottom: 12px; }
.section__title { font-family: var(--font-display); font-weight: 500; font-size: clamp(28px, 3.6vw, 44px); line-height: 1.12; }
.section__lead { margin-top: 12px; color: var(--ink-faint); font-size: 14.5px; max-width: 46ch; }
.section__action { flex-shrink: 0; }

.section--about { padding-bottom: 0; }
.section--about .section__head { margin-bottom: 0; }

/* ==========================================================================
   Toolbar
   ========================================================================== */
.toolbar {
  display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
  margin-bottom: 46px; padding: 18px 22px; border-radius: var(--radius-md);
  background: var(--panel); border: 1px solid var(--panel-border); backdrop-filter: blur(14px);
}
.toolbar__filters { display: flex; gap: 10px; flex-wrap: wrap; }
.toolbar__controls { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.toggle { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-dim); cursor: pointer; }
.toggle input { accent-color: var(--gold); width: 16px; height: 16px; }
.select, .search input {
  background: var(--bg-elevated); border: 1px solid var(--panel-border); color: var(--ink);
  padding: 9px 14px; border-radius: 999px; font-size: 13px; outline: none;
  transition: border-color 0.25s;
}
.select:focus, .search input:focus { border-color: var(--gold); }
.search input { width: 220px; }

/* ==========================================================================
   Cards & grids
   ========================================================================== */
/* ==========================================================================
   Featured showcase — one large cinematic panel per project, swiped horizontally.
   Scroll-snap does the work so it stays smooth and needs no drag library.
   ========================================================================== */
.showcase { position: relative; }
.showcase__track {
  display: flex; gap: 22px; overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  padding-bottom: 4px;
}
.showcase__track::-webkit-scrollbar { display: none; }

/*
 * Split panel rather than text-over-image: these thumbnails are screenshots of real
 * landing pages, so they carry their own large typography. Overlaying our title on top
 * of theirs made both unreadable. Copy gets its own column; the artwork gets its own.
 */
.showcase-item {
  position: relative; flex: 0 0 100%; scroll-snap-align: center;
  border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--panel-border); background: var(--bg-elevated);
  box-shadow: var(--shadow-lg); min-height: clamp(340px, 40vw, 440px);
  display: grid; grid-template-columns: 0.86fr 1.14fr; align-items: center;
}
/* All three share row 1; artwork and its feather sit in column 2, copy in column 1. */
.showcase-item__media {
  grid-column: 2; grid-row: 1; position: relative; align-self: stretch; overflow: hidden;
}
.showcase-item__media img { width: 100%; height: 100%; object-fit: cover; object-position: center top; }
/* Feathers the artwork into the copy column so the seam never reads as a hard cut. */
.showcase-item__scrim {
  grid-column: 2; grid-row: 1; align-self: stretch; z-index: 2; pointer-events: none;
  background: linear-gradient(90deg, var(--bg-elevated) 0%, rgba(18, 17, 26, 0.5) 18%, transparent 46%);
}
.showcase-item__body {
  grid-column: 1; grid-row: 1; position: relative; z-index: 3;
  padding: clamp(26px, 3.4vw, 46px);
}
.showcase-item__badge {
  display: inline-block; padding: 7px 15px; border-radius: 999px; font-size: 10.5px;
  letter-spacing: 1.5px; text-transform: uppercase; color: var(--ink);
  background: rgba(10, 10, 16, 0.62); border: 1px solid var(--panel-border);
  backdrop-filter: blur(10px); margin-bottom: 18px;
}
.showcase-item__title { font-family: var(--font-display); font-size: clamp(28px, 4vw, 46px); line-height: 1.05; }
.showcase-item__desc { margin-top: 12px; color: var(--ink-dim); font-size: 14.5px; max-width: 42ch; }
.showcase-item__actions { margin-top: 24px; display: flex; gap: 12px; flex-wrap: wrap; }
.showcase-item__date {
  position: absolute; right: clamp(18px, 3vw, 34px); bottom: clamp(18px, 3vw, 30px); z-index: 2;
  font-size: 11px; letter-spacing: 1.6px; text-transform: uppercase; color: var(--ink-faint);
}

.showcase__dots { display: flex; gap: 8px; justify-content: center; margin-top: 22px; }
.showcase__dot {
  width: 26px; height: 3px; border-radius: 999px; border: 0; padding: 0; cursor: pointer;
  background: var(--panel-border); transition: background 0.35s var(--ease), width 0.35s var(--ease);
}
.showcase__dot.is-active { width: 40px; background: linear-gradient(90deg, var(--gold-bright), var(--gold-deep)); }
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 26px; }

.card {
  position: relative; border-radius: var(--radius-lg); overflow: hidden;
  background: var(--bg-elevated); border: 1px solid var(--panel-border);
  box-shadow: var(--shadow-soft);
  transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 0.4s var(--ease-soft), box-shadow 0.4s var(--ease-soft), border-color 0.4s;
  display: flex; flex-direction: column;
}
.card:hover { box-shadow: var(--shadow-lg); border-color: rgba(201, 168, 106, 0.4); }
.card--featured { grid-column: span 1; }
.card--featured .card__media { aspect-ratio: 16 / 10; }

.card__media { position: relative; aspect-ratio: 4 / 3; overflow: hidden; background: linear-gradient(135deg, #1a1a2e, #3a2a1a); }
/* Anchor to the top: these are landing-page captures, so the hero/title matters most. */
.card__media img {
  width: 100%; height: 100%; object-fit: cover; object-position: center top;
  transition: transform 0.7s var(--ease-soft);
}
.card:hover .card__media img { transform: scale(1.07); }
.card__glow { position: absolute; inset: 0; background: linear-gradient(to top, rgba(0,0,0,0.65), transparent 55%); pointer-events: none; }
.card__badge {
  position: absolute; top: 14px; left: 14px; padding: 6px 14px; border-radius: 999px;
  background: rgba(7,7,11,0.55); backdrop-filter: blur(8px); border: 1px solid rgba(255,255,255,0.15);
  font-size: 11px; letter-spacing: 0.5px; text-transform: uppercase;
}

.card__body { padding: 26px; display: flex; flex-direction: column; gap: 12px; flex: 1; }
.card__meta { display: flex; justify-content: space-between; font-size: 12px; letter-spacing: 1px; text-transform: uppercase; color: var(--gold); }
.card__title { font-family: var(--font-display); font-size: clamp(20px, 2.4vw, 26px); font-weight: 500; }
.card__desc { color: var(--ink-dim); font-size: 14px; flex: 1; }
.card__tags { display: flex; flex-wrap: wrap; }
.card__actions { display: flex; margin-top: auto; padding-top: 16px; }
.card__actions .btn { width: 100%; justify-content: space-between; }

/* ==========================================================================
   Empty state
   ========================================================================== */
.empty-state { text-align: center; padding: 80px 0; color: var(--ink-faint); font-size: 15px; }

/* ==========================================================================
   Modal
   ========================================================================== */
.modal { position: fixed; inset: 0; z-index: 2000; display: flex; align-items: center; justify-content: center; visibility: hidden; opacity: 0; transition: opacity 0.35s var(--ease), visibility 0.35s var(--ease); padding: 24px; }
.modal.is-open { visibility: visible; opacity: 1; }
.modal__scrim { position: absolute; inset: 0; background: rgba(4,4,7,0.75); backdrop-filter: blur(10px); }
.modal__panel {
  position: relative; z-index: 1; width: min(920px, 100%); max-height: 88vh; overflow-y: auto;
  background: var(--bg-elevated); border: 1px solid var(--panel-border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); display: grid; grid-template-columns: 1fr 1fr;
  transform: scale(0.94) translateY(20px); transition: transform 0.4s var(--ease-soft);
}
.modal.is-open .modal__panel { transform: scale(1) translateY(0); }
.modal__close { position: absolute; top: 16px; right: 16px; z-index: 2; width: 38px; height: 38px; border-radius: 50%; border: 1px solid var(--panel-border); background: rgba(7,7,11,0.6); color: var(--ink); font-size: 20px; cursor: pointer; }
.modal__media { position: relative; min-height: 260px; }
.modal__media img { width: 100%; height: 100%; object-fit: cover; object-position: center top; }
.modal__body { padding: 40px; display: flex; flex-direction: column; gap: 14px; }
.modal__meta { display: flex; gap: 16px; font-size: 12px; letter-spacing: 1px; text-transform: uppercase; color: var(--gold); }
.modal__title { font-family: var(--font-display); font-size: clamp(24px, 3vw, 32px); }
.modal__desc { color: var(--ink-dim); font-size: 15px; }
.modal__row { display: flex; gap: 30px; }
.modal__field { display: flex; flex-direction: column; gap: 4px; font-size: 14px; }
.modal__field-label { font-size: 11px; letter-spacing: 1px; text-transform: uppercase; color: var(--ink-faint); }
.modal__features ul { margin-top: 6px; display: flex; flex-direction: column; gap: 6px; }
.modal__features li { font-size: 14px; color: var(--ink-dim); padding-left: 18px; position: relative; }
.modal__features li::before { content: '✦'; position: absolute; left: 0; color: var(--gold); font-size: 11px; top: 3px; }
.modal__actions { margin-top: 10px; display: flex; gap: 12px; flex-wrap: wrap; }

@media (max-width: 760px) {
  .modal__panel { grid-template-columns: 1fr; }
  .modal__media { min-height: 200px; }
}

/* ==========================================================================
   Contact
   ========================================================================== */
.section--contact { padding-top: 40px; }
/* CTA band + contact methods */
.cta-band {
  display: flex; align-items: center; justify-content: space-between; gap: clamp(28px, 5vw, 70px);
  flex-wrap: wrap; padding: clamp(32px, 4.5vw, 58px);
  border-radius: var(--radius-lg); border: 1px solid var(--panel-border);
  background:
    radial-gradient(70% 90% at 10% 10%, rgba(201, 168, 106, 0.14), transparent 60%),
    radial-gradient(60% 80% at 92% 96%, rgba(110, 59, 79, 0.26), transparent 62%),
    var(--bg-elevated);
  box-shadow: var(--shadow-lg);
}
.cta-band__title { font-family: var(--font-display); font-weight: 500; font-size: clamp(28px, 4vw, 46px); line-height: 1.12; }
.cta-band__aside { display: flex; flex-direction: column; gap: 18px; align-items: flex-start; }
.cta-band__aside p { color: var(--ink-faint); font-size: 14px; line-height: 1.7; }

.contact-methods {
  margin-top: 22px; display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px;
}
.contact-method {
  display: flex; align-items: center; gap: 15px; padding: 16px 20px;
  border-radius: var(--radius-md); border: 1px solid var(--panel-border);
  background: rgba(255, 255, 255, 0.035); backdrop-filter: blur(10px);
  transition: transform 0.3s var(--ease), border-color 0.3s, background 0.3s;
}
.contact-method:hover {
  transform: translateY(-3px); border-color: rgba(201, 168, 106, 0.5);
  background: rgba(255, 255, 255, 0.065);
}
.contact-method__icon {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, rgba(232, 200, 147, 0.2), rgba(138, 109, 59, 0.2));
  border: 1px solid rgba(201, 168, 106, 0.32); color: var(--gold-bright); font-size: 15px;
}
.contact-method__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.contact-method__label { font-size: 10px; letter-spacing: 1.5px; text-transform: uppercase; color: var(--ink-faint); }
.contact-method__value { font-size: 14px; color: var(--ink); word-break: break-word; }

/* ==========================================================================
   Footer
   ========================================================================== */
.footer {
  display: flex; align-items: center; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  padding: 42px clamp(24px, 7vw, 104px); margin-top: 90px;
  border-top: 1px solid var(--panel-border); color: var(--ink-faint);
}
.footer__brand { font-family: var(--font-display); font-size: 19px; color: var(--ink-dim); }
.footer__brand span { color: var(--gold); }
.footer__tagline { font-size: 12px; letter-spacing: 0.6px; margin-top: 4px; }
.footer__legal { font-size: 12.5px; }
.footer__social { display: flex; gap: 10px; }
.footer__social a {
  width: 38px; height: 38px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--panel-border); color: var(--ink-faint);
  transition: color 0.3s, border-color 0.3s, transform 0.3s var(--ease);
}
.footer__social a:hover { color: var(--gold-bright); border-color: var(--gold); transform: translateY(-2px); }

/* ==========================================================================
   Scroll reveal
   ========================================================================== */
.reveal { opacity: 0; transform: translateY(34px); transition: opacity 0.9s var(--ease) calc(var(--i, 0) * 70ms), transform 0.9s var(--ease) calc(var(--i, 0) * 70ms); }
.reveal.is-visible { opacity: 1; transform: none; }

/* ==========================================================================
   Hero entrance
   Plays on every load once the preloader clears. The hero's .reveal elements are
   deliberately excluded from the scroll observer (see main.js) so they stay hidden
   behind the preloader and then arrive as one composed, staggered sequence instead
   of having already animated out of sight.
   .hero--intro is added by JS, so without JS nothing is left hidden.
   ========================================================================== */
.hero--intro .hero__scroll-cue { opacity: 0; }

.hero--intro.is-ready .hero__eyebrow { animation: heroEyebrow 1.1s var(--ease) 0.10s both; }
.hero--intro.is-ready .hero__sub { animation: heroRise 1.1s var(--ease) 1.16s both; }
.hero--intro.is-ready .hero__cta { animation: heroRise 1.1s var(--ease) 1.30s both; }
.hero--intro.is-ready .hero__stats { animation: heroRise 1.1s var(--ease) 1.46s both; }
.hero--intro.is-ready .hero__scroll-cue { animation: heroFade 1s var(--ease) 1.72s both; }

/* --------------------------------------------------------------------------
   Title wave (markup built by splitHeroTitle in main.js)

   Each character is its own inline-block so it can be transformed individually;
   `.word` keeps a run of them unbreakable so the line still wraps between words
   and never mid-word.

   The perspective lives on the line rather than on each character — sharing one
   vanishing point is what makes the letters read as one sheet of type tipping up
   together, instead of each glyph rotating about its own centre.
   -------------------------------------------------------------------------- */
.hero__title .word { display: inline-block; white-space: nowrap; }
.hero__line { display: block; perspective: 620px; }
.hero__title .char {
  display: inline-block;
  transform-origin: 50% 100%;
  will-change: transform, opacity, filter;
}
/* Held back until .is-ready so the wave can't be spent behind the preloader. */
.hero--intro .hero__title .char { opacity: 0; }
.hero--intro.is-ready .hero__title .char {
  animation: heroChar 1.15s var(--ease-soft) both;
  animation-delay: calc(0.24s + var(--ci) * 34ms);
}

/*
 * Each letter rises out of soft focus and tips upright. The blur is what sells it as
 * cinematic focus-pull rather than a plain slide, and the small rotateX gives the wave
 * its crest — a pure translate reads mechanical at this size.
 */
@keyframes heroChar {
  from { opacity: 0; transform: translateY(0.42em) rotateX(-58deg); filter: blur(11px); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: none; filter: blur(0); }
}

/* Tracking settles inward — the type feels like it's coming to rest. */
@keyframes heroEyebrow {
  from { opacity: 0; transform: translateY(14px); letter-spacing: 11px; }
  to   { opacity: 1; transform: none; letter-spacing: 4px; }
}

@keyframes heroRise {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}

@keyframes heroFade { from { opacity: 0; } to { opacity: 1; } }

/*
 * Calm mode still gets an entrance — just a calm one.
 * Only the animation NAME and DURATION are overridden, so every element keeps the stagger
 * delay from the rules above and the sequence still reads as one composed arrival.
 * What's dropped is the blur, the tip and the large travel; a short rise remains.
 */
html[data-motion="calm"] .hero--intro.is-ready .hero__eyebrow,
html[data-motion="calm"] .hero--intro.is-ready .hero__sub,
html[data-motion="calm"] .hero--intro.is-ready .hero__cta,
html[data-motion="calm"] .hero--intro.is-ready .hero__stats {
  animation-name: heroCalmIn;
  animation-duration: 0.85s;
  filter: none;
}

/*
 * The wave survives calm mode, at roughly half the travel and no focus pull. Its per-letter
 * step is tightened to 22ms so the crest passes through the title quickly instead of
 * drawing attention to itself.
 */
html[data-motion="calm"] .hero--intro.is-ready .hero__title .char {
  animation-name: heroCharCalm;
  animation-duration: 0.7s;
  animation-delay: calc(0.2s + var(--ci) * 22ms);
  filter: none;
}

@keyframes heroCalmIn {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}

@keyframes heroCharCalm {
  from { opacity: 0; transform: translateY(0.16em); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   Responsive
   ========================================================================== */
@media (max-width: 640px) {
  .nav { padding: 18px 20px; }
  .nav__links { gap: 14px; font-size: 13px; }
  .hero { padding-top: 130px; }
  .toolbar { flex-direction: column; align-items: stretch; }
  .toolbar__controls { justify-content: space-between; }
  .search input { width: 100%; }
}

@media (max-width: 900px) {
  /* The pinned action drops under the headings rather than squeezing them. */
  .section__head { align-items: flex-start; }
  .cta-band { flex-direction: column; align-items: flex-start; }
  .footer { justify-content: center; text-align: center; }
  .footer__col { width: 100%; }
}

@media (max-width: 560px) {
  .nav { padding: 16px 18px; }
  .nav__brand { font-size: 17px; }
  /* The brand and four links collide at phone widths. Drop the section links — the
     hero's own CTAs already lead there — and keep the bar to brand + Contact. */
  .nav__links a:not(.nav__admin) { display: none; }
  .nav__admin { padding: 8px 17px; font-size: 12.5px; }

  .hero { padding-left: 58px; padding-right: 22px; }
  .hero__rail { left: 14px; }
  /* The seal would crowd the type at phone widths — let it sit behind, large and faint,
     and low enough that it never collides with the nav. */
  .hero__seal-wrap { right: -34%; top: 42%; width: 82vw; opacity: 0.24; }

  /* Stack the plate: three columns is too tight for the icon + number + label rows. */
  .hero__stats { grid-template-columns: 1fr; gap: 14px; }
  .stat + .stat {
    border-left: 0; padding-left: 0; padding-top: 14px;
    border-top: 1px solid var(--panel-border);
  }

  /* Stack: artwork on top, copy beneath. */
  .showcase-item { grid-template-columns: 1fr; min-height: 0; }
  .showcase-item__media { grid-column: 1; grid-row: 1; height: 190px; }
  .showcase-item__scrim {
    grid-column: 1; grid-row: 1;
    background: linear-gradient(180deg, transparent 45%, var(--bg-elevated) 100%);
  }
  .showcase-item__body { grid-column: 1; grid-row: 2; }
  .showcase-item__date { display: none; }

  .card__badge { font-size: 10px; padding: 6px 12px; max-width: calc(100% - 32px); }
}
