/* ============================================================
   studioM PORTRAITS — tokens
   ============================================================ */
:root {
  --paper: #f2f1ef;
  --ink: #0a0a0a;
  --ink-soft: #8c8c8c;
  --ink-faint: #c9c7c4;

  --pad: clamp(18px, 3.4vw, 56px);
  --font: "Poppins", ui-sans-serif, system-ui, -apple-system, "Helvetica Neue", sans-serif;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* One rhythm for the whole site: 140px between sections on desktop, 48px
     on phones (set in the mobile block below). Every section carries the gap
     on its top edge, so a boundary is exactly one gap — never doubled by a
     bottom padding underneath it. */
  --gap: 140px;
  --gap-half: calc(var(--gap) / 2);

  /* Height of the fixed top plate. Anything that can land at the very top of
     the viewport has to clear it — see .panel's scroll-margin and the detail
     hero's padding. */
  --nav-h: clamp(70px, 8.5vh, 100px);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

/* Scrolling is locked until the loading screen hands over; the transition
   timeline sets this back to `auto` (and restores it on reverse). */
html {
  overflow: hidden;
}

body {
  font-family: var(--font);
  background: var(--paper);
  color: var(--ink);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

/* ============================================================
   Shutter flash
   ============================================================ */
.flash {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: #fff;
  opacity: 0;
  pointer-events: none;
}

/* ============================================================
   Shared 3D stage for the photo cards
   Perspective lives here so cards genuinely travel toward the
   viewer as they leave the lens, instead of merely scaling up.
   ============================================================ */
/* Above the loader (40) — the photos are thrown toward the viewer, so they
   must pass in front of the photographer, not behind him. */
.stage {
  position: fixed;
  inset: 0;
  z-index: 45;
  perspective: 1200px;
  perspective-origin: 50% 50%;
  pointer-events: none;
}

/* Two layers on purpose:
   .card     — owned by GSAP for flight path + parallax (x/y/rotation/scale)
   .card__in — owned by the idle float loop, so the two never overwrite
               each other's transform. */
.card {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 210px;
  margin: -130px 0 0 -105px;
  transform-style: preserve-3d;
  will-change: transform, opacity;
  opacity: 0;
  /* Enabled only once the hero is live (see .stage.is-live below), so the
     flying cards can't be clicked mid-intro. */
  pointer-events: none;
  color: inherit;
  text-decoration: none;
}

.stage.is-live .card {
  pointer-events: auto;
  cursor: pointer;
}

.card__in {
  display: block;
  padding: 10px;
  background: #fff;
  box-shadow: 0 18px 44px -18px rgba(0, 0, 0, 0.42), 0 2px 8px rgba(0, 0, 0, 0.06);
  will-change: transform;
  transition: box-shadow 0.5s var(--ease-out);
}

/* Hover: the card lifts and its "view gallery" cue brightens. Applied to the
   inner frame so it composes with the idle-float transform on the same node
   via a CSS var handoff would be overkill — GSAP owns .card__in's transform,
   so we lift with box-shadow + a scale on a nested wrapper instead. */
.stage.is-live .card:hover .card__in {
  box-shadow: 0 30px 60px -22px rgba(0, 0, 0, 0.5), 0 4px 12px rgba(0, 0, 0, 0.1);
}

.card--tall .card__in { padding-bottom: 34px; }

.card__media {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  background: linear-gradient(150deg, var(--c1), var(--c2));
  position: relative;
}

/* Placeholder frames: only used when a card has no real photo (PHOTOS[].src). */
.card__media--ph::after {
  content: attr(data-label);
  position: absolute;
  inset: auto 0 10px 0;
  text-align: center;
  font-size: 10px;
  letter-spacing: 0.24em;
  color: rgba(255, 255, 255, 0.92);
  text-transform: uppercase;
}

.card__media--ph::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(70% 55% at 30% 22%, rgba(255, 255, 255, 0.42), transparent 62%);
}

/* Caption: the category name over a soft scrim at the foot of the photo,
   plus a "view gallery" cue that fades up on hover. */
.card__cap {
  position: absolute;
  left: 10px;
  right: 10px;
  bottom: 10px;
  padding: 22px 8px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  text-align: center;
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.62), transparent);
}

.card--tall .card__cap { bottom: 34px; }

.card__cap b {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  line-height: 1.15;
  color: #fff;
  text-transform: uppercase;
}

.card__cap i {
  font-style: normal;
  font-size: 8.5px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.stage.is-live .card:hover .card__cap i {
  opacity: 1;
  transform: translateY(0);
}

/* ============================================================
   LOADER
   ============================================================ */
.loader {
  position: fixed;
  inset: 0;
  z-index: 40;
  overflow: hidden;
  /* Opaque, not transparent: on reload the browser can bring back the old
     scroll position underneath, and a see-through loader played the intro on
     top of mid-page content. Solid paper means whatever the document is doing
     behind the curtain, the intro always opens on a clean sheet — and the
     handover stays seamless because the hero sits on this same paper. */
  background: var(--paper);
}

.loader__social {
  position: absolute;
  top: var(--pad);
  left: var(--pad);
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: clamp(11px, 1vw, 13px);
  font-weight: 300;
  overflow: hidden;
}

.loader__social span {
  display: block;
}

/* ── logo ─────────────────────────────────────────────── */
/* Base mark, used twice: top-right on the loading screen, and centred in
   the nav bar once the site is live. */
.logo {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  line-height: 1;
}

.logo--loader {
  position: absolute;
  top: var(--pad);
  right: var(--pad);
  align-items: flex-end;
}

.logo__row {
  display: inline-flex;
  align-items: center;
  font-size: clamp(22px, 2.5vw, 34px);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.logo__m {
  display: inline-grid;
  place-items: center;
  font-style: normal;
  background: var(--ink);
  color: var(--paper);
  width: 1.02em;
  height: 1.02em;
  margin-left: 0.06em;
  font-weight: 700;
  border-radius: 2px;
}

.logo__sub {
  font-size: clamp(9px, 0.95vw, 12.5px);
  font-weight: 400;
  letter-spacing: 0.06em;
  color: var(--ink);
}

/* ── photographer ─────────────────────────────────────── */
.shooter {
  position: absolute;
  /* Flush to the right edge — any negative inset pushes his head out of
     frame, since the subject sits at the top-right of the cutout. */
  right: 0;
  bottom: 0;
  margin: 0;
  height: min(90vh, 920px);
  /* Constrained on BOTH axes. Height alone lets him swallow the whole screen
     on a tall/narrow viewport; aspect-ratio then shrinks the height to match. */
  max-width: 54vw;
  aspect-ratio: 1564 / 1801;
  z-index: 10;
  will-change: transform;
}

.shooter img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: bottom right;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
}

/* Sits exactly over the front element of the lens — measured off the
   asset (x 15%, y 43.9% of its box). Cards are launched from here. */
.shooter__lens {
  position: absolute;
  left: 15%;
  top: 43.9%;
  width: 10px;
  height: 10px;
  margin: -5px 0 0 -5px;
  border-radius: 50%;
  pointer-events: none;
}

/* Concentric pulse rings that fire with each shutter release. */
.lens-ring {
  position: fixed;
  z-index: 30;
  width: 26px;
  height: 26px;
  margin: -13px 0 0 -13px;
  border: 1.5px solid rgba(10, 10, 10, 0.55);
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
}

/* ── type block ───────────────────────────────────────── */
/* Deliberately BELOW the photographer (z 10): where the tail of a long word
   meets him it slides behind the figure, which reads as depth. Above him it
   would be black type on a black shirt. */
.loader__type {
  position: absolute;
  left: var(--pad);
  bottom: clamp(40px, 8vh, 96px);
  z-index: 8;
  max-width: 92vw;
}

.wordmark {
  margin: 0;
  font-size: clamp(34px, 6vw, 92px);
  font-weight: 300;
  letter-spacing: -0.005em;
  line-height: 0.98;
  white-space: nowrap;
}

.wordmark--indent {
  padding-left: clamp(16px, 4.6vw, 74px);
}

.char {
  display: inline-block;
  will-change: transform;
}

.tagline {
  margin: clamp(8px, 1.4vw, 18px) 0 clamp(6px, 1.2vw, 14px);
  padding-left: 0.35em;
  font-size: clamp(11px, 1.35vw, 19px);
  font-weight: 300;
  letter-spacing: 0.22em;
  color: var(--ink-faint);
  white-space: nowrap;
}

/* ── progress ─────────────────────────────────────────── */
/* Bottom-LEFT, not right: the right side is the photographer's dark shirt,
   where an ink-coloured hairline bar simply disappears. */
.loader__progress {
  position: absolute;
  left: var(--pad);
  bottom: clamp(16px, 2.6vh, 30px);
  display: flex;
  align-items: center;
  gap: 14px;
  z-index: 12;
}

.loader__count {
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.16em;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.loader__bar {
  display: block;
  width: clamp(90px, 12vw, 190px);
  height: 1px;
  background: var(--ink-faint);
}

.loader__bar i {
  display: block;
  height: 100%;
  width: 0%;
  background: var(--ink);
}

/* ============================================================
   FIXED CHROME
   Corner furniture + the dial. Stays put while sections scroll
   underneath it.
   ============================================================ */
.chrome {
  position: fixed;
  inset: 0;
  z-index: 25;
  /* The panel itself must never intercept clicks meant for the page; only
     its actual controls opt back in. */
  pointer-events: none;
}

.chrome a,
.dial__item {
  pointer-events: auto;
}

/* Top plate. Section copy scrolls *behind* the fixed corner furniture, so
   without an opaque band a heading collides with "IT'S MARVIN HALL TIME" and
   the social marks. Flat paper, only as tall as that furniture — the old
   gradient version read as a grey wash over whatever passed under it.
   (The bottom is handled by the dial's own plate — see .dial::before.) */
.chrome::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: var(--nav-h);
  background: var(--paper);
  pointer-events: none;
}

/* autoAlpha (opacity + visibility) so the invisible dial can't be clicked
   during the loading screen. */
[data-hero-fade] {
  opacity: 0;
  visibility: hidden;
}

/* z-index 1 keeps the labels and the dial above the two plates, which are
   pseudo-elements of this same stacking context. */
.chrome__bl,
.chrome__br {
  position: absolute;
  z-index: 1;
  font-size: clamp(10px, 1vw, 13px);
  font-weight: 300;
  letter-spacing: 0.02em;
}

.chrome__bl { bottom: var(--pad); left: var(--pad); }
.chrome__br { bottom: var(--pad); right: var(--pad); }

.chrome__credit { color: var(--ink-faint); }

/* ── booking CTA, bottom-right corner ──────────────────────────
   Outline pill that fills with ink on hover, matching the reference. */
.chrome__cta {
  position: absolute;
  bottom: var(--pad);
  right: var(--pad);
  z-index: 1;
  display: inline-flex;
  align-items: center;
  padding: clamp(9px, 0.9vw, 13px) clamp(18px, 1.7vw, 28px);
  border: 1px solid var(--ink);
  border-radius: 999px;
  font-size: clamp(11px, 0.85vw, 13px);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  overflow: hidden;
  isolation: isolate;
  /* Opaque paper, not transparent: the pill floats over page content while
     scrolling, and an outline alone disappears against dark photos. */
  background: var(--paper);
}

/* Ink wash slides up from below on hover. */
.chrome__cta::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform 0.5s var(--ease-out);
}

