/* ============================================================================
   AJID review site: shared components
   Nav (three colourings + phone menu), inquire band, footer, buttons, text
   links, image frames, section transitions (seams, shelves, tray), scroll cue.
   Source for each block is noted; values come from tokens.css.
   ========================================================================= */

/* ---- Logo ------------------------------------------------------------------
   <svg class="logo" viewBox="0 0 178.4 103.2" role="img" aria-label="…">
     <use href="#ajid-logo"></use></svg>
   The symbol itself sits once at the top of each page's <body> (copied from
   assets/img/ajid-logo-sprite.svg); an external file reference did not render.
   Colours come from --logo-mark / --logo-accent, so each context below
   recolours it without a second file. */
.logo { display: block; width: 100%; height: auto; }
.logo__mark   { fill: var(--logo-mark); }
.logo__accent { fill: var(--logo-accent); }
.logo--knockout { --logo-mark: var(--d-display); --logo-accent: var(--d-display); }

/* ============================================================================
   NAV  (base = light; source: Buckminster v4 / Praise v3e / Home v6)
   Markup order: logo, burger, menu, CTA. The burger comes before the menu so
   that, on phones, Tab moves from the burger straight into the open menu.
   ========================================================================= */
.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 90;
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  padding: 26px var(--gut);
  transition:
    padding var(--dur-chrome) var(--ease),
    background var(--dur-chrome) var(--ease),
    box-shadow var(--dur-chrome) var(--ease),
    -webkit-backdrop-filter var(--dur-chrome) var(--ease),
    backdrop-filter var(--dur-chrome) var(--ease);
}
.nav.is-stuck {
  padding-block: 12px;
  background: color-mix(in srgb, var(--relief) 92%, transparent);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  backdrop-filter: saturate(140%) blur(14px);
  box-shadow: 0 1px 0 var(--r-hairline);
}
.nav__logo {
  position: relative; z-index: 2;       /* stays above the open phone menu */
  width: 104px; flex: none;
  transition: width var(--dur-chrome) var(--ease);
}
.nav.is-stuck .nav__logo { width: 78px; }

.nav__menu {
  display: flex; align-items: center; gap: clamp(14px, 2vw, 30px);
  margin-left: auto;
  font-size: var(--size-eyebrow); letter-spacing: .2em; text-transform: uppercase;
}
.nav__menu a {
  position: relative; padding-block: 6px;
  color: var(--r-ink-2);
  transition: color var(--dur-micro) var(--ease);
}
.nav__menu a::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform var(--dur-chrome) var(--ease);
}
.nav__menu a:hover::after,
.nav__menu a[aria-current]::after { transform: scaleX(1); transform-origin: left; }
.nav.is-top .nav__menu a { color: var(--r-ink); }
.nav__menu-cta { display: none; }       /* "Inquire" inside the phone menu */
.nav__menu-sub { display: none; }       /* "Collaborate", a small secondary link in the phone menu (2026-10-02) */

.nav__cta {
  flex: none;
  font-size: var(--size-eyebrow); letter-spacing: .2em; text-transform: uppercase;
  padding: .85em 1.7em;
  border: 1px solid var(--r-hairline); color: var(--r-ink);
  transition:
    background var(--dur-micro) var(--ease),
    border-color var(--dur-micro) var(--ease),
    color var(--dur-micro) var(--ease);
}
.nav__cta:hover { background: var(--r-ink); border-color: var(--r-ink); color: var(--relief); }

.nav__burger {
  display: none; position: relative; z-index: 2; order: 3;
  width: 34px; height: 20px;
}
.nav__burger span {
  position: absolute; left: 0; width: 100%; height: 1px;
  background: var(--r-ink);
  transition: transform var(--dur-micro) var(--ease), top var(--dur-micro) var(--ease),
              bottom var(--dur-micro) var(--ease), background var(--dur-micro) var(--ease);
}
.nav__burger span:nth-child(1) { top: 3px; }
.nav__burger span:nth-child(2) { bottom: 3px; }

/* ---- Dark colouring (Homepage, About) ------------------------------------- */
.nav--dark .nav__logo { --logo-mark: var(--d-display); --logo-accent: var(--d-display); }
.nav--dark .nav__menu a { color: var(--d-ink); }
.nav--dark.is-top .nav__menu a { color: var(--d-display); }
.nav--dark .nav__cta { color: var(--d-ink); border-color: color-mix(in srgb, var(--d-ink) 34%, transparent); }
.nav--dark.is-top .nav__cta { color: var(--d-display); border-color: color-mix(in srgb, var(--d-display) 50%, transparent); }
.nav--dark .nav__cta:hover,
.nav--lifted.is-top .nav__cta:hover { background: var(--d-quiet); border-color: var(--d-quiet); color: var(--d-deep); }
.nav--dark .nav__burger span { background: var(--d-ink); }
.nav--dark.is-top .nav__burger span { background: var(--d-display); }
.nav--dark.is-stuck,
.nav--lifted.is-top.is-stuck {
  background: color-mix(in srgb, var(--d-deep) 90%, transparent);
  box-shadow: 0 1px 0 color-mix(in srgb, var(--d-ink) 14%, transparent);
}

/* ---- Lifted colouring (portfolio detail: light page, photo hero) ----------
   White over the photo, light once past it. */
.nav--lifted.is-top .nav__logo { --logo-mark: var(--d-display); --logo-accent: var(--d-display); }
.nav--lifted.is-top .nav__menu a { color: var(--d-display); }
.nav--lifted.is-top .nav__cta { color: var(--d-display); border-color: color-mix(in srgb, var(--d-display) 50%, transparent); }
.nav--lifted.is-top .nav__burger span { background: var(--d-display); }

/* ---- Shade behind the white nav over photo heroes -------------------------
   SITE (Robb, 2026-09-24): not in the mockups. Keeps the white logo, links and
   phone-menu button readable over bright photos; fades out once the nav is
   stuck or you scroll past the hero. */
.nav::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 140%;
  z-index: -1; pointer-events: none; opacity: 0;
  background: linear-gradient(180deg, rgba(20,26,36,.55) 0%, rgba(20,26,36,.28) 55%, rgba(20,26,36,0) 100%);
  transition: opacity var(--dur-chrome) var(--ease);
}
/* Opt-in with .nav--shade on pages that open on a photo (Homepage, portfolio
   detail). About opens on a plain navy hero and doesn't need it. */
.nav--shade.is-top:not(.is-stuck):not(.is-open)::before { opacity: 1; }

/* ---- Phone menu (≤900px, every page; source: Home v6 at 960px) ------------ */
@media (max-width: 899px) {   /* 899 so it never overlaps the 900px two-column layouts (critique S-31) */
  /* SITE (critique M-12, 2026-10-02): keep a small "Inquire" beside the burger at every width */
  .nav__cta { order: 2; margin-left: auto; padding: .7em 1.15em; letter-spacing: .18em; }
  .nav.is-open .nav__cta { visibility: hidden; }        /* the open menu has its own Inquire */
  /* 44 x 44 tap target; the drawn lines stay 34 x 20 and in the same place */
  .nav__burger { display: block; width: 44px; height: 44px; margin: -12px -5px -12px 0; }
  .nav__burger span { left: 5px; width: 34px; }
  .nav__burger span:nth-child(1) { top: 15px; }
  .nav__burger span:nth-child(2) { bottom: 15px; }
  .nav__menu {
    position: fixed; inset: 0; z-index: 1;
    flex-direction: column; justify-content: center; gap: 30px;
    margin: 0; font-size: 14px;
    background: var(--d-deep);
    opacity: 0; visibility: hidden;
    transition: opacity var(--dur-chrome) var(--ease), visibility var(--dur-chrome);
  }
  .nav__menu a,
  .nav.is-top .nav__menu a { color: var(--linen); }
  /* the menu's Inquire as an outline button, so it doesn't read as a sixth page */
  .nav__menu .nav__menu-cta {
    display: block; margin-top: 12px; padding: .85em 1.7em;
    border: 1px solid color-mix(in srgb, var(--linen) 50%, transparent);
  }
  .nav__menu .nav__menu-cta::after { display: none; }   /* a button, not an underlined link */
  .nav__menu .nav__menu-sub {
    display: block; margin-top: 6px;
    font-size: var(--size-eyebrow); letter-spacing: var(--track-eyebrow); text-transform: uppercase; opacity: .8;
  }
  .nav.is-open .nav__menu { opacity: 1; visibility: visible; }
  .nav.is-open .nav__logo { --logo-mark: var(--d-display); --logo-accent: var(--d-display); }
  .nav.is-open .nav__burger span { background: var(--linen); }
  .nav.is-open .nav__burger span:nth-child(1) { top: 21px; transform: rotate(45deg); }
  .nav.is-open .nav__burger span:nth-child(2) { bottom: 22px; transform: rotate(-45deg); }
  /* SITE: a blurred, stuck nav would trap the fixed menu inside the bar
     (backdrop-filter creates a containing block). Drop it while open. */
  .nav.is-open { background: transparent; box-shadow: none;
    -webkit-backdrop-filter: none; backdrop-filter: none; }
}
@media (max-width: 374px) { .nav { gap: 14px; } }   /* room for logo + Inquire + burger on the smallest phones */
.menu-open { overflow: hidden; }