.chrome__cta span {
  transition: color 0.5s var(--ease-out);
}

.chrome__cta:hover::before { transform: translateY(0); }
.chrome__cta:hover span { color: var(--paper); }

/* On phones the credit line would crowd the CTA; drop the "Site by TBP"
   half and let the corners breathe. */
@media (max-width: 560px) {
  .chrome__credit { display: none; }
  .chrome__cta {
    padding: 8px 16px;
    font-size: 11px;
  }
}

/* ── centred brand + scroll-in nav bar ─────────────────────────
   At the top of the page only the logo shows. Scrolling grows the white
   pill out from behind it and fades the two link groups in beside it.
   The links keep their natural width the whole time — they're merely
   invisible at rest — so the logo never shifts when they appear. */
.brandbar {
  position: absolute;
  top: clamp(10px, 1.6vh, 24px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.4vw, 22px);
  padding: clamp(8px, 1vw, 13px) clamp(16px, 2vw, 30px);
  /* A definite width is what lets the two groups take equal halves, which is
     what keeps the logo on the viewport's centre line — the right-hand group
     is much wider than the left, so content-sizing would shove it off.
     It must also be wide enough that the WIDER group still fits its half:
     at 1000px the right group overflowed and pushed the mark 12px left.

     The width TRACKS the viewport because the link type and gaps are all vw
     clamps — a fixed px width fits at one size and either clips the CONTACT
     pill or leaves lopsided white at every other. 78vw shadows the content's
     own growth to within ~20px, and the 1260px ceiling matches the widest the
     bar ever needs, once every clamp has topped out (~1244px). */
  width: min(clamp(990px, 78vw, 1260px), calc(100vw - 2 * var(--pad)));
}

/* z-index -1 keeps the plate behind the links. .brandbar makes its own
   stacking context, so this can't fall behind the page itself. */
.brandbar__bg {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 230px;
  transform: translateX(-50%);
  z-index: -1;
  background: #fff;
  border-radius: 999px;
  box-shadow: 0 12px 34px -16px rgba(0, 0, 0, 0.3);
  opacity: 0;
}

.brandbar__group {
  /* Equal halves either side of the mark. min-width:0 is what makes them stay
     equal: without it a nowrap group that outgrows its half refuses to shrink
     and pushes the mark off the centre line. */
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.1vw, 18px);
  font-size: clamp(10px, 0.8vw, 13px);
  font-weight: 400;
  letter-spacing: 0.04em;
  white-space: nowrap;
}

/* Each group spans its half so its OUTER edge lands on the pill's padding.
   Hugging the logo instead would pile every pixel of leftover space at the
   pill's ends — and since the two groups aren't the same width, that slack
   lands unevenly and the bar reads as off-centre. */
.brandbar__group--l { justify-content: space-between; }
.brandbar__group--r { justify-content: space-between; }

.brandbar__group a {
  position: relative;
  transition: opacity 0.35s var(--ease-out);
}

/* Current-page indicator: the same hairline the portfolio tabs use, growing
   in from the left under the open page's link. */
.brandbar__group a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -7px;
  width: 100%;
  height: 1.5px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.5s var(--ease-out);
}

.brandbar__group a.is-current::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* Outbound link: the arrow marks that this one leaves the site, matching the
   ↗ used in the journal rows and the directions link. */
.brandbar__ext i {
  font-style: normal;
  font-size: 0.8em;
  margin-left: 4px;
  vertical-align: 1px;
  transition: transform 0.4s var(--ease-out);
  display: inline-block;
}

.brandbar__ext:hover i { transform: translate(2px, -2px); }

/* Contact is the one action in the bar, so it reads as a button rather than
   another destination — outline pill that fills with ink on hover, matching
   the booking CTA. */
.brandbar__cta {
  flex: 0 0 auto;
  padding: 7px 16px;
  margin-left: 4px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.45s var(--ease-out);
}

.brandbar__cta::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform 0.45s var(--ease-out);
}

.brandbar__cta:hover { color: var(--paper); }
.brandbar__cta:hover::before { transform: translateY(0); }

/* The pill states its own current-page look; the shared underline would sit
   awkwardly outside its border. */
.brandbar__cta::after { content: none; }
.brandbar__cta.is-current { color: var(--paper); }
.brandbar__cta.is-current::before { transform: translateY(0); }

.brandbar__group a:hover { opacity: 0.45; }

.logo--nav .logo__row {
  font-size: clamp(17px, 1.55vw, 25px);
}

.logo--nav .logo__sub {
  font-size: clamp(7.5px, 0.62vw, 10px);
  letter-spacing: 0.04em;
}

/* Eight links plus the mark stop fitting well before tablet width, so the
   groups drop out and the centred logo stays — the same links move behind the
   burger below. */
@media (max-width: 1180px) {
  .brandbar__group { display: none; }
  /* Without the groups the bar should hug the mark, not hold a 1000px pill. */
  .brandbar { width: auto; }
}

/* ── burger + mobile menu ──────────────────────────────────────
   Only exists below the brandbar's breakpoint. The button sits in the
   top-left corner, opposite the socials, and the panel it opens is the
   page's own paper — a sheet, not a dark scrim. */
.burger {
  all: unset;
  /* Restated because `all: unset` above wipes the hidden state that
     [data-hero-fade] sets — same specificity, and this rule comes later, so
     without these the bars sat over the loader's social list. */
  opacity: 0;
  visibility: hidden;
  position: fixed;
  /* Above the floating photo cards (45), below the shutter flash (90). */
  z-index: 60;
  top: var(--pad);
  left: var(--pad);
  display: none;
  box-sizing: border-box;
  width: 44px;
  height: 44px;
  margin: -11px 0 0 -11px; /* 44px tap target, optically aligned to the corner */
  padding: 11px;
  cursor: pointer;
  pointer-events: auto;
}

.burger span {
  display: block;
  width: 22px;
  height: 1.5px;
  background: var(--ink);
  transition: transform 0.45s var(--ease-out), opacity 0.3s var(--ease-out);
}

.burger span + span { margin-top: 6px; }

/* Open: the two bars cross. */
.burger.is-open span:first-child { transform: translateY(3.75px) rotate(45deg); }
.burger.is-open span:last-child { transform: translateY(-3.75px) rotate(-45deg); }

.menu {
  position: fixed;
  inset: 0;
  /* Over the cards and the whole page; the burger sits one layer above so it
     stays clickable as the close control. */
  z-index: 55;
  display: flex;
  flex-direction: column;
  /* `safe` is load-bearing, not a tidy-up. With a plain `center`, a flex column
     whose content is taller than the box overflows off BOTH ends, and the top
     end sits before the scroll origin — so it cannot be scrolled to. On a
     390x844 phone these 13 links plus the booking row come to 992px, which put
     "01 About", "13 Contact", "Book a Session" and the studio's phone number
     permanently out of reach. `safe center` falls back to start-alignment only
     when the content overflows, so it is pixel-identical wherever the menu
     already fits and only differs where items were previously unreachable. */
  justify-content: safe center;
  gap: clamp(24px, 5vh, 44px);
  padding: calc(var(--pad) + 60px) var(--pad) var(--pad);
  background: var(--paper);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.menu[hidden] { display: none; }

.menu__links {
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--ink-faint);
}

.menu__links a {
  display: flex;
  align-items: baseline;
  gap: clamp(12px, 4vw, 20px);
  padding: clamp(11px, 2.2vh, 18px) 0;
  border-bottom: 1px solid var(--ink-faint);
  font-size: clamp(21px, 6.4vw, 34px);
  font-weight: 300;
  letter-spacing: -0.01em;
  color: var(--ink-soft);
  transition: color 0.4s var(--ease-out), padding-left 0.5s var(--ease-out);
}

.menu__links a:hover,
.menu__links a:focus-visible {
  color: var(--ink);
  padding-left: 10px;
}

/* Current page in the mobile menu: full ink, and its number turns solid —
   the sheet's version of the desktop underline. */
.menu__links a.is-current {
  color: var(--ink);
}

.menu__links a.is-current i {
  color: var(--ink);
}

.menu__links i {
  font-style: normal;
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--ink-faint);
}

.menu__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(16px, 4vw, 26px);
}

.menu__tel {
  font-size: clamp(13px, 3.6vw, 16px);
  font-weight: 300;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 2px;
}

@media (max-width: 1180px) {
  .burger { display: block; }

  /* Nine labels on an ellipse need width this screen hasn't got — they land
     on top of the booking CTA and the credit line. The burger carries
     navigation here instead, so the dial stands down. */
  .dial { display: none; }

  /* Without the dial, pages only need to clear the corner furniture — the
     desktop clearance left a screen's worth of dead paper above the bar.
     (Type-qualified so these outrank the base rules further down the file.) */
  footer.foot { padding-bottom: clamp(96px, 14vh, 126px); }
  article.dpage { padding-bottom: clamp(96px, 14vh, 126px); }

  /* Its plate stood down with it, but the bottom corners still need paper
     under them. Same treatment: solid behind the furniture, short ramp above. */
  .chrome::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: calc(var(--pad) + 46px + 52px);
    background: linear-gradient(
      0deg,
      var(--paper) 0,
      var(--paper) calc(100% - 52px),
      transparent 100%
    );
    pointer-events: none;
  }
}

/* The menu is a phone/tablet affordance only — above the breakpoint the
   brandbar carries the links, so the panel must never be left open. */
@media (min-width: 1181px) {
  .menu { display: none !important; }
}

/* ── rotating dial nav ─────────────────────────────────────────
   Geometry, all measured from one origin (the pivot dot):
     --dial-r       horizontal radius of the ellipse the items ride on
     --dial-ry      vertical radius — flatter, so the nav is short
     --pivot-bottom height of the pivot above the dial's bottom edge
   All three are written by JS (src/dial.ts), which also positions each item —
   the values below are only the pre-script fallback. Items are centred on
   their point via translate(-50%, 50%). */