/* ============================================================================
   BUTTONS AND TEXT LINKS  (source: Footer v1, Home v6)
   ========================================================================= */
/* SITE: default is the relief button (#465469 / Linen). The mockups' default
   Chateau button with white text fails AA contrast at 12px. */
.btn {
  display: inline-block;
  font-size: var(--size-eyebrow); letter-spacing: var(--track-eyebrow); text-transform: uppercase;
  padding: 1.25em 2.6em;
  background: var(--r-link); color: var(--linen); border: 1px solid var(--r-link);
  transition:
    background var(--dur-micro) var(--ease),
    border-color var(--dur-micro) var(--ease),
    color var(--dur-micro) var(--ease);
}
.btn:hover { background: var(--r-ink); border-color: var(--r-ink); }
.dark .btn { background: var(--d-quiet); border-color: var(--d-quiet); color: var(--d-deep); }
.dark .btn:hover { background: var(--d-display); border-color: var(--d-display); }
.dark--slate .btn:hover { color: var(--slate); }

.tlink {
  position: relative; display: inline-flex; align-items: center; gap: .7em;
  padding-block: .55em;
  font-size: var(--size-eyebrow); letter-spacing: var(--track-eyebrow); text-transform: uppercase;
  color: var(--voice-link);
}
.tlink::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(1); transform-origin: left;
  transition: transform .55s var(--ease);
}
.tlink:hover::after { transform: scaleX(0); transform-origin: right; }
.tlink .arw { transition: transform var(--dur-chrome) var(--ease); }
.tlink:hover .arw { transform: translateX(6px); }
.dark .tlink:hover { color: var(--d-display); }

/* Short rule under an eyebrow (About/Praise: 120px) */
.draw--short { max-width: 120px; margin: 14px 0 26px; }

/* ============================================================================
   IMAGE FRAMES  (source: Buckminster v4 / About v3b)
   <figure class="slot ar-4x5 reveal"><img class="slot__inner" …></figure>
   The image settles from a slight zoom as the frame is revealed.
   ========================================================================= */
.slot {
  position: relative; display: block; overflow: hidden; isolation: isolate;
  aspect-ratio: var(--ar, 4 / 3);
  background: var(--surface-lift);
}
.slot__inner {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
}
.js .slot__inner { transform: scale(var(--set-scale)); transition: transform var(--set-dur) var(--ease); }
.js .reveal.in .slot__inner,
.js .slot.reveal.in .slot__inner { transform: scale(1); }
.slot--settle-sm { --set-scale: 1.04; --set-dur: 1.2s; }   /* pairs, tiles */
.slot--portrait  { --set-scale: 1.10; --set-dur: var(--dur-image); }
/* Native ratio: the image's own width/height attributes set the shape. */
.slot--native { aspect-ratio: auto; }
.slot--native .slot__inner { position: static; height: auto; }

.ar-1x1  { --ar: 1 / 1; }
.ar-2x1  { --ar: 2 / 1; }
.ar-2x3  { --ar: 2 / 3; }
.ar-3x4  { --ar: 3 / 4; }
.ar-4x3  { --ar: 4 / 3; }
.ar-4x5  { --ar: 4 / 5; }
.ar-5x4  { --ar: 5 / 4; }
.ar-5x6  { --ar: 5 / 6; }
.ar-16x9 { --ar: 16 / 9; }

@media (prefers-reduced-motion: reduce) {
  /* translateZ(0), not none (2026-10-28): keeps each framed photo on its own
     layer so Safari repaints lazy images inside sticky columns (Home .phil__sticky,
     Process .manage__fig, detail .about__fig). Looks identical; no motion. */
  .js .slot__inner { transform: translateZ(0); }
}

/* ============================================================================
   SECTION TRANSITIONS
   ========================================================================= */

/* ---- 01 Long dissolve, hung into existing padding (source: Home v6) -------
   Put on the LOWER section with a pair class naming top → bottom ground.
   Adds no height: the ramp spans the upper section's bottom padding and this
   section's top padding. Never on single-ground light pages (use .draw). */
.seam-in { position: relative; --seam-up: var(--sec); --seam-dn: var(--sec); }
.seam-in > * { position: relative; z-index: 1; }
.seam-in::before,
.seam-in::after {
  content: ""; position: absolute; left: 0; right: 0; z-index: 0; pointer-events: none;
  top: calc(-1 * var(--seam-up));
  height: calc(var(--seam-up) + var(--seam-dn));
}
.seam-in::before {
  background: linear-gradient(180deg,
    var(--seam-a) 0%,
    color-mix(in oklab, var(--seam-b) 1.5%,  var(--seam-a)) 7.1%,
    color-mix(in oklab, var(--seam-b) 5.5%,  var(--seam-a)) 14.3%,
    color-mix(in oklab, var(--seam-b) 11.8%, var(--seam-a)) 21.4%,
    color-mix(in oklab, var(--seam-b) 19.8%, var(--seam-a)) 28.6%,
    color-mix(in oklab, var(--seam-b) 29.2%, var(--seam-a)) 35.7%,
    color-mix(in oklab, var(--seam-b) 39.4%, var(--seam-a)) 42.9%,
    color-mix(in oklab, var(--seam-b) 50%,   var(--seam-a)) 50%,
    color-mix(in oklab, var(--seam-b) 60.6%, var(--seam-a)) 57.1%,
    color-mix(in oklab, var(--seam-b) 70.8%, var(--seam-a)) 64.3%,
    color-mix(in oklab, var(--seam-b) 80.2%, var(--seam-a)) 71.4%,
    color-mix(in oklab, var(--seam-b) 88.2%, var(--seam-a)) 78.6%,
    color-mix(in oklab, var(--seam-b) 94.5%, var(--seam-a)) 85.7%,
    color-mix(in oklab, var(--seam-b) 98.5%, var(--seam-a)) 92.9%,
    var(--seam-b) 100%);
}
.seam-in::after {                                    /* dither, so it never bands */
  opacity: .062; mix-blend-mode: overlay;
  background: url("../assets/img/noise.svg") 0 0 / 160px 160px;
}
.dark + .dark.seam-in { box-shadow: none; }

.seam-in--relief-base  { --seam-a: var(--relief);   --seam-b: var(--d-base); }
.seam-in--base-relief  { --seam-a: var(--d-base);   --seam-b: var(--relief); }
.seam-in--deep-base    { --seam-a: var(--d-deep);   --seam-b: var(--d-base); }
.seam-in--base-raised  { --seam-a: var(--d-base);   --seam-b: var(--d-raised); }
.seam-in--raised-base  { --seam-a: var(--d-raised); --seam-b: var(--d-base); }

/* ---- 05a Inset step ("shelf"): 30px top edge, nothing at the bottom -------
   <span class="iband iband--slate" aria-hidden="true"></span> as the first
   child of a positioned section. Gradients, not inset box-shadow (which
   bleeds at the corners). Source: Footer v1. */