.dial {
  --dial-r: clamp(92px, 10vw, 150px);
  --dial-ry: calc(var(--dial-r) * 0.5);
  --pivot-bottom: clamp(30px, 4.2vh, 48px);
  position: absolute;
  left: 50%;
  bottom: 0;
  z-index: 1;
  width: min(92vw, 780px);
  /* Tall enough for an item at the top of the ellipse plus its line height. */
  height: calc(var(--pivot-bottom) + var(--dial-ry) + 2.2em);
  transform: translateX(-50%);
}

/* Paper backdrop for the whole dial area, full viewport width. Section copy
   scrolls underneath the fixed dial, so without an opaque plate behind it the
   labels sit on top of body text.
   Solid for its whole height, with a short ramp on the very top edge so
   content doesn't hit a guillotine line as it scrolls under. The ramp lives
   entirely ABOVE the dial box (hence the extra height), so every label still
   sits on flat paper — the old version faded across the labels themselves,
   which is what read as a grey wash.
   It is the FIRST child of .dial, so it paints behind the needle, pivot and
   labels while still covering everything in #scroller. */
.dial::before {
  --fade: 52px;
  content: "";
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 100vw;
  height: calc(100% + var(--fade));
  transform: translateX(-50%);
  background: linear-gradient(
    0deg,
    var(--paper) 0,
    var(--paper) calc(100% - var(--fade)),
    transparent 100%
  );
  pointer-events: none;
}

/* Plain container — the items inside are absolutely positioned against
   .dial, so this adds no layout of its own. */
.dial__ring {
  position: absolute;
  inset: 0;
}

.dial__pivot {
  position: absolute;
  left: 50%;
  /* -2.5px so the dot's centre, not its bottom edge, is the origin. */
  bottom: calc(var(--pivot-bottom) - 2.5px);
  width: 5px;
  height: 5px;
  margin-left: -2.5px;
  border-radius: 50%;
  background: var(--ink);
}

.dial__needle {
  position: absolute;
  left: 50%;
  bottom: calc(var(--pivot-bottom) - 0.5px);
  /* Stops just short of the active label, at 0.7 of the distance out to it.
     JS overwrites this with the exact ellipse radius along the needle's
     heading; the value here is only the pre-script fallback. */
  width: calc(var(--dial-r) * 0.7);
  height: 1px;
  background: var(--ink);
  /* Rotate about the left end so that end never leaves the pivot. */
  transform-origin: 0 50%;
  pointer-events: none;
}

.dial__item {
  position: absolute;
  left: 50%;
  bottom: var(--pivot-bottom);
  transform: translate(-50%, 50%);
  /* Nine labels ride one circle, so the type has to shrink with the radius —
     at 40° apart, "TESTIMONIALS" still has to clear its neighbours. */
  font-size: clamp(10px, 0.95vw, 15px);
  font-weight: 300;
  letter-spacing: 0.02em;
  line-height: 1;
  color: var(--ink-faint);
  white-space: nowrap;
  transition: color 0.45s var(--ease-out);
}

.dial__item:hover,
.dial__item.is-active {
  color: var(--ink);
}

/* ============================================================
   SECTIONS
   ============================================================ */
#scroller {
  position: relative;
  z-index: 5;
}

/* No min-height: a section is as tall as its content. Forcing every panel to
   a full viewport left short ones (the services list, the press row) trailing
   a screen of empty paper before the next heading. Each side contributes half
   the gap, so any two neighbours are exactly --gap apart. */
.panel {
  padding: var(--gap-half) var(--pad);
  max-width: 1180px;
  margin: 0 auto;
  /* Anchor jumps (the mobile menu, the footer index) put a section's top edge
     at the top of the viewport, where the fixed plate would cover its heading
     — most visibly on phones, where half the gap is smaller than the plate. */
  scroll-margin-top: var(--nav-h);
}

/* HOME is the floating-photo composition; the cards live in #stage. */
.panel--home {
  padding: 0;
  min-height: 100vh;
}


.panel__no {
  display: block;
  font-size: 11px;
  letter-spacing: 0.24em;
  color: var(--ink-faint);
  margin-bottom: clamp(12px, 2vw, 22px);
}

.panel__title {
  margin: 0 0 clamp(18px, 3vw, 34px);
  font-size: clamp(40px, 7vw, 108px);
  font-weight: 300;
  letter-spacing: -0.015em;
  line-height: 0.98;
}

.panel__lead {
  margin: 0;
  max-width: 46ch;
  font-size: clamp(14px, 1.5vw, 21px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-soft);
}

.panel__lead a {
  color: var(--ink);
  border-bottom: 1px solid var(--ink-faint);
}

.panel__list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 44ch;
}

.panel__list li {
  padding: clamp(10px, 1.4vw, 18px) 0;
  border-top: 1px solid var(--ink-faint);
  font-size: clamp(16px, 2vw, 30px);
  font-weight: 300;
  transition: padding-left 0.5s var(--ease-out), color 0.5s var(--ease-out);
  color: var(--ink-soft);
}

.panel__list li:hover {
  padding-left: 14px;
  color: var(--ink);
}

.panel__list--wide { max-width: 56ch; }

.panel__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(10px, 1.4vw, 20px);
  margin-top: clamp(20px, 3vw, 40px);
  max-width: 760px;
}

@media (min-width: 860px) {
  .panel__grid { grid-template-columns: repeat(4, 1fr); }
}

.panel__grid span {
  display: block;
  aspect-ratio: 4 / 5;
  background: linear-gradient(
    150deg,
    hsl(calc(var(--h) * 1deg) 16% 62%),
    hsl(calc((var(--h) + 40) * 1deg) 14% 28%)
  );
}

.panel__quote {
  margin: 0;
  max-width: 26ch;
  font-size: clamp(22px, 3.4vw, 52px);
  font-weight: 300;
  line-height: 1.22;
  letter-spacing: -0.01em;
}

.panel__quote cite {
  display: block;
  margin-top: clamp(14px, 2vw, 26px);
  font-size: clamp(11px, 1vw, 14px);
  font-style: normal;
  letter-spacing: 0.14em;
  color: var(--ink-faint);
}

/* ============================================================
   ABOUT
   Two columns: copy left, framed portrait right. The portrait PNG
   ships with its white border + drop shadow baked in, so the frame
   here is the image itself — no extra border.
   ============================================================ */
.panel--about {
  max-width: 1360px;
  /* Column flex: the bio grid is vertically centred by the padding, and the
     studio-story accordion stacks BELOW it at full width (as a row flex it
     became the grid's sibling column and crushed the bio into a sliver). */
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
  min-height: 100vh;
  padding: var(--gap-half) var(--pad);
}

.about {
  display: grid;
  /* Copy takes the flexible column; the portrait holds a firm right column so
     the headline never overruns it. minmax(0, …) lets the copy column shrink
     rather than forcing overflow. */
  grid-template-columns: minmax(0, 1fr) clamp(320px, 34vw, 480px);
  align-items: center;
  gap: clamp(28px, 4.5vw, 76px);
  width: 100%;
}

.about__copy {
  min-width: 0;
}

.about__eyebrow {
  display: block;
  font-size: clamp(14px, 1.5vw, 22px);
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: clamp(14px, 2vw, 26px);
}

.about__sub {
  margin: 0 0 clamp(16px, 2.6vw, 34px);
  font-size: clamp(28px, 3.9vw, 58px);
  font-weight: 500;
  line-height: 1.02;
  letter-spacing: -0.005em;
  color: var(--ink-soft);
}

.about__name {
  margin: 0 0 clamp(20px, 2.8vw, 38px);
  /* Sized to fit the copy column on one line at desktop widths, reaching
     toward the portrait like the mock without overrunning it. */
  font-size: clamp(42px, 6.1vw, 92px);
  font-weight: 500;
  line-height: 0.94;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

.about__text {
  margin: 0 0 clamp(26px, 3.4vw, 44px);
  max-width: 52ch;
  font-size: clamp(14px, 1.4vw, 19px);
  font-weight: 300;
  line-height: 1.62;
  color: var(--ink-soft);
}

/* Word-mask reveal: each word rides up out of its own clipped box. */
.a-word {
  display: inline-block;
  overflow: hidden;
  vertical-align: top;
}

.a-word__in {
  display: inline-block;
  will-change: transform;
}

/* Line-mask reveal for body copy: one clipped box per wrapped line. The box is
   block-level (its own row) and the inner span holds the whole line on one line
   (nowrap), so a captured line can't re-wrap and shift as it animates. */
.a-line {
  display: block;
  overflow: hidden;
}

.a-line__in {
  display: inline-block;
  white-space: nowrap;
  will-change: transform;
}

.about__more {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: clamp(13px, 1.1vw, 16px);
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
}

.about__more svg {
  width: 22px;
  height: 22px;
  transition: transform 0.5s var(--ease-out);
}

.about__more:hover svg {
  transform: translateX(8px);
}

/* Portrait. The wrapper is the reveal mask (clip-path); the img inside
   carries the scale + scroll parallax, so the two never fight over one
   transform. */
.about__media {
  justify-self: end;
  width: 100%;
  will-change: clip-path;
}

.about__media img {
  display: block;
  width: 100%;
  height: auto;
  will-change: transform;
}

@media (max-width: 900px) {
  .panel--about { min-height: auto; }
  .about {
    grid-template-columns: 1fr;
    gap: clamp(30px, 6vw, 48px);
  }
  .about__media {
    grid-row: 1;
    width: min(78%, 360px);
    justify-self: start;
  }
  .about__name { white-space: normal; }
}

/* ── the studio story: expandable index (full site copy) ── */
.studio-acc {
  margin-top: clamp(64px, 10vw, 140px);
  width: 100%;
}

/* Now its own section (moved to match the old site's order) — the panel's
   own top padding already provides the gap, so drop the extra margin that
   used to separate it from the About bio directly above it. */
#sec-story .studio-acc { margin-top: 0; }

.studio-acc__head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(20px, 4vw, 60px);
  margin-bottom: clamp(18px, 2.6vw, 34px);
}

.studio-acc__head h3 {
  margin: 0;
  font-size: clamp(26px, 3.6vw, 54px);
  font-weight: 300;
  letter-spacing: -0.015em;
}

/* A small print pinned beside the heading — the family frame the old site
   used for its "what we cover" story. */