.iband {
  position: absolute; left: 0; right: 0; top: 0; height: 30px; pointer-events: none;
  background: linear-gradient(180deg, rgba(52,58,68,.090) 0%, rgba(52,58,68,.042) 34%,
                                      rgba(52,58,68,.012) 66%, rgba(52,58,68,0) 100%);
}
.iband--dark {
  background: linear-gradient(180deg, rgba(10,14,22,.30) 0%, rgba(10,14,22,.14) 34%,
                                      rgba(10,14,22,.04) 66%, rgba(10,14,22,0) 100%);
}
.iband--slate {
  background: linear-gradient(180deg, rgba(0,0,0,.42) 0%, rgba(0,0,0,.20) 34%,
                                      rgba(0,0,0,.06) 66%, rgba(0,0,0,0) 100%);
}

/* ---- 05b Recessed tray over a photo band (source: Home v6 .band__scrim) ---
   Heavier at the top (a recess lit from above), both edges gone by ~100px.
   SITE: bottom edge at half the mockup's strength (Robb, 2026-09-24): over a
   pale floor the full value read as a grey haze. */
.tray {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background-image:
    linear-gradient(180deg, rgba(0,0,0,.72) 0%, rgba(0,0,0,.54) 9%, rgba(0,0,0,.36) 21%,
      rgba(0,0,0,.21) 36%, rgba(0,0,0,.10) 55%, rgba(0,0,0,.035) 76%, rgba(0,0,0,0) 100%),
    linear-gradient(0deg, rgba(0,0,0,.30) 0%, rgba(0,0,0,.22) 9%, rgba(0,0,0,.145) 21%,
      rgba(0,0,0,.085) 36%, rgba(0,0,0,.04) 55%, rgba(0,0,0,.015) 76%, rgba(0,0,0,0) 100%),
    linear-gradient(180deg, rgba(26,32,42,.10) 0%, rgba(26,32,42,.04) 50%, rgba(26,32,42,.09) 100%);
  background-size: 100% 104px, 100% 104px, 100% 100%;
  background-position: top, bottom, top;
  background-repeat: no-repeat;
}

/* ---- Scroll cue on photo heroes (source: Home v6, Buckminster v4) --------- */
.cue {
  position: absolute; left: 50%; bottom: 34px; z-index: 3; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  font-size: 11px; letter-spacing: .24em; text-transform: uppercase;
  color: color-mix(in srgb, var(--d-display) 80%, transparent);
}
.cue i {
  position: relative; display: block; width: 1px; height: 56px; overflow: hidden;
  background: color-mix(in srgb, var(--d-display) 42%, transparent);
}
.cue i::after {
  content: ""; position: absolute; inset: 0; background: var(--d-display);
  animation: cue 2.6s var(--ease) infinite;
}
@keyframes cue { 0% { transform: translateY(-100%); } 55%, 100% { transform: translateY(100%); } }
@media (max-width: 700px) { .cue { display: none; } }
@media (prefers-reduced-motion: reduce) { .cue i::after { animation: none; } }

/* ============================================================================
   INQUIRE BAND + FOOTER  (source: ajid-footer-v1.html; every page closes here)
   ========================================================================= */
.inquire { text-align: center; }
.dark.inquire { box-shadow: none; }        /* the 05a shelf marks this edge */
.inquire__in { max-width: 640px; margin-inline: auto; }
.inquire p { margin-top: 20px; color: var(--d-ink-2); }
.inquire__actions {   /* two actions in the band (Contact's variant, 2026-10-02) */
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 18px 32px; margin-top: 30px;
}
.inquire .inquire__actions .btn { margin-top: 0; }
.inquire .btn { margin-top: 36px; }