.studio-acc__photo {
  margin: 0;
  flex: none;
  width: clamp(150px, 17vw, 250px);
  background: #fff;
  padding: 7px 7px 20px;
  box-shadow: 0 20px 44px -22px rgba(0, 0, 0, 0.4);
  rotate: 2.2deg;
}

.studio-acc__photo img { width: 100%; display: block; }

.studio-acc__photo figcaption {
  margin-top: 7px;
  text-align: center;
  font-size: 8.5px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

@media (max-width: 700px) {
  .studio-acc__photo { display: none; }
}

.studio-acc__item { border-top: 1px solid var(--ink-faint); }
.studio-acc__item:last-child { border-bottom: 1px solid var(--ink-faint); }

.studio-acc__btn {
  all: unset;
  cursor: pointer;
  display: grid;
  grid-template-columns: clamp(28px, 3.4vw, 52px) 1fr auto;
  align-items: center;
  gap: clamp(10px, 2vw, 26px);
  width: 100%;
  padding: clamp(14px, 1.8vw, 24px) 0;
  box-sizing: border-box;
}

.studio-acc__btn i {
  font-style: normal;
  font-size: 11px;
  letter-spacing: 0.18em;
  color: var(--ink-faint);
}

.studio-acc__btn b {
  font-size: clamp(17px, 2vw, 30px);
  font-weight: 300;
  letter-spacing: -0.01em;
  color: var(--ink-soft);
  transition: color 0.4s var(--ease-out), padding-left 0.5s var(--ease-out);
}

.studio-acc__btn:hover b { color: var(--ink); padding-left: clamp(6px, 1vw, 14px); }

/* Plus mark that turns into a minus when open. */
.studio-acc__btn em {
  position: relative;
  width: 14px;
  height: 14px;
}

.studio-acc__btn em::before,
.studio-acc__btn em::after {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 100%;
  height: 1.5px;
  background: var(--ink);
  transition: transform 0.5s var(--ease-out);
}

.studio-acc__btn em::after { transform: rotate(90deg); }

.studio-acc__item.is-open .studio-acc__btn em::after { transform: rotate(0deg); }
.studio-acc__item.is-open .studio-acc__btn b { color: var(--ink); }

/* Height is animated by GSAP; hidden at rest. */
.studio-acc__panel {
  height: 0;
  overflow: hidden;
}

.studio-acc__panel p {
  margin: 0;
  padding: 0 0 clamp(20px, 2.6vw, 34px);
  max-width: 68ch;
  font-size: clamp(13.5px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.65;
  color: var(--ink-soft);
}

/* ============================================================
   Shared CTA pill — the one hover everywhere: outline pill, ink
   wash rising from below. Same treatment as the corner CTA and
   the detail-page Book button.
   ============================================================ */
.inkbtn {
  all: unset;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  padding: clamp(10px, 1vw, 15px) clamp(20px, 2vw, 32px);
  border: 1px solid var(--ink);
  border-radius: 999px;
  font-size: clamp(11px, 0.9vw, 14px);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.5s var(--ease-out);
}

.inkbtn::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform 0.5s var(--ease-out);
}

.inkbtn:hover { color: var(--paper); }
.inkbtn:hover::before { transform: translateY(0); }

/* Light variant, for the dark band: paper outline, paper wash, ink text on hover. */
.inkbtn--light {
  border-color: var(--paper);
  color: var(--paper);
}

.inkbtn--light::before { background: var(--paper); }
.inkbtn--light:hover { color: var(--ink); }

/* ============================================================
   HOME SECTIONS — real Studio M content, editorial layouts.
   Shared: .panel--custom panels opt out of the generic reveal
   and are choreographed in src/home-sections.ts.
   ============================================================ */

/* ── 02 Categories: service index ─────────────────────── */
.svc { position: relative; }

.svc__title,
.pf__title,
.tst__title,
.art__title,
.ct__title,
.loc__title,
.expect__title {
  margin: 0 0 clamp(28px, 4.5vw, 64px);
  font-size: clamp(34px, 5.4vw, 84px);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: -0.02em;
}

.svc__lead,
.expect__lead {
  margin: clamp(-14px, -1.6vw, -30px) 0 clamp(30px, 4.5vw, 64px);
  max-width: 58ch;
  font-size: clamp(14px, 1.3vw, 19px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-soft);
}

.expect__lead { margin-bottom: clamp(12px, 1.4vw, 20px); }

.svc__list {
  display: block;
  border-top: 1px solid var(--ink-faint);
}

.svc__row {
  display: grid;
  grid-template-columns: clamp(30px, 4vw, 60px) 1fr auto clamp(30px, 3vw, 44px);
  align-items: baseline;
  gap: clamp(10px, 2vw, 28px);
  padding: clamp(16px, 2.2vw, 30px) 0;
  border-bottom: 1px solid var(--ink-faint);
  position: relative;
}

.svc__row i {
  font-style: normal;
  font-size: 12px;
  letter-spacing: 0.18em;
  color: var(--ink-faint);
}

.svc__row b {
  font-size: 32px;
  font-weight: 300;
  letter-spacing: -0.015em;
  color: var(--ink-soft);
  transition: color 0.4s var(--ease-out), padding-left 0.5s var(--ease-out);
}

.svc__row span {
  font-size: clamp(11px, 1vw, 14px);
  font-weight: 300;
  color: var(--ink-faint);
  transition: color 0.4s var(--ease-out);
}

.svc__row em {
  font-style: normal;
  font-size: clamp(18px, 2vw, 30px);
  justify-self: end;
  transform: translateX(-8px);
  opacity: 0;
  transition: transform 0.5s var(--ease-out), opacity 0.5s var(--ease-out);
}

.svc__row:hover b { color: var(--ink); padding-left: clamp(8px, 1.4vw, 22px); }

/* The old site's full per-category paragraph — wraps under the row instead
   of forcing it into the single-line tagline column. */
.svc__desc {
  grid-column: 2 / -1;
  margin: clamp(2px, 0.3vw, 4px) 0 0;
  max-width: 60ch;
  font-size: clamp(12.5px, 1vw, 14.5px);
  font-weight: 300;
  line-height: 1.55;
  color: var(--ink-soft);
}
.svc__row:hover span { color: var(--ink-soft); }
.svc__row:hover em { transform: translateX(0); opacity: 1; }

/* The thumbnail is a touch-screen affordance only: on a fine pointer the
   cursor-chasing preview shows the same photo, and a second copy in the row
   would just be noise. */
.svc__thumb { display: none; }

/* Cursor-chasing preview photo (categories + articles share this). */
.svc__preview {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 30;
  width: clamp(170px, 17vw, 250px);
  aspect-ratio: 4 / 5;
  padding: 8px 8px 22px;
  background: #fff;
  box-shadow: 0 24px 50px -20px rgba(0, 0, 0, 0.45);
  pointer-events: none;
  opacity: 0;
  will-change: transform;
}

.svc__preview img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ── services on touch screens ─────────────────────────────
   Four columns on a phone gives every row a squashed name beside a
   wrapping description. Below this width each row becomes a card
   instead: photo on the left, number/name/description stacked beside
   it — so the image, the heading and the body copy are all legible,
   and the hover-only preview (which a touch screen never sees) is
   replaced by something you can actually look at. */
@media (max-width: 760px) {
  .svc__list { border-top: 0; }

  .svc__row {
    grid-template-columns: 92px 1fr;
    grid-template-areas:
      "thumb num"
      "thumb name"
      "thumb desc"
      "para para"
      "cta cta";
    align-items: start;
    gap: 4px 16px;
    padding: 16px 0;
  }

  .svc__desc {
    grid-area: para;
    max-width: none;
    margin-top: 10px;
  }

  .svc__thumb {
    display: block;
    grid-area: thumb;
    width: 92px;
    aspect-ratio: 4 / 5;
    object-fit: cover;
    align-self: center;
    background: #fff;
    padding: 5px;
    box-shadow: 0 12px 26px -14px rgba(0, 0, 0, 0.42);
  }

  .svc__row i { grid-area: num; }

  .svc__row b {
    grid-area: name;
    font-size: clamp(22px, 6.4vw, 30px);
    line-height: 1.05;
    color: var(--ink);
  }

  .svc__row span {
    grid-area: desc;
    font-size: 13px;
    line-height: 1.45;
    color: var(--ink-soft);
  }

  /* Explicit tap affordance: swap the desktop hover-arrow for a "Know More →"
     label so mobile users see the row is clickable. */
  .svc__row em {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    grid-area: cta;
    justify-self: start;
    margin-top: 12px;
    font-style: normal;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink);
    transform: none;
    opacity: 1;
    text-indent: -9999px;
  }
  .svc__row em::before {
    content: "Know More →";
    text-indent: 0;
  }

  /* Tapping shouldn't shift the name sideways. */
  .svc__row:hover b { padding-left: 0; }
}

.svc__expect {
  margin-top: clamp(48px, 7vw, 100px);
  max-width: 680px;
}

.svc__expect h3 {
  margin: 0 0 clamp(14px, 2vw, 24px);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.svc__expect ol {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: expect;
}

.svc__expect li {
  counter-increment: expect;
  display: flex;
  gap: 16px;
  padding: clamp(10px, 1.4vw, 16px) 0;
  border-top: 1px solid var(--ink-faint);
  font-size: clamp(13px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.5;
  color: var(--ink-soft);
}

.svc__expect li::before {
  content: counter(expect, decimal-leading-zero);
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--ink-faint);
  padding-top: 4px;
}

.pf__lead {
  margin: clamp(-18px, -2vw, -36px) 0 clamp(30px, 4.5vw, 64px);
  font-size: clamp(14px, 1.3vw, 19px);
  font-weight: 300;
  color: var(--ink-soft);
}

/* ── 03 Portfolio: tabbed gallery (original UX, our clothes) ── */
.pf__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(14px, 2.4vw, 38px);
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: clamp(12px, 1.6vw, 20px);
  margin-bottom: clamp(28px, 4vw, 56px);
}

.pf__tab {
  all: unset;
  cursor: pointer;
  position: relative;
  font-size: clamp(14px, 1.5vw, 22px);
  font-weight: 300;
  letter-spacing: 0.01em;
  color: var(--ink-faint);
  padding-bottom: 6px;
  transition: color 0.4s var(--ease-out);
}

/* Hairline indicator grows in from the left under the active tab. */
.pf__tab::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1.5px;
  background: var(--ink);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform 0.5s var(--ease-out);
}

.pf__tab:hover { color: var(--ink-soft); }

.pf__tab.is-active { color: var(--ink); }
.pf__tab.is-active::after {
  transform: scaleX(1);
  transform-origin: left;
}

.pf__board {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(14px, 2vw, 30px) clamp(10px, 1.6vw, 26px);
  align-items: start;
  /* Reserve room so switching a tab never collapses the section height to
     zero mid-swap and yanks the scroll position around. */
  min-height: 40vh;
}

/* ── booking band: the one dark, faded-image section ─────
   Breaks out of the panel column to full viewport width. The
   background is the original site's darkened photo grid; a
   radial wash fades it into the band's black at the edges. */
.band {
  position: relative;
  width: 100vw;
  margin: clamp(48px, 7vw, 100px) 0 0 calc(50% - 50vw);
  padding: clamp(70px, 11vw, 150px) var(--pad);
  background: #0c0d10;
  overflow: hidden;
  text-align: center;
}

.band__bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.55;
  will-change: transform;
}

/* Fade the grid into the black at the edges — the "faded photos on dark"
   effect from the original site. */
.band::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(105% 90% at 50% 50%, transparent 22%, rgba(12, 13, 16, 0.94) 88%);
}

.band__in {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 1.8vw, 24px);
}

.band__eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: rgba(242, 241, 239, 0.55);
}

.band__title {
  margin: 0;
  font-size: clamp(26px, 3.8vw, 56px);
  font-weight: 300;
  line-height: 1.12;
  letter-spacing: -0.015em;
  color: var(--paper);
}

.band__trust {
  margin: 0;
  font-size: clamp(11px, 1vw, 14.5px);
  font-weight: 300;
  letter-spacing: 0.04em;
  color: rgba(242, 241, 239, 0.6);
}

.band__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(14px, 2vw, 26px);
  margin-top: clamp(6px, 1vw, 14px);
}

.band__alt {
  font-size: clamp(12px, 1vw, 15px);
  font-weight: 300;
  color: rgba(242, 241, 239, 0.75);
  border-bottom: 1px solid rgba(242, 241, 239, 0.3);
  padding-bottom: 2px;
  transition: color 0.4s var(--ease-out), border-color 0.4s var(--ease-out);
}

.band__alt:hover {
  color: var(--paper);
  border-color: var(--paper);
}

.pf__item {
  grid-column: var(--c);
  margin-top: var(--mt, 0);
  display: block;
  will-change: transform;
}

.pf__item figure img {
  aspect-ratio: var(--ar, 4 / 5);
  object-fit: cover;
}

.pf__item figure {
  margin: 0;
  overflow: hidden;
  background: #fff;
  padding: clamp(6px, 0.7vw, 10px);
  box-shadow: 0 20px 44px -22px rgba(0, 0, 0, 0.38);
}

.pf__item img {
  width: 100%;
  height: auto;
  display: block;
}

.pf__item span {
  display: inline-block;
  margin-top: 10px;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

@media (max-width: 760px) {
  .pf__item { grid-column: span 6 !important; margin-top: 0 !important; }
}

/* ── 04 Featured on: press marquee ────────────────────── */
.feat {
  max-width: none;          /* marquee runs edge to edge */
  overflow: hidden;
}

.feat .panel__no,
.feat__eyebrow,
.feat__note {
  max-width: 1180px;
  margin-left: auto;
  margin-right: auto;
  display: block;
}

.feat__eyebrow {
  margin: 0 auto clamp(30px, 5vw, 70px);
  font-size: clamp(24px, 3vw, 46px);
  font-weight: 300;
  letter-spacing: -0.01em;
}

.feat__marquee {
  border-top: 1px solid var(--ink-faint);
  border-bottom: 1px solid var(--ink-faint);
  padding: clamp(22px, 3.4vw, 48px) 0;
  white-space: nowrap;
  margin-bottom: clamp(26px, 4vw, 56px);
}

.feat__row {
  display: inline-flex;
  align-items: center;
  gap: clamp(24px, 3.4vw, 60px);
  padding-right: clamp(24px, 3.4vw, 60px);
  will-change: transform;
}

/* The press logos were built for the old site's dark background (two are
   near-white). brightness(0) recasts every one as an ink silhouette, so the
   mismatched originals read as a single engraved set on paper. */
.feat__row img {
  height: clamp(30px, 4vw, 62px);
  width: auto;
  filter: brightness(0);
  opacity: 0.72;
  transition: opacity 0.5s var(--ease-out);
}

.feat__row img:hover { opacity: 1; }

.feat__row em {
  font-style: normal;
  font-size: clamp(12px, 1.4vw, 20px);
  color: var(--accent, var(--ink-faint));
}

.feat__note {
  font-size: clamp(13px, 1.15vw, 17px);
  font-weight: 300;
  color: var(--ink-soft);
  max-width: 1180px;
}

/* ── 05 Testimonials: pinned prints ───────────────────── */
.tst__board {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: clamp(18px, 2.6vw, 38px);
  align-items: start;
}

.tst__card {
  margin: 0;
  background: #fff;
  padding: clamp(22px, 2.6vw, 38px) clamp(20px, 2.4vw, 34px) clamp(18px, 2vw, 28px);
  box-shadow: 0 22px 48px -24px rgba(0, 0, 0, 0.4), 0 2px 8px rgba(0, 0, 0, 0.05);
  rotate: var(--r, 0deg);
  transition: rotate 0.6s var(--ease-out), box-shadow 0.6s var(--ease-out);
  position: relative;
}

/* Quote tick, like a printer's mark. */
.tst__card::before {
  content: "“";
  position: absolute;
  top: 6px;
  left: clamp(16px, 2vw, 28px);
  font-size: clamp(44px, 4.4vw, 70px);
  line-height: 1;
  color: var(--ink-faint);
}

.tst__card:hover {
  rotate: 0deg;
  box-shadow: 0 34px 64px -26px rgba(0, 0, 0, 0.48), 0 4px 12px rgba(0, 0, 0, 0.07);
}

.tst__card p {
  margin: clamp(26px, 3vw, 42px) 0 clamp(14px, 1.6vw, 22px);
  font-size: clamp(13.5px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-soft);
}

.tst__card cite {
  font-style: normal;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* Middle column drops for a hand-placed feel. */
@media (min-width: 980px) {
  .tst__board { grid-template-columns: repeat(3, 1fr); }
  .tst__card:nth-child(2) { margin-top: clamp(30px, 4vw, 64px); }
  .tst__card:nth-child(3) { margin-top: clamp(14px, 2vw, 30px); }
  .tst__card:nth-child(4) { margin-top: clamp(-20px, -1vw, -8px); }
  .tst__card:nth-child(5) { margin-top: clamp(24px, 3vw, 48px); }
}

/* ── 06 Articles: journal index ───────────────────────── */
.art { position: relative; }

.art__list { border-top: 1px solid var(--ink-faint); }

.art__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: clamp(16px, 2vw, 26px) 0;
  border-bottom: 1px solid var(--ink-faint);
}

/* Every journal row carries its article's photo inline, at every width —
   a small print beside the title. */
.art__thumb {
  display: block;
  flex: none;
  width: clamp(64px, 6.4vw, 92px);
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: #fff;
  padding: 4px;
  box-shadow: 0 10px 22px -12px rgba(0, 0, 0, 0.4);
  transition: rotate 0.5s var(--ease-out);
}

.art__row { justify-content: flex-start; }
.art__row b { flex: 1; }
.art__row:hover .art__thumb { rotate: -2.4deg; }

.art__row b {
  font-size: clamp(15px, 1.7vw, 26px);
  font-weight: 300;
  letter-spacing: -0.005em;
  color: var(--ink-soft);
  transition: color 0.4s var(--ease-out), padding-left 0.5s var(--ease-out);
}

.art__row em {
  font-style: normal;
  font-size: clamp(15px, 1.6vw, 24px);
  color: var(--ink-faint);
  transition: transform 0.5s var(--ease-out), color 0.4s var(--ease-out);
}

.art__row:hover b { color: var(--ink); padding-left: clamp(6px, 1vw, 16px); }
.art__row:hover em { color: var(--ink); transform: translate(3px, -3px); }

/* ── 07 Contact ───────────────────────────────────────── */
.ct { text-align: left; }

.ct__cols {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(34px, 5vw, 72px);
  align-items: start;
}

@media (min-width: 960px) {
  .ct__cols { grid-template-columns: 1.1fr 0.9fr; }
}

.ct__mail {
  display: inline-block;
  margin: clamp(6px, 1vw, 14px) 0 clamp(26px, 3.4vw, 46px);
  font-size: clamp(20px, 2.9vw, 44px);
  font-weight: 300;
  letter-spacing: -0.015em;
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 8px;
  transition: border-color 0.5s var(--ease-out), letter-spacing 0.6s var(--ease-out);
  word-break: break-all;
}

.ct__mail:hover {
  border-color: var(--ink);
  letter-spacing: 0.002em;
}

/* The form — original fields, dressed as one of our prints. */
.ct__form {
  background: #fff;
  padding: clamp(24px, 2.8vw, 42px) clamp(22px, 2.6vw, 38px);
  box-shadow: 0 26px 54px -26px rgba(0, 0, 0, 0.42), 0 3px 9px rgba(0, 0, 0, 0.05);
  rotate: -0.8deg;
  display: flex;
  flex-direction: column;
  gap: clamp(16px, 1.8vw, 24px);
}

.ct__form label {
  display: flex;
  flex-direction: column;
  gap: 7px;
}

.ct__form label span {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.ct__form input,
.ct__form textarea {
  all: unset;
  box-sizing: border-box;
  width: 100%;
  font-family: var(--font);
  font-size: clamp(14px, 1.15vw, 17px);
  font-weight: 300;
  color: var(--ink);
  padding: 6px 0 9px;
  border-bottom: 1px solid var(--ink-faint);
  transition: border-color 0.4s var(--ease-out);
}

.ct__form input:focus,
.ct__form textarea:focus {
  border-color: var(--ink);
}

.ct__form textarea {
  resize: vertical;
  min-height: 84px;
  white-space: pre-wrap;
}

/* Honeypot: off-canvas, not display:none — some bots skip hidden fields. */
.ct__hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
}

.ct__formrow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-top: 4px;
}

.ct__status {
  font-size: clamp(11px, 0.95vw, 14px);
  font-weight: 300;
  color: var(--ink-soft);
}

.ct__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(16px, 2.6vw, 40px);
  font-size: clamp(12px, 1.05vw, 15px);
  font-weight: 300;
  color: var(--ink-soft);
}

/* Plain text links only — the pill keeps the shared .inkbtn hover. */
.ct__meta a:not(.inkbtn) { transition: opacity 0.4s var(--ease-out); }
.ct__meta a:not(.inkbtn):hover { opacity: 0.5; }