.foot {
  background: var(--d-deep); color: var(--d-ink);
  padding-block: clamp(60px, 8vw, 96px) 30px;
  box-shadow: inset 0 1px 0 var(--d-seam-line);
}
.foot__grid { display: grid; gap: clamp(32px, 4vw, 60px); grid-template-columns: 1fr; }
@media (min-width: 900px) { .foot__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1100px) { .foot__grid { grid-template-columns: 1.3fr 1fr 1fr 1.4fr; } }
.foot__logo {
  display: block; width: 150px; margin-bottom: 22px;
  --logo-mark: var(--logo-mark-dark); --logo-accent: var(--logo-accent-dark);
}
.foot h2 {
  margin-bottom: 16px;
  font-size: 11px; font-weight: 400; letter-spacing: .24em; text-transform: uppercase;
  color: var(--d-quiet);
}
.foot ul { display: grid; gap: 10px; }
.foot li, .foot p, .foot address { font-size: var(--size-caption); line-height: 1.65; color: var(--d-ink-2); }
.foot a { transition: color var(--dur-micro) var(--ease); }
.foot a:hover { color: var(--d-display); }
/* Newsletter signup (critique S-01, 2026-10-02): a quiet underline field and a text button */
.foot__form { display: flex; align-items: flex-end; gap: 14px; max-width: 26rem; margin-top: 14px; }
.foot__form input {
  flex: 1; min-width: 0; padding: 8px 0;
  background: transparent; border: 0; border-bottom: 1px solid var(--d-hairline); border-radius: 0;
  font-size: 16px; color: var(--d-display);       /* 16px: no zoom on iPhone */
  transition: border-color var(--dur-micro) var(--ease);
}
.foot__form input::placeholder { color: var(--d-ink-2); opacity: .8; }
.foot__form input:hover { border-bottom-color: var(--d-ink-2); }
.foot__form input:focus-visible { outline: 2px solid var(--focus); outline-offset: 4px; border-bottom-color: var(--d-display); }
.foot__form input[aria-invalid="true"] { border-bottom-color: var(--d-display); }
.foot__form button {
  flex: none; padding: 8px 0;
  font-size: var(--size-eyebrow); letter-spacing: .2em; text-transform: uppercase; color: var(--d-display);
  border-bottom: 1px solid currentColor;
}
.foot__form button:hover { color: var(--d-quiet); }
.foot .foot__done { margin-top: 14px; color: var(--d-display); }
.foot__done[hidden], .foot__form[hidden] { display: none; }
/* THEME PORT: the live signup is a Mailchimp for WP form wearing .foot__form; its reply
   ("Thank you…" or an error) prints in .mc4wp-response, on its own line under the field. */
.foot__form.mc4wp-form { flex-wrap: wrap; }
.foot__form .mc4wp-form-fields { display: contents; } /* its input and button join the row */
.foot__form .mc4wp-response { flex: 1 0 100%; }
.foot__form .mc4wp-response:empty { display: none; }
.foot__form .mc4wp-response p { margin: 0; color: var(--d-display); }
.foot__bot {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 10px 26px;
  margin-top: clamp(40px, 5vw, 68px); padding-top: 22px;
  border-top: 1px solid var(--d-hairline);
  font-size: var(--size-eyebrow); color: var(--d-ink-2);
}
/* Social links (Robb, 2026-11-07, from the live site's footer). Icons: assets/img/icons/social.svg
   (Simple Icons, CC0). Each link is a 44px tap target; the negative margin keeps the first glyph
   level with the address above. */
.foot ul.foot__social { display: flex; flex-wrap: wrap; gap: 4px; margin: 14px 0 0 -13px; }
.foot__social a {
  display: grid; place-items: center; width: 44px; height: 44px;
  color: var(--d-ink-2);
}
.foot__social a:hover { color: var(--d-display); }
.foot__social a:focus-visible, .foot__bot a:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
.foot__icon { width: 18px; height: 18px; }

/* ============================================================================
   TONAL DRIFT AND FLOATING NOTE (js/drift.js places and moves them)
   ========================================================================= */
/* ---- 02 Tonal drift: one gradient field behind two sections, no seam ------
   (source: About v3b, Praise v3e)
   js/drift.js places the ramp (--ra/--rb, percent of the field) from the
   page layout and moves it gently with the scroll (--p). */