/* ── 08 Location ──────────────────────────────────────── */
.loc {
  position: relative;
}

.loc__title {
  font-size: clamp(52px, 9vw, 150px);
  line-height: 0.92;
  /* Watermark treatment: the place is scenery, the card is the message. */
  color: transparent;
  -webkit-text-stroke: 1.2px var(--ink-soft);
  margin-bottom: clamp(-30px, -2vw, -12px);
}

/* Address card + framed map, hand-placed over the watermark title. */
.loc__row {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: clamp(24px, 4vw, 64px);
  margin-left: clamp(10px, 4vw, 90px);
}

.loc__card {
  background: #fff;
  padding: clamp(24px, 3vw, 44px) clamp(26px, 3.4vw, 52px);
  box-shadow: 0 26px 54px -26px rgba(0, 0, 0, 0.42), 0 3px 9px rgba(0, 0, 0, 0.05);
  rotate: -1.6deg;
  max-width: 480px;
}

.loc__note {
  margin: 0 0 16px;
  max-width: 40ch;
  font-size: clamp(12px, 1vw, 15px);
  font-weight: 300;
  line-height: 1.55;
  color: var(--ink-soft);
}

.loc__lines {
  margin: 0 0 18px;
  font-size: clamp(13px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.6;
}

.loc__lines a { transition: opacity 0.4s var(--ease-out); }
.loc__lines a:hover { opacity: 0.5; }

.loc__dir {
  font-size: clamp(11px, 1vw, 14px);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 3px;
  transition: border-color 0.4s var(--ease-out);
}

.loc__dir:hover { border-color: var(--ink); }

/* The original site's Google map, matted like one of our prints. Greyscaled
   so the default map colours don't shout against the paper. */
.loc__map {
  margin: 0;
  flex: 1 1 380px;
  max-width: 620px;
  background: #fff;
  padding: clamp(8px, 0.9vw, 14px) clamp(8px, 0.9vw, 14px) clamp(26px, 2.6vw, 40px);
  box-shadow: 0 26px 54px -26px rgba(0, 0, 0, 0.42), 0 3px 9px rgba(0, 0, 0, 0.05);
  rotate: 1.4deg;
}

.loc__map iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 10;
  border: 0;
  filter: grayscale(1) contrast(1.04);
  transition: filter 0.6s var(--ease-out);
}

.loc__map:hover iframe { filter: grayscale(0.15) contrast(1); }

.loc__map figcaption {
  margin-top: 10px;
  text-align: center;
  font-size: 9px;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.loc__pin {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 12px;
}

.loc__card p {
  margin: 0 0 18px;
  font-size: clamp(16px, 1.7vw, 26px);
  font-weight: 300;
  line-height: 1.4;
}

.loc__card a {
  font-size: clamp(11px, 1vw, 14px);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 3px;
  transition: border-color 0.4s var(--ease-out);
}

.loc__card a:hover { border-color: var(--ink); }

.loc__coords {
  display: block;
  margin-top: clamp(26px, 4vw, 54px);
  font-size: 11px;
  letter-spacing: 0.3em;
  color: var(--ink-faint);
  text-transform: uppercase;
}

/* ============================================================
   FOOTER — end of the home scroll. Bottom padding clears the
   dial's fixed paper backdrop; the chrome corner line keeps the
   copyright, so this holds brand, links and office details.
   ============================================================ */
/* Last block on the page: the shared gap above, and below it only enough to
   clear the dial's fixed plate so the sign-off is never parked underneath it. */
.foot {
  max-width: 1180px;
  margin: 0 auto;
  padding: clamp(32px, 4.4vw, 64px) var(--pad) clamp(150px, 20vh, 200px);
  border-top: 1px solid var(--ink-faint);
}

/* One centred sign-off: the mark, the tagline, back to top. */
.foot__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: clamp(14px, 2vw, 24px);
  padding-top: clamp(24px, 3.4vw, 44px);
  border-top: 1px solid var(--ink-faint);
}

/* Big sign-off mark. Reuses the .logo structure at poster scale. */
.logo--foot { gap: 4px; }

.logo--foot .logo__row {
  font-size: clamp(44px, 6.5vw, 96px);
}

.logo--foot .logo__sub {
  font-size: clamp(12px, 1.8vw, 27px);
  letter-spacing: 0.18em;
}

.foot__tag {
  margin: 0;
  font-size: clamp(12px, 1.1vw, 16px);
  font-weight: 300;
  letter-spacing: 0.04em;
  color: var(--ink-soft);
}

.foot__top {
  all: unset;
  cursor: pointer;
  font-size: clamp(11px, 0.95vw, 13.5px);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 1px solid var(--ink-faint);
  padding-bottom: 2px;
  transition: border-color 0.4s var(--ease-out);
}

.foot__top:hover { border-color: var(--ink); }

/* ============================================================
   DETAIL PAGES
   Rendered client-side into #detail so the clicked card can morph
   into the hero. Inner pages carry NO dial — the top bar and the
   hero's own Book button are the navigation there.
   ============================================================ */
.detail {
  position: relative;
  z-index: 6;
}

/* Inner pages: the dial and the fixed bottom furniture are gone, and home's
   sections leave the layout entirely.
   This is applied only AFTER the transition settles (not the moment the view
   flips) so the fade-out can play first — and it must be `display: none`, not
   just transparency: a merely-faded #scroller still contributes its full height
   and the detail page inherits home's scroll length. */
/* The booking CTA is NOT in this list on purpose: it stays pinned to the
   corner on every page, exactly as on home. */
body.is-detail-settled #scroller,
body.is-detail-settled #stage,
body.is-detail-settled .dial,
body.is-detail-settled .chrome__bl {
  display: none;
}

/* The flying clone that morphs card → hero. Above everything, and never
   interactive — it is a visual stand-in only. */
.flyer {
  z-index: 80;
  overflow: hidden;
  background: #fff;
  pointer-events: none;
  box-shadow: 0 30px 70px -26px rgba(0, 0, 0, 0.45);
  will-change: left, top, width, height, transform;
}

.flyer img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.dpage {
  padding: 0 0 var(--gap);
}

/* ── hero ─────────────────────────────────────────────── */
.dpage__hero {
  /* This is the one block that starts at the very top of a page, so it has to
     clear the fixed nav plate outright — on phones half the gap is smaller
     than the plate, and the hero frame would slide underneath it. */
  padding: max(var(--gap-half), calc(var(--nav-h) + 14px)) var(--pad) 0;
}

.dpage__frame {
  position: relative;
  max-width: 1240px;
  margin: 0 auto;
  padding: clamp(10px, 1.1vw, 18px);
  background: #fff;
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.4), 0 3px 10px rgba(0, 0, 0, 0.05);
}

.dpage__media {
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
}

.dpage__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* The source photos are portraits — faces live in the upper part of the
     frame. A centred crop of a wide banner beheads them; biasing the window
     toward the top keeps every category's subject in view. */
  object-position: 50% 18%;
  display: block;
}

/* On phones the banner gets taller, so more of the portrait survives the crop. */
@media (max-width: 760px) {
  .dpage__media { aspect-ratio: 4 / 3; }
}

.dpage__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(16px, 3vw, 40px);
  padding: clamp(14px, 1.8vw, 24px) clamp(6px, 1vw, 16px) clamp(6px, 0.8vw, 12px);
}

.dpage__title {
  margin: 0;
  font-size: clamp(17px, 2.3vw, 34px);
  font-weight: 400;
  letter-spacing: -0.005em;
  line-height: 1.15;
}

.dpage__title b {
  font-weight: 600;
  color: var(--ink);
}

.dpage__title span { color: var(--ink-faint); }

.dpage__book {
  flex: none;
  display: inline-flex;
  align-items: center;
  padding: clamp(10px, 1vw, 15px) clamp(18px, 1.8vw, 30px);
  border: 1px solid var(--ink);
  border-radius: 999px;
  font-size: clamp(11px, 0.9vw, 14px);
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  position: relative;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.5s var(--ease-out);
}

.dpage__book::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ink);
  transform: translateY(101%);
  transition: transform 0.5s var(--ease-out);
}

.dpage__book:hover { color: var(--paper); }
.dpage__book:hover::before { transform: translateY(0); }

/* On phones the title wraps to three cramped lines beside the button;
   stacking gives both room. */
@media (max-width: 620px) {
  .dpage__bar {
    flex-direction: column;
    align-items: flex-start;
    gap: clamp(12px, 3vw, 18px);
  }
}

/* ── intro ────────────────────────────────────────────── */
.dpage__intro {
  max-width: 720px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__intro h2 {
  margin: 0 0 clamp(12px, 1.6vw, 20px);
  font-size: clamp(18px, 1.9vw, 27px);
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.01em;
}

.dpage__subhead {
  margin: 0 0 clamp(14px, 1.8vw, 22px) !important;
  font-style: italic;
  font-size: clamp(15px, 1.35vw, 20px);
  font-weight: 400;
  color: var(--ink);
}

.dpage__intro p {
  margin: 0 0 clamp(14px, 1.6vw, 20px);
  font-size: clamp(14px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.62;
  color: var(--ink-soft);
}

.dpage__intro p:last-child { margin-bottom: 0; }

/* ── gallery ──────────────────────────────────────────── */
.dpage__gallery {
  padding: var(--gap) var(--pad) 0;
  max-width: 1320px;
  margin: 0 auto;
}

.dpage__gtitle {
  margin: 0 0 clamp(24px, 4vw, 52px);
  font-size: clamp(26px, 4.4vw, 62px);
  font-weight: 400;
  letter-spacing: -0.015em;
  line-height: 1;
}

/* Editorial scatter: a 12-column grid where each shot takes a different span
   and vertical offset, so the column edges never line up in a row. */
.dpage__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(14px, 2vw, 34px);
  align-items: start;
}

.dpage__shot {
  margin: 0;
  overflow: hidden;
}

.dpage__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.9s var(--ease-out);
}

.dpage__shot:hover img { transform: scale(1.04); }

/* The scatter is a six-step pattern that REPEATS, so a gallery of any
   length keeps its rhythm. Fixed nth-child(1..6) left a seventh and eighth
   photograph with no column of their own, and they collapsed to thumbnails. */
@media (min-width: 860px) {
  .dpage__shot:nth-child(6n + 1) { grid-column: 1 / span 4; aspect-ratio: 3 / 4; }
  .dpage__shot:nth-child(6n + 2) { grid-column: 5 / span 3; aspect-ratio: 4 / 5; margin-top: 14vh; }
  .dpage__shot:nth-child(6n + 3) { grid-column: 9 / span 4; aspect-ratio: 3 / 4; margin-top: -2vh; }
  .dpage__shot:nth-child(6n + 4) { grid-column: 6 / span 3; aspect-ratio: 1 / 1; margin-top: 4vh; }
  .dpage__shot:nth-child(6n + 5) { grid-column: 2 / span 4; aspect-ratio: 4 / 5; margin-top: -6vh; }
  .dpage__shot:nth-child(6n + 6) { grid-column: 8 / span 4; aspect-ratio: 3 / 4; margin-top: 6vh; }
}

/* Two tidy columns below the scatter breakpoint. */
@media (max-width: 859px) {
  .dpage__shot { grid-column: span 6; aspect-ratio: 3 / 4; }
  .dpage__shot:nth-child(even) { margin-top: 5vh; }
}

/* ── footer ───────────────────────────────────────────── */
.dpage__foot {
  max-width: 1320px;
  margin: var(--gap) auto 0;
  padding: clamp(32px, 4.4vw, 64px) var(--pad) 0;
  border-top: 1px solid var(--ink-faint);
}

/* Bio blurb takes the widest column; the two link lists share the rest.
   (No contact column here — the office card just above the footer already
   carries the address, phone and email.) */
.dpage__footgrid {
  display: grid;
  grid-template-columns: minmax(0, 1.8fr) repeat(2, minmax(0, 1fr));
  gap: clamp(24px, 3.6vw, 64px);
}

.dpage__footcol {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(8px, 1vw, 12px);
}

.dpage__footcol .dpage__kicker { margin-bottom: clamp(4px, 0.6vw, 8px); }

.dpage__footcol p,
.dpage__footcol a {
  margin: 0;
  font-size: clamp(12.5px, 1.05vw, 15px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-soft);
}

.dpage__footcol a { transition: color 0.4s var(--ease-out); }
.dpage__footcol a:hover { color: var(--ink); }

.dpage__footcol--bio p { max-width: 38ch; }

/* The centred sign-off borrows the home footer's clothes; only the distance
   from the link columns above is this page's own. */
.dpage__footbrand {
  margin-top: clamp(36px, 5vh, 64px);
}

.dpage__footbar {
  margin-top: clamp(28px, 4vh, 48px);
  padding: clamp(14px, 2vh, 22px) 0 0;
  border-top: 1px solid var(--ink-faint);
  display: flex;
  justify-content: center;
  text-align: center;
  font-size: clamp(11px, 1vw, 13px);
  font-weight: 300;
  color: var(--ink-soft);
}

@media (max-width: 900px) {
  .dpage__footgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dpage__footcol--bio { grid-column: 1 / -1; }
}


/* ── inner-page content sections (story → features → quotes →
   FAQ → booking band), sharing the home page's clothes ──── */