.drift { position: relative; isolation: isolate; overflow: hidden; }
.drift__field {
  position: absolute; left: 0; right: 0; top: -8%; bottom: -8%; z-index: 0; pointer-events: none;
  --ra: 30; --rb: 70;
  transform: translate3d(0, calc((var(--p, .5) - .5) * 4%), 0);
  will-change: transform;
}
.drift__field::after {                                  /* dither */
  content: ""; position: absolute; inset: 0;
  opacity: .05; mix-blend-mode: overlay;
  background: url("../assets/img/noise.svg") 0 0 / 160px 160px;
}
.drift > section { background: none; position: relative; z-index: 1; }
.drift > aside { position: relative; z-index: 1; }
.drift--deep-base  .drift__field { --drift-a: var(--d-deep); --drift-b: var(--d-base); }
.drift--relief-base .drift__field { --drift-a: var(--relief); --drift-b: var(--d-base); }
.drift__field {
  background: linear-gradient(180deg,
    var(--drift-a) 0%,
    var(--drift-a) calc(var(--ra) * 1%),
    color-mix(in oklab, var(--drift-b) 1.5%,  var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .0714) * 1%),
    color-mix(in oklab, var(--drift-b) 5.5%,  var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .1429) * 1%),
    color-mix(in oklab, var(--drift-b) 11.8%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .2143) * 1%),
    color-mix(in oklab, var(--drift-b) 19.8%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .2857) * 1%),
    color-mix(in oklab, var(--drift-b) 29.2%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .3571) * 1%),
    color-mix(in oklab, var(--drift-b) 39.4%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .4286) * 1%),
    color-mix(in oklab, var(--drift-b) 50%,   var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .5)    * 1%),
    color-mix(in oklab, var(--drift-b) 60.6%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .5714) * 1%),
    color-mix(in oklab, var(--drift-b) 70.8%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .6429) * 1%),
    color-mix(in oklab, var(--drift-b) 80.2%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .7143) * 1%),
    color-mix(in oklab, var(--drift-b) 88.2%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .7857) * 1%),
    color-mix(in oklab, var(--drift-b) 94.5%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .8571) * 1%),
    color-mix(in oklab, var(--drift-b) 98.5%, var(--drift-a)) calc((var(--ra) + (var(--rb) - var(--ra)) * .9286) * 1%),
    var(--drift-b) calc(var(--rb) * 1%),
    var(--drift-b) 100%);
}
@media (prefers-reduced-motion: reduce) { .drift__field { transform: none; } }

/* ---- Floating note over the drift (About, Praise) ---------------------------- */
.drift-note__float { will-change: transform; }
.drift-note__card {
  max-width: 760px; margin: 0 auto;
  padding: clamp(34px, 4.4vw, 56px) clamp(24px, 5vw, 72px);
  background: var(--relief-a); color: var(--r-ink); text-align: center;
  box-shadow: 0 28px 70px rgba(20,26,36,.24);
}
.drift-note__card .h2 { margin: 0; color: var(--r-ink); }
.drift-note__card .eyebrow { margin-top: 22px; color: var(--r-quiet); }
/* The page close on Portfolio and the project pages (2026-10-29): the card sits in the
   light end of the drift; the ramp starts at this aside's top edge so it never shows a seam. */
.drift-note--close { padding-top: clamp(120px, 16vh, 176px); }

@media (prefers-reduced-motion: reduce) { .drift-note__float { transform: none !important; } }

/* ---- FAQ (question | answer rows) ----------------------------------------------
   Shared by Process and Services (moved from process.css, 2026-10-02). */
.faq { margin-top: clamp(32px, 4vw, 48px); max-width: 64rem; }
.faq__item { display: grid; grid-template-columns: 1fr; gap: 8px clamp(28px, 4vw, 56px); padding-block: 22px; border-top: 1px solid var(--hairline); }
.faq__item:last-child { border-bottom: 1px solid var(--hairline); }
@media (min-width: 900px) { .faq__item { grid-template-columns: .9fr 1.1fr; } }
.faq__item dd { margin: 0; color: var(--ink-2); }
.faq__item dd a { color: var(--voice-link); text-decoration: underline; text-underline-offset: .2em; }