/* Small caps label that opens every section. */
.dpage__kicker {
  display: block;
  margin-bottom: clamp(12px, 1.6vw, 22px);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* Story: editorial two-column — title column left, copy right. */
.dpage__story {
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: clamp(28px, 5vw, 90px);
  align-items: start;
  max-width: 1320px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__shead h2 {
  margin: 0;
  font-size: clamp(28px, 3.8vw, 58px);
  font-weight: 300;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.dpage__sbody p {
  margin: 0 0 clamp(16px, 2vw, 26px);
  max-width: 62ch;
  font-size: clamp(14px, 1.2vw, 17.5px);
  font-weight: 300;
  line-height: 1.65;
  color: var(--ink-soft);
}

.dpage__sbody p:last-child { margin-bottom: 0; }

/* First paragraph carries a hanging hairline, like a pull-quote rule. */
.dpage__sbody p:first-child {
  padding-top: clamp(14px, 1.8vw, 24px);
  border-top: 1px solid var(--ink-faint);
}

@media (max-width: 900px) {
  .dpage__story { grid-template-columns: 1fr; }
}

/* Features: the numbered index rows the home services list uses. */
.dpage__feats {
  max-width: 1320px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__feats h2 {
  margin: 0 0 clamp(24px, 3.6vw, 52px);
  font-size: clamp(28px, 3.8vw, 58px);
  font-weight: 300;
  line-height: 1.05;
  letter-spacing: -0.02em;
  max-width: 18ch;
}

.dpage__featlist {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink-faint);
}

.dpage__feat {
  display: grid;
  grid-template-columns: clamp(30px, 4vw, 60px) 1fr;
  gap: clamp(10px, 2vw, 28px);
  padding: clamp(18px, 2.6vw, 36px) 0;
  border-bottom: 1px solid var(--ink-faint);
}

.dpage__feat i {
  font-style: normal;
  font-size: 12px;
  letter-spacing: 0.18em;
  color: var(--ink-faint);
  padding-top: clamp(4px, 0.6vw, 9px);
}

.dpage__feat b {
  display: block;
  margin-bottom: clamp(8px, 1vw, 14px);
  font-size: clamp(18px, 2.2vw, 32px);
  font-weight: 300;
  letter-spacing: -0.01em;
  color: var(--ink);
}

.dpage__feat p {
  margin: 0;
  max-width: 68ch;
  font-size: clamp(13.5px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.62;
  color: var(--ink-soft);
}

/* Quotes: the home testimonial prints, two to a table. */
.dpage__quotes {
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__qboard { align-items: start; }

@media (min-width: 980px) {
  .dpage__qboard { grid-template-columns: repeat(2, 1fr); }
  .dpage__qboard .tst__card:nth-child(2) { margin-top: clamp(26px, 3.4vw, 56px); }
}

/* FAQ: the studio-story accordion, narrowed to reading width. */
.dpage__faq {
  max-width: 1000px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__faq h2 {
  margin: 0 0 clamp(20px, 3vw, 40px);
  font-size: clamp(28px, 3.8vw, 58px);
  font-weight: 300;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

/* The accordion block itself needs no extra headroom here — the section
   provides it. */
.dpage__acc { margin-top: 0; }

/* Booking band inside a detail page: give it air before the footer and
   keep the full-bleed breakout working from inside the article. */
.dpage__band {
  margin-top: var(--gap);
}

/* ── standalone pages (About, Contact) ─────────────────────────
   Text-first pages with no photo hero: a big page header, then the
   same section clothes the rest of the site wears. */
.dpage__head {
  max-width: 1320px;
  margin: 0 auto;
  padding: max(var(--gap-half), calc(var(--nav-h) + 14px)) var(--pad) 0;
}

.dpage__head h1 {
  margin: 0;
  font-size: clamp(38px, 6vw, 92px);
  font-weight: 300;
  line-height: 1.02;
  letter-spacing: -0.02em;
}

.dpage__ct,
.dpage__office {
  max-width: 1320px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

/* Social marks, now in the footer rather than pinned to the viewport
   corner — same row of three, centred with the sign-off. */
.foot__social {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(16px, 2vw, 26px);
  margin-top: clamp(28px, 4vh, 48px);
}

.foot__social a {
  display: block;
  color: var(--ink-soft);
  transition: color 0.4s var(--ease-out), transform 0.4s var(--ease-out);
}

.foot__social a svg {
  display: block;
  width: 20px;
  height: 20px;
}

.foot__social a:hover {
  color: var(--ink);
  transform: translateY(-2px);
}

/* ── Inner-page sections, in the old site's order ──────────
   One rule set per section type; the page just stacks them. */
.dpage__sec {
  max-width: 900px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

/* A heading-less prose section (no h2 rendered) reads as a continuation of
   whatever came before it, not a new topic — the full inter-section gap
   leaves a void with nothing to anchor it. Halve it. */
.dpage__sec--prose:not(:has(h2)) {
  padding-top: calc(var(--gap) / 2);
}

.dpage__sec h2 {
  margin: 0 0 clamp(24px, 3.6vw, 52px);
  font-size: clamp(28px, 3.8vw, 58px);
  font-weight: 300;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.dpage__prose p {
  margin: 0 0 clamp(16px, 2vw, 24px);
  font-size: clamp(14.5px, 1.2vw, 17.5px);
  font-weight: 300;
  line-height: 1.68;
  color: var(--ink-soft);
}

.dpage__prose p:last-child { margin-bottom: 0; }

/* The line the wedding page prints under its questions. */
.dpage__faqnote {
  margin: clamp(20px, 2.6vw, 32px) 0 0;
  font-size: clamp(13.5px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* An expandable group inside a page — the home page's studio index, reused. */
.dpage__accsec {
  max-width: 1180px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__accsec .studio-acc { margin-top: 0; }

/* An open row sets its copy beside the photograph rather than leaving the
   right-hand half of the page empty. */
.acc__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) clamp(200px, 22vw, 290px);
  gap: clamp(24px, 4vw, 56px);
  align-items: start;
  padding-bottom: clamp(20px, 2.6vw, 34px);
}

.acc__copy p {
  margin: 0 0 clamp(14px, 1.8vw, 22px);
  padding: 0;
  max-width: 62ch;
  font-size: clamp(13.5px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.65;
  color: var(--ink-soft);
}

.acc__copy p:last-child { margin-bottom: 0; }

.acc__photo {
  margin: 0;
  justify-self: end;
  background: #fff;
  padding: clamp(6px, 0.7vw, 10px);
  box-shadow: 0 22px 48px -24px rgba(0, 0, 0, 0.42);
  rotate: 1.6deg;
}

.acc__photo img {
  display: block;
  width: 100%;
  /* The portraits are full-length, so a landscape crop takes the subject's
     head off — the print keeps its shape and is simply set smaller. */
  aspect-ratio: 4 / 5;
  object-fit: cover;
}

@media (max-width: 820px) {
  .acc__body { grid-template-columns: 1fr; }
  /* Stacked under the copy, the print centres instead of hanging off the
     right edge where the two-column rule had put it. */
  .acc__photo {
    width: min(72%, 300px);
    justify-self: center;
  }
}

/* Copy beside a pair of prints; the pair swaps sides down the page. */
.dpage__sec--split {
  display: grid;
  /* The copy column is deliberately narrower than the picture column: a
     measure you can actually read, and room for the prints to breathe. */
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1fr);
  gap: clamp(28px, 6vw, 110px);
  align-items: center;
  max-width: 1300px;
}

.dpage__sec--split.is-flipped .dpage__splitcopy { order: 2; }

.dpage__splitcopy { position: relative; }



/* Two prints, overlapping — a dominant frame with a second tucked into its
   lower corner, rather than two equal tiles side by side. */
.dpage__pics {
  position: relative;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  align-items: start;
}

.dpage__pic {
  margin: 0;
  background: #fff;
  padding: clamp(7px, 0.8vw, 12px);
  box-shadow: 0 30px 60px -28px rgba(0, 0, 0, 0.45);
  overflow: hidden;
}

.dpage__pic img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 1s var(--ease-out);
}

.dpage__pic:hover img { transform: scale(1.06); }

/* Large frame: portrait, occupying the left two-thirds of the column. */
.dpage__pic--1 {
  grid-area: 1 / 1 / 2 / 7;
  rotate: -1.6deg;
}

.dpage__pic--1 img { aspect-ratio: 4 / 5; }

/* Smaller frame: landscape, overlapping the big one's lower-right corner and
   hanging below it so the pair reads as prints laid on a desk. */
.dpage__pic--2 {
  grid-area: 1 / 5 / 2 / 9;
  align-self: end;
  margin-bottom: clamp(-90px, -9vw, -40px);
  rotate: 2.4deg;
  z-index: 1;
}

.dpage__pic--2 img { aspect-ratio: 1 / 1; }

/* The overlap hangs below the grid, so the section needs the room back. */
.dpage__sec--split { padding-bottom: clamp(40px, 6vw, 90px); }

@media (max-width: 860px) {
  .dpage__sec--split {
    grid-template-columns: 1fr;
    /* Just enough for the hang and the rotation — no more, so the space to
       the next section stays exactly one gap. */
    padding-bottom: clamp(10px, 3.4vw, 18px);
  }
  .dpage__sec--split.is-flipped .dpage__splitcopy { order: 0; }
  .dpage__pic--1 { grid-area: 1 / 1 / 2 / 8; }
  .dpage__pic--2 {
    grid-area: 1 / 5 / 2 / 9;
    margin-bottom: clamp(-26px, -5vw, -14px);
  }
}

/* "Other Photography" — the three sub-pages, as prints with a caption bar. */
.dpage__other {
  max-width: 1320px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__othergrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 2.4vw, 34px);
}

.dpage__othercard {
  display: block;
  background: #fff;
  box-shadow: 0 22px 48px -24px rgba(0, 0, 0, 0.4);
  overflow: hidden;
}

.dpage__othercard img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  transition: transform 0.9s var(--ease-out);
}

.dpage__othercard:hover img { transform: scale(1.05); }

.dpage__othergrid { }

@media (max-width: 720px) {
  .dpage__othergrid { grid-template-columns: 1fr; }
}

.dpage__othercard span {
  display: block;
  padding: clamp(12px, 1.4vw, 18px) clamp(14px, 1.6vw, 20px);
  font-size: clamp(13px, 1.1vw, 16px);
  font-weight: 500;
  letter-spacing: 0.02em;
}

/* ── Journal article pages ─────────────────────────────────
   A reading column, not an editorial scatter: one measure, generous
   leading, and the same paper the rest of the site is printed on. */
.apage__head {
  max-width: 820px;
  margin: 0 auto;
  padding: max(var(--gap-half), calc(var(--nav-h) + 20px)) var(--pad) 0;
}

.apage__head h1 {
  margin: 0 0 clamp(18px, 2.4vw, 30px);
  font-size: clamp(30px, 4.4vw, 62px);
  font-weight: 300;
  line-height: 1.04;
  letter-spacing: -0.02em;
}

.apage__lead {
  margin: 0;
  font-size: clamp(16px, 1.5vw, 22px);
  font-weight: 300;
  line-height: 1.55;
  color: var(--ink-soft);
}

.apage__cover {
  max-width: 1100px;
  margin: clamp(28px, 4vw, 56px) auto 0;
  padding: 0 var(--pad);
}

.apage__cover img {
  display: block;
  width: 100%;
  height: auto;
  background: #fff;
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.4);
}

.apage__body {
  max-width: 720px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.apage__body h2 {
  margin: clamp(34px, 4.4vw, 60px) 0 clamp(12px, 1.6vw, 20px);
  font-size: clamp(20px, 2.2vw, 30px);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.apage__body h2:first-child { margin-top: 0; }

.apage__body p {
  margin: 0 0 clamp(16px, 2vw, 24px);
  font-size: clamp(14.5px, 1.2vw, 17.5px);
  font-weight: 300;
  line-height: 1.7;
  color: var(--ink-soft);
}

.apage__list {
  margin: 0 0 clamp(16px, 2vw, 24px);
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--ink-faint);
}

.apage__list li {
  padding: clamp(12px, 1.6vw, 18px) 0;
  border-bottom: 1px solid var(--ink-faint);
  font-size: clamp(14px, 1.15vw, 17px);
  font-weight: 300;
  line-height: 1.62;
  color: var(--ink-soft);
}

/* Photos from the original post, as prints on the page. */
.apage__gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: clamp(16px, 2.4vw, 34px);
  max-width: 1100px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.apage__gallery figure { margin: 0; }

.apage__gallery img {
  display: block;
  width: 100%;
  height: auto;
  background: #fff;
  padding: clamp(6px, 0.7vw, 10px);
  box-shadow: 0 20px 44px -22px rgba(0, 0, 0, 0.4);
}

.apage__more {
  max-width: 1000px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.apage__more .art__list { border-top: 1px solid var(--ink-faint); }

/* Copy carried over from the old site, set as a reading column below the
   designed sections. */
.dpage__more-copy {
  max-width: 760px;
  margin: 0 auto;
  padding: var(--gap) var(--pad) 0;
}

.dpage__pull {
  margin: clamp(20px, 3vw, 34px) 0;
  padding: clamp(18px, 2.4vw, 30px) clamp(20px, 2.6vw, 34px);
  background: #fff;
  box-shadow: 0 22px 48px -24px rgba(0, 0, 0, 0.4);
  font-size: clamp(14px, 1.2vw, 17px);
  font-weight: 300;
  line-height: 1.6;
  color: var(--ink-soft);
}

/* ── About hero: the home bio composition as a page opener ──
   Eyebrow, grey location line, the name in full ink, bio copy and CTA on
   the left; the studio portrait as a white-framed print on the right. */
.ahero {
  display: grid;
  grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
  gap: clamp(28px, 5vw, 90px);
  align-items: center;
  max-width: 1320px;
  margin: 0 auto;
  padding: max(var(--gap-half), calc(var(--nav-h) + 20px)) var(--pad) 0;
}

.ahero__eyebrow {
  display: block;
  margin-bottom: clamp(14px, 2vw, 26px);
  font-size: clamp(13px, 1.15vw, 17px);
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.ahero__loc {
  margin: 0 0 clamp(8px, 1.2vw, 16px);
  font-size: clamp(28px, 3.4vw, 52px);
  font-weight: 500;
  line-height: 1.04;
  letter-spacing: -0.005em;
  color: var(--ink-soft);
}

.ahero__name {
  margin: 0 0 clamp(18px, 2.4vw, 34px);
  font-size: clamp(38px, 5.4vw, 84px);
  font-weight: 600;
  line-height: 0.96;
  letter-spacing: -0.02em;
}

.ahero__copy p {
  margin: 0 0 clamp(24px, 3vw, 40px);
  max-width: 52ch;
  font-size: clamp(14px, 1.3vw, 19px);
  font-weight: 300;
  line-height: 1.62;
  color: var(--ink-soft);
}

/* The asset carries its own white matte with a dark distressed edge; the
   frame clips a whisker in from every side so only clean matte shows. */
.ahero__media {
  margin: 0;
  overflow: hidden;
  background: #fff;
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, 0.4), 0 3px 10px rgba(0, 0, 0, 0.05);
}

.ahero__media img {
  display: block;
  width: 106%;
  height: auto;
  margin: -3%;
}

@media (max-width: 900px) {
  .ahero { grid-template-columns: 1fr; }
  .ahero__media {
    grid-row: 1;
    width: min(78%, 380px);
  }
}

/* Marvin leaning on the form card, as shot — the cutout's resting arm lands
   on the card's top edge. Absolutely positioned so the grid never reflows,
   and click-transparent so the fields under his elbow stay usable. */
.dpage__ct .ct__cols { position: relative; }

.ct__marvin {
  position: absolute;
  right: calc(-1 * clamp(40px, 7vw, 110px));
  bottom: -16px;
  height: calc(100% + clamp(120px, 14vw, 200px));
  width: auto;
  pointer-events: none;
  user-select: none;
  filter: drop-shadow(0 30px 40px rgba(0, 0, 0, 0.18));
}

/* The cutout is a wide-desktop flourish only. Measured: at 1100px he stands
   ON the fields with his elbow over the first input, and at tablet widths he
   spills past the section boundary. He earns his place from 1280px up. */
@media (max-width: 1279px) {
  .ct__marvin { display: none; }
}

/* The card gives up its last stretch so Marvin stands BESIDE it, arm over
   the top-right corner, the way the reference has it — rather than standing
   on the card with the fields running under him. Only where he is shown:
   narrower than this the form keeps its full column. */
@media (min-width: 1280px) {
  .dpage__ct .ct__form {
    width: 80%;
  }
}

.dpage__office h2,
.dpage__ct h2 {
  margin: 0 0 clamp(24px, 3.6vw, 52px);
  font-size: clamp(28px, 3.8vw, 58px);
  font-weight: 300;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

/* ============================================================
   Small screens: the photographer would eat the type, so drop
   the crop back and tighten the dial.
   ============================================================ */
@media (max-width: 760px) {
  /* Phones get a much tighter rhythm — 200px of paper between sections is
     most of a screen here, where the desktop version reads as generous. */
  :root { --gap: 48px; }

  /* He used to be pushed most of the way off the right edge, leaving just a
     pair of hands and a lens. Sitting flush with the edge keeps the camera
     in frame and the head in shot — but smaller than before, so the wordmark
     below keeps its own ground. */
  .shooter {
    height: 46vh;
    right: -6vw;
    max-width: 62vw;
    opacity: 0.85;
  }

  /* On phones the type rides ABOVE the photographer (desktop keeps it
     behind), higher up and without the indent, with a soft paper halo where
     a letter still crosses the dark shirt — the words must stay readable. */
  .loader__type {
    bottom: 16vh;
    z-index: 11;
  }
  .wordmark {
    font-size: clamp(24px, 8.8vw, 46px);
    text-shadow:
      0 0 10px var(--paper),
      0 0 22px var(--paper),
      0 0 34px var(--paper);
  }
  .wordmark--indent { padding-left: 0; }
  .tagline {
    text-shadow: 0 0 10px var(--paper), 0 0 20px var(--paper);
  }

  .card { width: 150px; margin-left: -75px; margin-top: -95px; }
  .hero__tr { gap: 1px; }
}

@media (prefers-reduced-motion: reduce) {
  .flash { display: none; }
}