/* ---- Centered hero (Services and Process variations, 2026-10-02) ---------------
   Design system: "Centring is ceremonial: heroes … may centre". One Besotted Love
   accent per page: Medium (500) at or above the 34px floor on a light ground. */
.hero-c { padding: clamp(112px, 12vw, 150px) 0 clamp(40px, 5vw, 64px); text-align: center; }
.hero-c__in > * { margin-inline: auto; }
.hero-c .eyebrow { display: block; }
.hero-c__script {
  margin-top: clamp(14px, 1.8vw, 22px);
  font-family: var(--script); font-weight: var(--script-weight); font-synthesis: none;
  font-size: clamp(44px, 5.2vw, 66px); line-height: 1.4;   /* room for the swashes above and below */
  color: var(--voice);
}
.hero-c .display { max-width: 20ch; margin-top: 4px; margin-inline: auto; text-align: center; }
/* Process: eyebrow, script, headline inside one H1 (same spacing as Services) */
.hero-c h1 .hero-c__script + .display { margin-top: clamp(10px, 1.4vw, 18px); }
.hero-c__script + h1 { margin-top: clamp(10px, 1.4vw, 18px); }   /* keep the script's descenders off the line below */
.hero-c .lede { max-width: 54ch; margin-top: 22px; color: var(--ink-2); }
.hero-c .tlink { margin-top: 26px; }

/* ---- REVIEW SITE ONLY: hero variation switcher (js/hero-variants.js) ---------- */
.hero-switch {
  position: fixed; right: 12px; bottom: 12px; z-index: 95;
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 6px 8px;
  max-width: calc(100vw - 24px);   /* wraps on phones instead of running off-screen */
  background: var(--ink); color: var(--linen);
  font-family: var(--mono); font-size: 11px;
  box-shadow: 0 6px 20px rgba(20, 26, 36, .25);
}
.hero-switch__label { margin-right: 4px; opacity: .75; }
.hero-switch button { padding: 3px 9px; border: 1px solid rgba(238, 238, 237, .35); font-family: var(--mono); font-size: 11px; color: var(--linen); }
.hero-switch button[aria-pressed="true"] { background: var(--linen); color: var(--ink); border-color: var(--linen); }
.hero-switch button:focus-visible { outline: 2px solid var(--linen); outline-offset: 2px; }
.hero-switch__sep { margin-left: 10px; padding-left: 10px; border-left: 1px solid rgba(238, 238, 237, .35); }
.hero-switch a { padding: 3px 9px; border: 1px solid rgba(238, 238, 237, .35); color: var(--linen); text-decoration: none; }
.hero-switch a[aria-current="page"] { background: var(--linen); color: var(--ink); border-color: var(--linen); }
.hero-switch a:focus-visible { outline: 2px solid var(--linen); outline-offset: 2px; }

/* ---- Quote card on the light ground (Robb, 2026-11-06) ------------------------------------------
   Services Rev 2's greige card, now shared with About. Contrast on --relief-c: quote 6.8:1,
   attribution 4.8:1. Movement is About's former drawn rule, carried onto the card: the card draws
   down from the top as it is reached, then its quote and attribution rise in (their own .reveal
   staggers). Each page keeps its own quote typography. */
.qcard {
  position: relative; isolation: isolate;
  padding: clamp(24px, 3vw, 36px) clamp(24px, 3.4vw, 44px);
  border: 0; background: var(--relief-c);
}
.qcard blockquote, .qcard blockquote p { color: var(--r-ink); }
.qcard figcaption, .qcard cite { color: var(--r-quiet); }
/* The ground is drawn as a layer behind the text, so the card itself is never clipped (a clipped
   element never counts as on screen, and would never be revealed). */
.js .qcard.reveal { opacity: 1; transform: none; background: transparent; }
.js .qcard.reveal::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--relief-c);
  transform: scaleY(0); transform-origin: top;
  transition: transform .9s var(--ease);
}
.js .qcard.reveal.in::before { transform: none; }
@media (prefers-reduced-motion: reduce) { .js .qcard.reveal::before { transform: none; } }
