/* =========================================================
   Divisha Bhatia — Portfolio
   Built on tokens/design-tokens.css. Square corners, no
   cards/shadows, oxblood editorial accents, slow reversible
   motion. Desktop-first canvas at 1440px, fluid down to 360px.
   ========================================================= */

* { box-sizing: border-box; }
img { max-width: 100%; }

/* Text selection highlight — Powder Blue (the same accent used on the
   homepage hero's decorative squiggle) instead of the browser's
   generic default blue, so selecting text stays on-brand. */
::selection { background: var(--color-blue); color: var(--color-plum); }

/* Consistent 40px rhythm between every section — overrides the token
   file's larger clamp() so hero/statement/work/filmstrip/about/footer
   all sit the same distance apart instead of a mix of one-off values. */
:root { --section-space: 40px; }

/* Decorative bleed elements (about circle, scaled statement image,
   sliding filmstrip track) intentionally extend past their section's
   edge — clip that overflow at the document level so it never forces
   page-wide horizontal scroll. */
html, body { overflow-x: hidden; }

/* Paper-grain warmth over the ivory page background — fixed so it
   doesn't repeat/shift with scroll. This texture (regenerated with
   visible fiber grain) reads at a moderate tile size and opacity;
   the earlier source was so low-contrast it needed to be cranked to
   .9 opacity just to register, which is no longer necessary here.
   Sits behind all content (z-index -1) and never intercepts clicks. */
body { position: relative; }
body::before {
  content: ""; position: fixed; inset: 0; z-index: -1;
  background: url('assets/images/texture-ivory.jpg') center/700px repeat;
  opacity: .6;
  pointer-events: none;
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.skip-link {
  position: fixed; top: -60px; left: 12px; z-index: 200;
  background: var(--color-oxblood); color: #fff; padding: 10px 16px;
  font: 500 13px/1 var(--font-ui); text-decoration: none; transition: top .25s var(--ease-editorial);
}
.skip-link:focus { top: 12px; }

/* Site-wide custom cursor — a small oxblood dot that tracks the real
   pointer (see script.js) and scales up over links/buttons/photos.
   Desktop pointer only: script.js gates this behind the same
   (hover: hover) and (pointer: fine) check used for the hero/arc
   parallax, so touch devices keep their native tap behaviour and this
   element is simply never shown there. `cursor: none` on <html> hides
   the real system cursor only once that gate has actually passed
   (toggled via the .has-custom-cursor class), so a touch visit or a
   JS failure never leaves the visitor without any cursor at all. */
html.has-custom-cursor, html.has-custom-cursor a, html.has-custom-cursor button { cursor: none; }
/* Two-part editorial cursor: a tight center dot that tracks the
   pointer exactly, plus a larger ring that trails a beat behind it
   (its own, slower transition on the same transform) — a common
   premium-photography-site cursor treatment, more considered than a
   single flat dot. Over a photo/gallery trigger the ring expands and
   reveals a small "View" label; over a plain link it just grows. */
.cursor-dot {
  position: fixed; top: 0; left: 0; z-index: 300;
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--color-oxblood);
  transform: translate3d(-50%, -50%, 0);
  pointer-events: none;
  opacity: 0;
  transition: opacity .2s var(--ease-editorial), background-color .2s var(--ease-editorial);
}
.cursor-dot.is-active { opacity: 1; }
.cursor-dot.is-hovering { background: transparent; }

.cursor-ring {
  position: fixed; top: 0; left: 0; z-index: 299;
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--color-oxblood);
  transform: translate3d(-50%, -50%, 0) scale(.4);
  pointer-events: none;
  opacity: 0;
  display: grid; place-items: center;
  transition: opacity .25s var(--ease-editorial), transform .5s var(--ease-editorial),
              border-color .3s var(--ease-editorial), background-color .3s var(--ease-editorial);
}
.cursor-ring.is-active { opacity: 1; }
.cursor-ring.is-hovering {
  transform: translate3d(-50%, -50%, 0) scale(1);
  background: var(--color-oxblood);
}
.cursor-ring.is-hovering-media {
  transform: translate3d(-50%, -50%, 0) scale(1.6);
  background: rgba(23,23,23,.72);
  border-color: transparent;
}
.cursor-ring__label {
  font: 400 10px/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: #fff; opacity: 0; transition: opacity .2s var(--ease-editorial);
  white-space: nowrap;
}
.cursor-ring.is-hovering-media .cursor-ring__label { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .cursor-dot, .cursor-ring { display: none; } }

/* Site-wide sticky WhatsApp button — fixed bottom-right on every page,
   above the lightbox/nav z-index so it's always reachable. A small
   settle-in animation on load rather than appearing instantly, same
   restrained-motion approach as the rest of the site. */
.whatsapp-button {
  position: fixed; z-index: 250;
  right: clamp(16px, 3vw, 32px); bottom: clamp(16px, 3vw, 32px);
  width: 56px; height: 56px; border-radius: 50%;
  display: grid; place-items: center;
  background: #fff;
  box-shadow: 0 4px 16px rgba(23,23,23,.22);
  opacity: 0; transform: scale(.7);
  transition: opacity .5s var(--ease-editorial), transform .5s var(--ease-editorial), box-shadow .25s var(--ease-editorial);
}
.whatsapp-button.is-visible { opacity: 1; transform: scale(1); }
.whatsapp-button:hover, .whatsapp-button:focus-visible { box-shadow: 0 6px 22px rgba(23,23,23,.3); transform: scale(1.06); }
.whatsapp-button img { width: 38px; height: 38px; border-radius: 50%; }
@media (prefers-reduced-motion: reduce) { .whatsapp-button { transition: opacity .2s; transform: none !important; } }

/* Scroll progress hairline — echoes the thin-line motif used in the
   header/footer. Fixed at the very top, fills left-to-right with
   scroll position. Barely-there until noticed; never blocks clicks. */
.scroll-progress {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 100;
  background: rgba(23, 23, 23, .06); pointer-events: none;
}
.scroll-progress span {
  display: block; height: 100%; width: 0%;
  background: var(--color-oxblood);
  transition: width .1s linear;
}
@media (prefers-reduced-motion: reduce) {
  .scroll-progress span { transition: none; }
}

a { color: inherit; }
:focus-visible { outline: 2px solid var(--color-oxblood); outline-offset: 3px; }

/* ---------- Header ---------- */
.site-header {
  min-height: 88px;
  display: flex; align-items: center; gap: 24px;
  position: relative; z-index: 20;
}
.wordmark {
  font: 500 19px/1 var(--font-ui); letter-spacing: .2em; text-transform: uppercase;
  text-decoration: none; white-space: nowrap;
}
.wordmark__rule { width: 46px; height: 8px; margin-right: auto; opacity: .8; }
.site-header nav { display: flex; gap: clamp(18px, 2.5vw, 42px); }
.site-header nav a {
  color: inherit; font-size: 13px; text-decoration: none; position: relative; padding-bottom: 2px;
}
/* Animation guide section 7: underline grows left-to-right in Powder
   Blue via a scaleX transform (not a width/right animation). */
.site-header nav a::after {
  content: ""; position: absolute; left: 0; bottom: -7px; width: 100%; height: 2px;
  background: var(--color-blue);
  transform: scaleX(0); transform-origin: right;
  transition: transform .3s var(--ease-editorial);
}
.site-header nav a:hover::after, .site-header nav a:focus-visible::after,
.site-header nav a[aria-current="page"]::after {
  transform: scaleX(1); transform-origin: left;
}

.nav-toggle {
  /* position:relative so the .sr-only "Menu" label inside (position:
     absolute) is contained to this button rather than positioning
     against whatever ancestor happens to be the nearest positioning
     context — without this, the label's off-screen box could still
     widen the page's scrollable area on some layouts even though
     nothing is visibly rendered there. */
  position: relative;
  display: none; flex-direction: column; justify-content: center; gap: 5px;
  width: 34px; height: 34px; background: none; border: none; cursor: pointer; padding: 0;
}
.nav-toggle span { display: block; width: 100%; height: 1px; background: var(--color-charcoal); transition: transform .3s var(--ease-editorial), opacity .3s; }
.nav-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ---------- Collage hero (pixel-matched rebuild) ----------
   Two clusters of 3 overlapping real photos (left/right), a caption
   under each, a hand-drawn squiggle+spark above the headline, and a
   pill-style CTA — traced against a client-provided reference image
   (hero-refernce.png) rather than approximated. Follows the client's
   own animation guide: load-in stagger, hover lift with sibling dim,
   interpolated mouse parallax (small, clamped), scroll drift, and a
   simplified mobile layout (fade+rise only, no parallax). */
.collage-hero {
  position: relative;
  min-height: 100vh;
  padding-block: clamp(24px, 4vw, 48px);
  display: grid; place-items: center;
  overflow: hidden;
}

/* Each cluster is its own positioning context, placed as a whole
   block (not individual absolute photos scattered across the hero) —
   matches the reference's construction: two compact stacks of 3
   overlapping polaroid-style photos, not a spread field of many
   tiles. Percentage width/left/top so the whole cluster scales with
   the hero. */
.collage-hero__cluster {
  position: absolute; top: 8%;
  width: clamp(220px, 22vw, 340px); height: clamp(430px, 44vw, 640px);
}
.collage-hero__cluster--left { left: clamp(16px, 3vw, 64px); }
.collage-hero__cluster--right { right: clamp(16px, 3vw, 64px); }

.photo-card {
  position: absolute; display: block; overflow: hidden;
  width: 62%; aspect-ratio: .86;
  background: var(--color-paper);
  padding: 10px 10px 26px;
  box-shadow: 0 10px 26px rgba(23,19,15,.14);
  opacity: 0;
  transition:
    transform .45s var(--ease-editorial),
    box-shadow .45s ease,
    opacity .7s var(--ease-editorial),
    filter .3s ease;
}
.photo-card img { width: 100%; height: 100%; display: block; object-fit: cover; }

/* Load-in: starts slightly scaled down and rotated further than its
   resting angle, settles into place with a stagger per card (client
   spec: 0.94 starting scale, ~6deg starting rotation delta, 0.10s
   stagger, power3.out-equivalent easing). */
.photo-card { transform: scale(.94) rotate(var(--card-rotate-from, 0deg)); }
.collage-hero.is-loaded .photo-card {
  opacity: 1;
  transform: translateY(0) rotate(var(--card-rotate, 0deg)) scale(1);
}

/* Traced positions/rotations from the reference (percentages of the
   cluster box): each cluster is a fan of 3 photos, back-to-front. */
.photo-card--1 { top: 0%;   left: 0%;  z-index: 1; --card-rotate: -5deg; --card-rotate-from: -11deg; transition-delay: .1s; }
.photo-card--2 { top: 30%;  left: 22%; z-index: 2; --card-rotate: 4deg;  --card-rotate-from: 10deg;  transition-delay: .2s; }
.photo-card--3 { top: 58%;  left: -2%; z-index: 3; --card-rotate: -4deg; --card-rotate-from: -10deg; transition-delay: .3s; }
.photo-card--4 { top: 0%;   left: 30%; z-index: 1; --card-rotate: 5deg;  --card-rotate-from: 11deg;  transition-delay: .1s; }
.photo-card--5 { top: 28%;  left: 4%;  z-index: 2; --card-rotate: -3deg; --card-rotate-from: -9deg;  transition-delay: .2s; }
.photo-card--6 { top: 58%;  left: 32%; z-index: 3; --card-rotate: 3deg;  --card-rotate-from: 9deg;   transition-delay: .3s; }

/* Hover spec (desktop/mobile animation guide, section 4): lift 8-12px,
   de-rotate, scale to a max of 1.025, slightly bigger shadow, ~420ms,
   siblings dim only to .82 (not lower). */
.photo-card:hover, .photo-card:focus-visible {
  transform: translateY(-10px) rotate(0deg) scale(1.025);
  box-shadow: 0 24px 55px rgba(79,66,76,.20);
  z-index: 12;
  transition-duration: .42s;
}
.collage-hero__cluster:hover .photo-card:not(:hover) { opacity: .82; }
/* Mobile/touch: no hover, so a brief press-response instead. */
@media (hover: none) {
  .photo-card:active { transform: scale(.985); transition-duration: 120ms; }
}

/* Black & white by default, sitewide — admin-controlled per section
   (Homepage Content page in the admin panel), each section gated
   behind its own data-grayscale-* attribute on <body> (set by
   script.js from assets/data/site-settings.json, defaulting to ON)
   so it can be switched on/off independently for the hero, Selected
   Work tabs, gallery pages and About page photos. The grayscale
   itself applies on every device (including touch, which has no
   "hover" to reveal color) — only the color-on-hover REVEAL is
   restricted to devices with real hover, below, so touch visitors
   simply always see the black & white version rather than a
   permanently grayscale photo with a hover-only escape they can't
   reach. */
body[data-grayscale-hero] .photo-card img { filter: grayscale(1); transition: filter .5s var(--ease-editorial); }
body[data-grayscale-hero] .testimonials__photo img { filter: grayscale(1); transition: filter .5s var(--ease-editorial); }
body[data-grayscale-selected-work] .work-tabs__photo img { filter: grayscale(1); transition: filter .5s var(--ease-editorial), transform .6s var(--ease-editorial); }
body[data-grayscale-gallery] .gallery__item img { filter: grayscale(1); transition: filter .5s var(--ease-editorial); }
body[data-grayscale-gallery] .archive__media img { filter: grayscale(1); transition: filter .5s var(--ease-editorial); }
body[data-grayscale-about] .about-editorial-hero__photo img,
body[data-grayscale-about] .about-philosophy__photo img {
  filter: grayscale(1); transition: filter .5s var(--ease-editorial);
}

@media (hover: hover) and (pointer: fine) {
  body[data-grayscale-hero] .photo-card:hover img, body[data-grayscale-hero] .photo-card:focus-visible img { filter: grayscale(0); }
  body[data-grayscale-hero] .testimonials__card:hover .testimonials__photo img, body[data-grayscale-hero] .testimonials__card:focus-within .testimonials__photo img { filter: grayscale(0); }
  body[data-grayscale-selected-work] .work-tabs__photo:hover img, body[data-grayscale-selected-work] .work-tabs__photo:focus-visible img { filter: grayscale(0); }
  body[data-grayscale-gallery] .gallery__item:hover img, body[data-grayscale-gallery] .gallery__item:focus-within img { filter: grayscale(0); }
  body[data-grayscale-gallery] .archive__item:hover .archive__media img, body[data-grayscale-gallery] .archive__item:focus-visible .archive__media img { filter: grayscale(0); }
  body[data-grayscale-about] .about-editorial-hero__photo:hover img,
  body[data-grayscale-about] .about-philosophy__photo:hover img {
    filter: grayscale(0);
  }
}

.collage-hero__caption {
  position: absolute; bottom: 0; left: 0; width: 100%;
  text-align: center;
  font: 500 11px/1 var(--font-mono); letter-spacing: .18em; text-transform: uppercase;
  color: var(--color-muted);
  opacity: 0; transition: opacity .6s var(--ease-editorial) .6s;
}
.collage-hero.is-loaded .collage-hero__caption { opacity: 1; }

/* The single mobile-only "PEOPLE • PLACES • STORIES" caption row
   under the collage (matches hero_section_mobile_ref.png) — hidden at
   desktop widths, where each cluster keeps its own caption instead. */
.collage-hero__caption--mobile { display: none; }

.collage-hero__copy {
  position: relative; z-index: 2; text-align: center; max-width: 46rem;
  padding-inline: 16px;
  /* Central text per the guide stays "mostly stable" (0-2px parallax)
     and rises slightly on scroll — both driven by script.js as CSS
     custom properties and combined into one transform here, rather
     than two separate style.transform writes that would overwrite
     each other. */
  transform: translate3d(var(--parallax-x, 0px), var(--scroll-y, 0px), 0);
}
.collage-hero__copy h1 {
  color: var(--color-plum);
  font-size: clamp(40px, 5.6vw, 84px);
  line-height: 1.04; font-weight: 500; letter-spacing: -.01em;
  margin: 0;
}
.collage-hero__copy h1 .line { display: block; overflow: hidden; }
.collage-hero__copy h1 .line span { display: block; will-change: transform; }
.collage-hero__copy p {
  margin: 18px 0 0; font: 400 17px/1.5 var(--font-ui);
  color: var(--color-muted);
}

/* Small hand-drawn squiggle + spark sitting just above the headline —
   simpler than the earlier spinning-badge version, matching the
   reference exactly (a compact orange stroke, no ring/text). */
.collage-hero__underline {
  display: block; width: clamp(96px, 9vw, 128px); height: auto; margin: 0 auto 8px;
  overflow: visible;
}
/* Colour guide: "Muse symbol and fine decorative details: Powder
   Blue" — the earlier pixel-matched reference showed this stroke in
   red/orange, but the color guide is the more recent, more explicit
   instruction for this exact element, so it takes precedence.
   Stroke widened (3 -> 4.5) and the box sized up so it reads clearly
   instead of disappearing against the paper-texture background. */
.muse-path {
  fill: none; stroke: var(--color-blue); stroke-width: 4.5; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 400; stroke-dashoffset: 400;
}
.collage-hero.is-loaded .muse-path { animation: drawMuse 1.2s ease forwards .35s; }
@keyframes drawMuse { to { stroke-dashoffset: 0; } }
.collage-hero__spark {
  display: none;
}

.collage-hero__copy .hero-cta {
  margin-top: 30px;
}

@media (prefers-reduced-motion: reduce) {
  .photo-card, .collage-hero__caption, .muse-path { transition: none !important; animation: none !important; }
  .collage-hero.is-loaded .photo-card { opacity: 1; transform: rotate(var(--card-rotate, 0deg)); }
  .collage-hero.is-loaded .muse-path { stroke-dashoffset: 0; }
}

@media (max-width: 900px) {
  .collage-hero__cluster { width: clamp(160px, 34vw, 220px); height: clamp(320px, 62vw, 440px); }
}

@media (max-width: 640px) {
  /* Rebuilt to match the client's mobile reference
     (hero_section_mobile_ref.png) pixel-for-pixel: a single collage of
     exactly 3 photos (not two side-by-side clusters) — one tall photo
     top-left, one small photo overlapping front-and-centre lower down,
     one big tall photo top-right — a single caption row underneath,
     then the squiggle/headline/copy/CTA stacked normally below.
     Percentages measured off a 10% grid overlaid on the reference
     (see scratchpad hero_crop_grid.png for the measurement pass). No
     cursor parallax on mobile (already gated out in JS); load-in is
     the same fade/rotate-settle used on desktop, just repositioned.
     .collage-hero__collage is a dedicated positioning box (see HTML)
     that both clusters sit inside, stacked exactly on top of each
     other, so photos from the right cluster's markup can be placed
     into the single 3-photo collage without moving them in the DOM. */
  .collage-hero {
    display: block; min-height: auto; padding-block: 32px;
  }
  .collage-hero__collage {
    position: relative; width: 100%;
    height: clamp(340px, 92vw, 420px);
    margin-bottom: 14px;
  }
  .collage-hero__cluster {
    position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  }

  .collage-hero__cluster--left .photo-card { width: auto; padding: 8px 8px 20px; }
  .collage-hero__cluster--left .photo-card--2,
  .collage-hero__cluster--left .photo-card--3,
  .collage-hero__cluster--right .photo-card--4 { display: none; }
  .collage-hero__cluster--right .collage-hero__caption { display: none; }

  /* Photo A — leopard-hat portrait, top-left. */
  .collage-hero__cluster--left .photo-card--1 {
    top: 0; left: 5%; width: 38%; height: 60%;
    z-index: 1; --card-rotate: -6deg; --card-rotate-from: -13deg;
  }
  /* Photo B — street/lantern shot (right cluster's 2nd slot), small,
     overlapping front-and-centre, sits on top of both others. */
  .collage-hero__cluster--right .photo-card--5 {
    display: block; width: auto; padding: 8px 8px 20px;
    top: 48%; left: 25%; width: 28%; height: 47%;
    z-index: 3; --card-rotate: 4deg; --card-rotate-from: 10deg;
  }
  /* Photo C — the big tall portrait (right cluster's 3rd slot), top-right. */
  .collage-hero__cluster--right .photo-card--6 {
    display: block; width: auto; padding: 8px 8px 20px;
    top: 0; left: 52%; width: 41%; height: 88%;
    z-index: 2; --card-rotate: 3deg; --card-rotate-from: 9deg;
  }

  .photo-card { position: absolute; inset: auto; aspect-ratio: auto; }
  .collage-hero.is-loaded .photo-card { transform: rotate(var(--card-rotate, 0deg)); }

  /* Both per-cluster captions are replaced by the single
     "PEOPLE • PLACES • STORIES" row below the collage on mobile. */
  .collage-hero__cluster .collage-hero__caption { display: none; }
  .collage-hero__caption--mobile {
    /* Overrides the base .collage-hero__caption rule's
       position:absolute;bottom:0 (this element carries both classes)
       — without resetting position back to static here, it pins to
       the bottom of the whole hero and overlaps the CTA button. */
    display: block; position: static; width: auto;
    margin: 0 0 28px; text-align: center;
    font: 500 11px/1 var(--font-mono); letter-spacing: .18em; text-transform: uppercase;
    color: var(--color-muted);
    opacity: 0; transition: opacity .6s var(--ease-editorial) .6s;
  }
  .collage-hero.is-loaded .collage-hero__caption--mobile { opacity: 1; }
  .collage-hero__copy { order: 3; }
}

.text-link {
  display: inline-block; margin-top: 22px; color: inherit; text-decoration: none;
  font: 500 13px/1 var(--font-ui);
  padding-bottom: 6px; border-bottom: 1px solid currentColor;
  transition: letter-spacing .35s var(--ease-editorial), padding-right .35s var(--ease-editorial);
}
.text-link span { display: inline-block; transition: transform .35s var(--ease-editorial); }
.text-link:hover span, .text-link:focus-visible span { transform: translateX(6px); }

/* Pill-style CTA button (hero "Explore the archive"). The animation
   guide's own sample used ink-black/cream for hover; the later, more
   specific colour guide says "transparent with Deep Plum border" at
   rest and "Deep Plum background with Warm Cream text" on hover —
   followed here since it's the more recent, dedicated colour spec.
   Lift/arrow-nudge motion from the animation guide is kept as-is. */
.hero-cta {
  display: inline-flex; align-items: center; gap: 10px;
  font: 500 15px/1 var(--font-ui); color: var(--color-plum);
  background: transparent; border: 1px solid var(--color-plum); border-radius: 999px;
  padding: 15px 26px; text-decoration: none;
  transition: background-color .3s var(--ease-editorial), color .3s var(--ease-editorial), transform .3s var(--ease-editorial);
}
.hero-cta .arrow { display: inline-block; transition: transform .3s var(--ease-editorial); }
.hero-cta:hover, .hero-cta:focus-visible {
  background: var(--color-plum); color: var(--color-cream);
  transform: translateY(-2px);
}
.hero-cta:hover .arrow, .hero-cta:focus-visible .arrow { transform: translateX(6px); }

/* ---------- Statement (black, circular photo reveal) ----------
   Replaces both the earlier "range" photo-list section and the plain
   moss statement band with one bolder black section: a big headline
   beside a real photo that reveals through an expanding circular mask
   as it scrolls into view — a camera-aperture motif. The mask itself
   is a plain <span> with border-radius animated from a tiny circle to
   fully square/full-bleed (see .statement__mask.is-open), driven by
   an IntersectionObserver in script.js rather than scroll-position
   math, so it fires once and settles like the rest of the site's
   reveals instead of scrubbing continuously with scroll. */
/* ---------- Statement (full-bleed parallax landscape) ----------
   Replaces the earlier black-background circular-mask layout: one
   real, wide landscape-orientation photograph spans the full viewport
   width, using the classic background-attachment: fixed parallax
   trick (the image holds still while the page scrolls over it, so it
   appears to move slower than the content), with the headline
   overlaid in white on a dark gradient for legibility. */
/* Colour guide: keep the photograph full colour, use a plum-toned
   overlay (not a neutral black one) so the white quote still feels
   connected to the site's palette. */
.statement {
  position: relative;
  min-height: clamp(360px, 52vw, 620px);
  display: grid; place-items: center;
  color: var(--color-ivory);
  background-image:
    linear-gradient(rgba(79,66,76,.56), rgba(79,66,76,.36)),
    url('assets/gallery/vietnam/11.jpg');
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
}
.statement__copy { position: relative; z-index: 1; text-align: center; padding-inline: var(--page-gutter); }
.statement__copy h2 {
  font-size: clamp(32px, 4.6vw, 58px); line-height: 1.2; font-weight: 400;
  max-width: 20ch; margin: 0 auto;
}

/* iOS Safari doesn't support background-attachment: fixed reliably —
   it falls back to `scroll`, which just means no parallax drift
   there, not a broken layout. No fallback rule needed; the section
   still renders correctly as a plain full-bleed photo. */
@media (max-width: 767px) {
  .statement { background-attachment: scroll; min-height: 320px; }
}

/* ---------- Section shared ---------- */
.section-title { display: flex; align-items: flex-start; gap: 14px; margin-bottom: clamp(40px, 6vw, 80px); position: relative; }
.section-title img { width: 18px; margin-top: 14px; }
.section-title h2 { font-size: clamp(50px, 5.5vw, 82px); font-weight: 400; }
.section-title__meta {
  margin: 0 0 0 auto; align-self: stretch; display: flex; align-items: center;
  writing-mode: vertical-rl; font: 400 11px/1 var(--font-mono); letter-spacing: .12em;
  text-transform: uppercase; color: var(--color-muted); border-left: 1px solid var(--color-rule);
  padding-left: 14px;
}

/* Sections sit back-to-back — collapse the shared edge so consecutive
   sections don't stack double padding into a dead gap.
   .work's own bottom edge is unreliable for this: its last child
   (.filmstrip) breaks out full-bleed via left:50%/margin-left:-50vw,
   and that shift doesn't collapse against a parent padding the same
   way a normal static child would. So .work keeps an explicit bottom
   padding instead, and the section that follows it zeroes its own
   top padding rather than the other way around. */
.work { padding-bottom: var(--section-space); }
.testimonials { padding-top: 0; }
/* .about sits between two solid-color bands (testimonials' oxblood
   backdrop above, the footer's oxblood-dark below) rather than beside
   another ivory section, so the "collapse the shared edge" pattern
   used elsewhere doesn't apply here — it left .about's photo/heading
   flush against both bands with no breathing room. Give it its own
   explicit space on both sides instead of zeroing top padding. */
.about { padding-block: var(--section-space); }

/* ---------- Testimonials ----------
   Clean uniform grid of white cards on the site's cream background —
   each card pairs a small representative shoot photo (not a claimed
   photo of that specific client — we don't have real headshots tied
   to these testimonials) with a star rating, the quote, and the
   client's name/credit. */
.testimonials__grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(20px, 2.4vw, 28px);
}
.testimonials__card {
  background: var(--color-ivory);
  border-radius: 16px;
  padding: clamp(20px, 2vw, 26px);
  box-shadow: 0 12px 32px rgba(36, 31, 35, .1);
  display: flex; flex-direction: column;
}
.testimonials__card[data-reveal] { transform: translateY(20px) !important; }
.testimonials__card[data-reveal].is-visible { transform: none !important; }
.testimonials__photo {
  border-radius: 10px; overflow: hidden;
  aspect-ratio: 4 / 3; margin-bottom: 16px;
}
.testimonials__photo img { width: 100%; height: 100%; object-fit: cover; }
.testimonials__stars { color: var(--color-blue); font-size: 14px; letter-spacing: .1em; margin-bottom: 10px; }
.testimonials__card p {
  font: 400 clamp(15px, 1.1vw, 17px)/1.5 var(--font-display);
  margin: 0 0 16px;
  color: var(--color-charcoal);
  flex-grow: 1;
}
.testimonials__by {
  display: block; font: 500 13px/1.3 var(--font-ui);
  color: var(--color-plum);
}
.testimonials__by em { font-style: normal; color: var(--color-muted); }

/* ---------- Selected Work ---------- */
.project-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(38px, 6vw, 84px) var(--grid-gap);
  counter-reset: project-index;
}
.project { margin: 0; counter-increment: project-index; position: relative; }
.project__link { display: block; color: inherit; text-decoration: none; }
/* A small numbered tag per project — a restrained nod to a scattered
   "(01)(02)(03)" caption style, generated from CSS counters so it
   renumbers automatically if projects are added, removed or reordered. */
.project__index {
  display: block; margin-bottom: 10px;
  font: 400 11px/1 var(--font-mono); letter-spacing: .1em; color: var(--color-oxblood);
}
.project__index::before { content: "(0" counter(project-index) ")"; }
/* The per-photo crosshair cursor that used to live here has been
   replaced by the site-wide custom cursor (see .cursor-dot further
   down + script.js) so there's only ever one custom cursor design on
   screen at a time. */
.project__media { position: relative; aspect-ratio: 1.65; overflow: hidden; }
.project:nth-child(3) .project__media, .project:nth-child(4) .project__media { aspect-ratio: 1.55; }
/* These tiles are wide (1.55-1.65:1) but several source photos are
   tall portraits — object-fit:cover's default center crop cut off
   subjects' heads/faces at the top of the frame. Anchor the crop to
   the top instead so the subject stays in frame. */
.project__media img { object-position: top; transition: transform .6s var(--ease-editorial); }
.project:hover .project__media img, .project:focus-within .project__media img { transform: scale(1.025); }

/* The lead project's photo settles in with a very slight tilt+offset,
   like it was just set down on the page — a restrained nod to the
   overlapping-photo scrapbook look, on one image only so it reads as
   an accent rather than a whole-page treatment. Free of the article's
   own [data-reveal] transform since it targets this inner wrapper,
   not the article. */
.project--featured .project__media {
  transform: rotate(0deg);
  transition: transform 1s var(--ease-editorial);
}
.project--featured[data-reveal] .project__media { transform: rotate(-1.25deg) translateY(6px); }
.project--featured[data-reveal].is-visible .project__media { transform: rotate(0deg) translateY(0); }
.project h3 { font-size: clamp(28px, 2.5vw, 40px); margin: 18px 0 0; font-weight: 400; transition: transform .3s var(--ease-editorial); }
.project:hover h3 { transform: translateX(4px); }
.project__meta { font: 400 11px/1.6 var(--font-mono); color: var(--color-muted); letter-spacing: .04em; margin: 6px 0 0; }
.crop-marks { position: absolute; width: calc(100% + 28px); height: calc(100% + 28px); inset: -14px; pointer-events: none; }
.work__all-link { display: inline-block; margin-top: clamp(40px, 5vw, 64px); }

/* ---------- Selected Work tabs ----------
   Pill-style nav tabs (same visual language as .gallery__pill on the
   category pages) switch which single category's featured photo is
   shown below — plain show/hide via script.js's work-tabs block, no
   scroll-jacking or auto-play. */
.work-tabs__nav {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin-bottom: clamp(28px, 4vw, 44px);
}
.work-tabs__pill {
  font: 400 13px/1 var(--font-ui);
  color: var(--color-muted); background: none;
  border: 1px solid var(--color-rule); border-radius: 999px;
  padding: 9px 18px; cursor: pointer;
  transition: color .25s var(--ease-editorial), border-color .25s var(--ease-editorial), background-color .25s var(--ease-editorial);
}
.work-tabs__pill:hover, .work-tabs__pill:focus-visible { border-color: var(--color-oxblood); color: var(--color-charcoal); }
.work-tabs__pill.is-active { background: var(--color-oxblood); border-color: var(--color-oxblood); color: #fff; }

.work-tabs__panels { position: relative; }
.work-tabs__panel { margin: 0; }

/* 5-photo grid per category tab: one large lead photo + 4 smaller
   photos alongside, all real gallery images. Plain CSS grid, no JS
   layout logic. */
.work-tabs__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: repeat(2, 1fr);
  gap: clamp(10px, 1.2vw, 16px);
  height: clamp(320px, 42vw, 460px);
}
.work-tabs__photo {
  display: block; position: relative; overflow: hidden;
  border-radius: 0; background: var(--color-ivory);
}
.work-tabs__photo:first-child { grid-column: span 2; grid-row: span 2; }
.work-tabs__photo img {
  width: 100%; height: 100%; object-fit: cover; object-position: top;
  display: block; transition: transform .6s var(--ease-editorial);
}
.work-tabs__photo:hover img, .work-tabs__photo:focus-visible img { transform: scale(1.04); }

.work-tabs__view-all { display: inline-block; margin-top: clamp(20px, 3vw, 32px); }

@media (max-width: 767px) {
  .work-tabs__grid {
    grid-template-columns: repeat(2, 1fr);
    grid-template-rows: repeat(3, 1fr);
    height: clamp(360px, 90vw, 480px);
  }
  .work-tabs__photo:first-child { grid-column: span 2; grid-row: span 1; }
}

/* ---------- Arc photo field ----------
   Replaces the earlier flat filmstrip: real photo cards fanned around
   a centered "About Divisha" statement + stats card. Photo list and
   hand-placed positions live in script.js (ARC_PHOTOS/ARC_POSITIONS);
   this file only owns the visual treatment each card gets. */
.arc {
  position: relative;
  margin-top: var(--section-space);
  /* Generous top padding — the fan of photos (each roughly 200-280px
     tall including its outward tilt) sits above .arc__card entirely,
     so the section itself needs enough clearance that the card starts
     below all of them instead of the two overlapping. This was the
     actual bug behind the photos cutting through the card's headline:
     the card previously started too close to the top of the section
     for the photos' real rendered height. */
  padding-block: clamp(220px, 24vw, 300px) clamp(32px, 5vw, 56px);
  display: grid; place-items: center;
}
/* Fixed fan of cards — replaces two earlier orbiting-motion attempts
   that both produced broken-looking results (rotating the rectangular
   field swung photos to one side; per-photo circular paths were hard
   to keep evenly spaced and collision-free at every viewport width).
   This is deliberately simpler and more stable: five cards in fixed,
   evenly-spaced positions, each angled outward from center like an
   open hand of cards, framing the card without any of them traveling.
   Motion now lives in the scroll-reveal settle (translateY, unrelated
   transform than the orbit approach used) and the existing per-photo
   autoplay crossfade — both already reliable elsewhere on this site. */
/* A full-width, edge-to-edge row of 7 cards (no gaps between them,
   per feedback that the earlier 5-card version looked too sparse) —
   each one progressively more tilted toward the outer edges, like a
   fully-fanned hand of cards. .arc__card sits above this row entirely
   (z-index 2, opaque background) rather than being woven into it, so
   there's no risk of the card and a photo competing for the same
   space the way earlier attempts did. */
.arc__field {
  position: absolute; inset: 0; pointer-events: none;
  display: flex; align-items: flex-start; justify-content: center;
  padding-top: clamp(4px, 1vw, 16px);
}
.arc__photo {
  position: relative; display: block; overflow: hidden; flex: 1 1 0;
  min-width: 0; max-width: clamp(140px, 15vw, 220px);
  aspect-ratio: .78;
  border-radius: 14px;
  box-shadow: 0 8px 24px rgba(23,23,23,.12);
  transform: rotate(var(--arc-rotate, 0deg));
  transform-origin: bottom center;
  margin-inline: -2px;
}
.arc__photo--center {
  z-index: 1;
  transform: translateY(-14px);
}
.arc__photo img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: opacity .3s var(--ease-editorial);
}

.arc__card {
  position: relative; z-index: 2; text-align: center;
  max-width: 46rem; background: var(--color-ivory);
  padding: clamp(28px, 4vw, 44px) clamp(20px, 4vw, 40px);
}
.arc__eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font: 400 11px/1 var(--font-mono); letter-spacing: .12em; text-transform: uppercase;
  color: var(--color-oxblood); border: 1px solid var(--color-rule); border-radius: 999px;
  padding: 8px 16px; margin-bottom: 20px;
}
.arc__eyebrow img { width: 12px; height: 12px; }
.arc__title { font-size: clamp(24px, 2.6vw, 36px); font-weight: 400; line-height: 1.25; margin: 0 auto; max-width: 26ch; }
.arc__desc { max-width: 48ch; margin: 18px auto 0; color: var(--color-muted); line-height: 1.6; font-size: 15px; }
.arc__card .text-link { margin-top: 22px; }
.arc__stats {
  display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 16px;
  margin: clamp(32px, 5vw, 48px) 0 0; padding-top: clamp(24px, 3vw, 32px);
  border-top: 1px solid var(--color-rule);
}
.arc__stats dt { font: 400 clamp(24px, 2.6vw, 34px)/1 var(--font-display); color: var(--color-oxblood); margin: 0; }
.arc__stats dd { font: 400 11px/1.4 var(--font-mono); letter-spacing: .06em; text-transform: uppercase; color: var(--color-muted); margin: 8px 0 0; }

/* Stale rule from an earlier absolutely-positioned fan design: it hid
   every photo except the center one, which made sense for that layout
   but left just one lonely tile once the fan became a full edge-to-
   edge flex row (see .arc__field above) — a real "images not visible"
   bug on mobile, not a deliberate simplification.
   At phone width, 7 photos in one row were too small to register as
   real photos — drop the two outermost (most tilted, least legible)
   and let the flex row's `flex: 1 1 0` redistribute the freed space
   to the remaining 5, sized up accordingly. */
@media (max-width: 560px) {
  .arc { padding-top: clamp(150px, 42vw, 210px); }
  .arc__photo:first-child, .arc__photo:last-child { display: none; }
  .arc__photo { max-width: clamp(72px, 17vw, 104px); }
  .arc__stats { grid-template-columns: repeat(2, minmax(0,1fr)); row-gap: 24px; }
}

/* ---------- About ---------- */
.about {
  position: relative; display: grid; grid-template-columns: 5fr 7fr;
  gap: clamp(44px, 7vw, 110px); align-items: center; overflow: visible;
  min-height: 90vh;
}
/* The polaroid photo is shot at a slight tilt with its own white
   border baked in — object-fit:cover on a matched-ratio box still
   crops unevenly into that border/frame edge whenever the rendered
   box isn't pixel-exact to the image ratio (it visibly ate into the
   left edge in testing). object-fit:contain guarantees the whole
   polaroid, border included, is always visible regardless of any
   rounding mismatch; the ivory section background fills any letterbox
   gap so there's no visible seam. */
.about__portrait { margin: 0; aspect-ratio: 1.239; overflow: hidden; background: var(--color-ivory); }
.about__portrait img { width: 100%; height: 100%; object-fit: contain; display: block; }
.about__copy h2 { font-size: clamp(50px, 5vw, 78px); line-height: .92; font-weight: 400; margin: 0; }
.about__copy p { max-width: 60ch; line-height: 1.6; color: var(--color-muted); margin: 22px 0 0; }
/* Wraps the "Let's work together" popup trigger and the newer "Read
   the full story" link to /about side by side — two distinct, non-
   redundant paths out of this compact homepage teaser (open the quick
   inquiry form, or go read the dedicated About page). */
.about__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 28px; margin-top: 28px; }
.about__cta { margin-top: 0; border: 1px solid var(--color-plum); cursor: pointer; }
.about__more-link { margin-top: 0; }
.about__circle { position: absolute; width: 240px; right: -150px; bottom: 8%; pointer-events: none; }

/* ---------- Inquiry popup (About section CTA) ----------
   Same visual language as the contact page's inline form (reuses
   .contact-form/.contact-form__* wholesale) inside a centred modal
   panel. Backdrop fade + panel rise, ~280ms, matching the site's
   --ease-editorial timing used everywhere else for entrances. */
.inquiry-modal {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center;
  padding: 24px;
}
.inquiry-modal[hidden] { display: none; }
.inquiry-modal__backdrop {
  position: absolute; inset: 0;
  background: rgba(36, 31, 35, .55);
  opacity: 0; transition: opacity .3s var(--ease-editorial);
}
.inquiry-modal.is-open .inquiry-modal__backdrop { opacity: 1; }
.inquiry-modal__panel {
  position: relative; z-index: 1;
  width: min(100%, 34rem); max-height: calc(100vh - 48px);
  overflow-y: auto;
  background: var(--color-cream);
  padding: clamp(32px, 5vw, 48px);
  opacity: 0; transform: translateY(18px) scale(.98);
  transition: opacity .32s var(--ease-editorial), transform .32s var(--ease-editorial);
}
.inquiry-modal.is-open .inquiry-modal__panel { opacity: 1; transform: none; }
.inquiry-modal__panel h2 {
  font-size: clamp(28px, 3.4vw, 38px); line-height: 1.08; font-weight: 400; margin: 0;
}
.inquiry-modal__panel > p {
  max-width: 46ch; color: var(--color-muted); line-height: 1.6;
  margin: 14px 0 26px; font-size: 15px;
}
.inquiry-modal__panel .contact-form { border: none; padding: 0; gap: 18px; }
.inquiry-modal__close {
  position: absolute; top: clamp(16px, 3vw, 24px); right: clamp(16px, 3vw, 24px);
  width: 36px; height: 36px; display: grid; place-items: center;
  font-size: 24px; line-height: 1; color: var(--color-muted);
  background: transparent; border: none; cursor: pointer;
  transition: color .25s var(--ease-editorial);
}
.inquiry-modal__close:hover, .inquiry-modal__close:focus-visible { color: var(--color-plum); }

@media (prefers-reduced-motion: reduce) {
  .inquiry-modal__backdrop, .inquiry-modal__panel { transition: none !important; }
}

/* ---------- Footer ---------- */
/* Colour guide: Deep Plum background, Warm Cream heading, Soft Ivory
   links, Powder Blue link hover (not just a dimmed opacity). */
.footer { color: var(--color-ivory); background: var(--color-plum); padding-block: var(--section-space) 0; position: relative; }
.footer__rule { position: absolute; top: clamp(28px, 4vw, 48px); left: var(--page-gutter); width: 64px; height: 8px; filter: brightness(0) invert(1); opacity: .6; }
.footer__inner { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: clamp(24px, 4vw, 64px); align-items: end; padding-top: 28px; }
.footer h2 { font-size: clamp(42px, 4.8vw, 74px); line-height: 1.05; text-transform: none; font-weight: 400; margin: 0; color: var(--color-cream); }
.footer__links {
  display: grid; gap: 10px; align-content: end; justify-items: start;
  padding-left: clamp(16px,2vw,32px); border-left: 1px solid rgba(182,203,224,.3);
  font-size: 16px; text-transform: uppercase; letter-spacing: .04em;
}
.footer__links a { color: var(--color-ivory); text-decoration: none; transition: color .25s; }
.footer__links a:hover, .footer__links a:focus-visible { color: var(--color-blue); }
.footer__links span { color: rgba(255,253,248,.68); font-size: 15px; }
.footer__bottom {
  margin-top: clamp(56px, 7vw, 96px); padding-block: 24px;
  border-top: 1px solid rgba(255,255,255,.18);
  display: flex; justify-content: space-between; gap: 16px;
  font: 400 11px/1 var(--font-mono); letter-spacing: .08em; text-transform: uppercase;
  color: rgba(255,255,255,.6);
}
.footer__bottom span:first-child { font: inherit; letter-spacing: inherit; text-transform: inherit; }
.footer__tagline {
  font-family: var(--font-display); font-style: italic; font-weight: 500;
  font-size: 15px; letter-spacing: 0; text-transform: none;
  color: rgba(255,253,248,.75);
}

/* =========================================================
   Motion — reveal on scroll (respects prefers-reduced-motion)
   ========================================================= */
[data-reveal] {
  opacity: 0; transform: translateY(14px);
  transition: opacity .8s var(--ease-editorial), transform .8s var(--ease-editorial);
  transition-delay: var(--delay, 0ms);
  will-change: opacity, transform;
  backface-visibility: hidden;
}
[data-reveal].is-visible {
  opacity: 1; transform: none;
  /* Drop the GPU layer once settled so text renders crisp, not mid-composite. */
  transition-property: opacity, transform, will-change;
  transition-duration: .8s, .8s, 0s;
  transition-delay: var(--delay, 0ms), var(--delay, 0ms), calc(var(--delay, 0ms) + .8s);
  will-change: auto;
}
.reveal-media[data-reveal] { transform: translateY(12px); }
.fade-in[data-reveal] { transform: none; }

/* Headline line-by-line mask reveal */
.mask-reveal .line span {
  transform: translateY(105%);
  transition: transform .8s var(--ease-editorial);
}
.mask-reveal.is-visible .line:nth-child(1) span { transition-delay: 0ms; }
.mask-reveal.is-visible .line:nth-child(2) span { transition-delay: 80ms; }
.mask-reveal.is-visible .line:nth-child(3) span { transition-delay: 160ms; }
.mask-reveal.is-visible .line:nth-child(4) span { transition-delay: 240ms; }
.mask-reveal.is-visible .line span { transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  [data-reveal], .mask-reveal .line span { transition: none !important; transform: none !important; opacity: 1 !important; }
  .project__media img, .text-link span { transition: none !important; }
  .draw-in path { stroke-dashoffset: 0 !important; transition: none !important; }
  .photo-card {
    opacity: 1 !important; transition: none !important;
    transform: rotate(var(--card-rotate, 0deg)) !important;
  }
}

/* =========================================================
   Gallery pages (/work/<category>.html)
   ========================================================= */
.gallery-hero {
  padding-block: clamp(48px, 8vw, 96px) var(--section-space);
  position: relative;
}
.gallery-hero__eyebrow {
  display: block; margin-bottom: 14px;
  font: 400 11px/1 var(--font-mono); letter-spacing: .14em; text-transform: uppercase;
  color: var(--color-oxblood);
}
.gallery-hero__eyebrow a { text-decoration: none; border-bottom: 1px solid currentColor; padding-bottom: 2px; }
.gallery-hero__eyebrow a:hover { opacity: .7; }
.gallery-hero h1 { font-size: clamp(48px, 6vw, 92px); line-height: .96; font-weight: 400; max-width: 20ch; }
.gallery-hero p { max-width: 60ch; color: var(--color-muted); line-height: 1.6; margin: 20px 0 0; font-size: 15px; }
.gallery-hero__count {
  display: inline-block; margin-top: 18px;
  font: 400 11px/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--color-muted); border-top: 1px solid var(--color-rule); padding-top: 10px;
}

/* ---------- Contact page ----------
   Never had its own rules — contact.html's markup (.contact-page__*)
   rendered as an unstyled stacked list, which read as a broken page.
   Mirrors the two-column pattern used elsewhere (About, project cards):
   a copy column plus a details list, sharing the site's existing
   type/spacing scale rather than inventing a new one. */
.contact-page {
  padding-block: 0 var(--section-space);
}
.contact-page__grid {
  display: grid; grid-template-columns: 1fr 1.1fr;
  gap: clamp(48px, 8vw, 120px); align-items: start;
}
.contact-page__copy h2 {
  font-size: clamp(34px, 3.6vw, 52px); line-height: 1.08; font-weight: 400; margin: 0;
}
.contact-page__copy p {
  max-width: 46ch; color: var(--color-muted); line-height: 1.6;
  margin: 18px 0 0; font-size: 16px;
}
.contact-page__details {
  margin: 32px 0 0; padding-top: clamp(4px, 1vw, 12px);
  border-top: 1px solid var(--color-rule);
}
.contact-page__details > div {
  padding-block: 16px;
  border-bottom: 1px solid var(--color-rule);
  display: grid; grid-template-columns: 8rem 1fr; gap: 16px; align-items: baseline;
}
.contact-page__details > div:first-child { padding-top: 0; }
.contact-page__details dt {
  font: 400 11px/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--color-muted);
}
.contact-page__details dd {
  margin: 0; font-size: 16px; color: var(--color-charcoal);
}
.contact-page__details dd a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--color-rule); }
.contact-page__details dd a:hover, .contact-page__details dd a:focus-visible { border-color: currentColor; }

/* Inquiry form — no backend, submits as a pre-filled mailto: (see
   script.js) rather than posting anywhere. Styled to match the site's
   restrained, square-cornered, no-shadow language rather than a
   generic form-library look. */
.contact-form {
  display: grid; gap: 20px;
  padding: clamp(28px, 4vw, 44px);
  border: 1px solid var(--color-rule);
}
.contact-form__field { display: grid; gap: 8px; }
.contact-form__field label {
  font: 400 11px/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--color-muted);
}
.contact-form__field input,
.contact-form__field select,
.contact-form__field textarea {
  font: 400 15px/1.4 var(--font-ui); color: var(--color-charcoal);
  background: var(--color-ivory);
  border: 1px solid var(--color-rule);
  padding: 12px 14px; border-radius: 0;
  transition: border-color .25s var(--ease-editorial);
}
.contact-form__field textarea { resize: vertical; min-height: 100px; }
.contact-form__field input:focus-visible,
.contact-form__field select:focus-visible,
.contact-form__field textarea:focus-visible {
  outline: none; border-color: var(--color-oxblood);
}
.contact-form__submit {
  justify-self: start;
  font: 500 14px/1 var(--font-ui); color: #fff;
  background: var(--color-oxblood); border: none;
  padding: 14px 28px; cursor: pointer;
  transition: background-color .25s var(--ease-editorial);
}
.contact-form__submit:hover, .contact-form__submit:focus-visible { background: var(--color-oxblood-dark); }
.contact-form__note {
  margin: -8px 0 0; font-size: 12px; color: var(--color-muted);
}
/* Inline success/error message shown after an api/enquiry.php submit
   (see script.js's inquiry-form handler) — success uses the site's
   plum/ink tone family (kept on-brand rather than a generic green),
   error uses a clearly distinct warm warning tone so the two are easy
   to tell apart at a glance. */
.contact-form__result {
  margin: 0; padding: 10px 14px;
  font: 500 13px/1.4 var(--font-ui);
  border-radius: 2px;
}
.contact-form__result[hidden] { display: none; }
.contact-form__result.is-success {
  color: var(--color-plum);
  background: var(--color-blue-soft);
  border: 1px solid rgba(79, 66, 76, 0.18);
}
.contact-form__result.is-error {
  color: #7a2e22;
  background: #fbe9e4;
  border: 1px solid rgba(122, 46, 34, 0.25);
}

@media (max-width: 767px) {
  .contact-page__grid { grid-template-columns: 1fr; gap: 40px; }
  .contact-page__details > div { grid-template-columns: 1fr; gap: 4px; }
}

/* ---------- Journal page (empty state) ----------
   Same gap as the contact page had — .journal-empty* markup existed
   with no matching CSS anywhere, so it rendered as a plain unstyled
   stacked block. */
.journal-empty {
  padding-block: clamp(40px, 6vw, 80px) var(--section-space);
  display: grid; place-items: center;
}
.journal-empty__card {
  max-width: 32rem; text-align: center;
  padding: clamp(40px, 6vw, 64px) clamp(28px, 5vw, 48px);
  border: 1px solid var(--color-rule);
}
.journal-empty__icon { width: 28px; height: 28px; margin-bottom: 20px; opacity: .8; }
.journal-empty__card p {
  color: var(--color-muted); line-height: 1.6; font-size: 16px; margin: 0 0 22px;
}
.journal-empty__card .text-link { font-size: 15px; }

.gallery {
  padding-block: 0 var(--section-space);
}
/* Filter pills for multi-shoot categories (Street & Travel, Events,
   etc.) — one pill per sub-shoot plus "All", switching which
   .gallery__group section is visible via gallery.js rather than
   stacking every group's full photo set on one endless page. */
.gallery__pills {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin-bottom: clamp(32px, 5vw, 56px);
}
.gallery__pill {
  font: 400 13px/1 var(--font-ui);
  color: var(--color-muted); background: none;
  border: 1px solid var(--color-rule); border-radius: 999px;
  padding: 9px 18px; cursor: pointer;
  transition: color .25s var(--ease-editorial), border-color .25s var(--ease-editorial), background-color .25s var(--ease-editorial);
}
.gallery__pill:hover, .gallery__pill:focus-visible { border-color: var(--color-oxblood); color: var(--color-charcoal); }
.gallery__pill.is-active {
  background: var(--color-oxblood); border-color: var(--color-oxblood); color: #fff;
}
/* Multi-shoot categories render as labeled groups, each its own
   masonry grid, stacked with the section rhythm; single-shoot
   categories skip .gallery__group entirely and use .gallery__grid
   directly as a child of .gallery (see gallery.js). */
.gallery__group + .gallery__group { margin-top: var(--section-space); }
.gallery__group-title {
  font: 400 clamp(22px, 2.4vw, 30px)/1 var(--font-display);
  margin: 0 0 24px; padding-bottom: 14px;
  border-bottom: 1px solid var(--color-rule);
}
/* Clean, compact, uniform grid — replaces an earlier editorial/
   alternating layout that read as randomly sized rather than
   deliberate, and felt slow to scroll through with full-bleed photos.
   Every photo is the same size and aspect ratio; the "moment" comes
   from the reveal (a curtain wipe, below), not from varying sizes. */
.gallery__grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(12px, 1.6vw, 20px);
}
.gallery__item { margin: 0; }

.gallery__trigger {
  display: block; width: 100%; padding: 0; border: none; background: none; cursor: pointer;
  overflow: hidden; position: relative;
  /* aspect-ratio on the trigger itself (not just the inner img) —
     guarantees every grid cell is the same height regardless of each
     photo's native dimensions, so the grid reads as full, uniform
     rows rather than photos of varying heights leaving ragged gaps. */
  aspect-ratio: 4 / 5;
}
.gallery__trigger img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: transform .6s var(--ease-editorial);
}
.gallery__trigger:hover img, .gallery__trigger:focus-visible img { transform: scale(1.04); }

/* Curtain-wipe reveal: a solid ivory panel covers each photo and
   slides up and out of the way as the photo scrolls into view — a
   clearly noticeable per-photo moment, still quick enough (0.7s) that
   scrolling through a full gallery doesn't feel slow. The panel is a
   plain ::before (no extra markup needed); .gallery__item itself
   handles the (separate, milder) fade the item's caption/spacing use. */
.gallery__trigger::before {
  content: "";
  position: absolute; inset: 0; z-index: 1;
  background: var(--color-cream);
  transform: scaleY(1); transform-origin: top;
  transition: transform .7s var(--ease-editorial);
  transition-delay: var(--delay, 0ms);
}
.gallery__item.is-visible .gallery__trigger::before { transform: scaleY(0); }

/* Numbered mono caption under each photo — a quieter echo of the
   (01)(02)(03) tag used on the home page's Selected Work grid. */
.gallery__caption {
  display: block; margin-top: 10px;
  font: 400 11px/1.5 var(--font-mono); letter-spacing: .04em; color: var(--color-muted);
}
.gallery__caption b { color: var(--color-oxblood); font-weight: 400; margin-right: 6px; }

.gallery__empty { color: var(--color-muted); font-size: 15px; padding-block: 40px; }

@media (prefers-reduced-motion: reduce) {
  .gallery__trigger::before { transition: none !important; transform: scaleY(0) !important; }
}

@media (max-width: 900px) {
  .gallery__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .gallery__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 150;
  display: none; align-items: center; justify-content: center;
  background: rgba(23, 23, 23, .94);
  padding: 24px;
}
.lightbox[data-open="true"] { display: flex; }
.lightbox__figure { position: relative; max-width: min(1200px, 92vw); max-height: 88vh; margin: 0; }
.lightbox__figure img { display: block; max-width: 100%; max-height: 80vh; width: auto; height: auto; margin: 0 auto; }
.lightbox__caption {
  display: block; margin-top: 14px; text-align: center;
  font: 400 13px/1.5 var(--font-ui); color: rgba(255,255,255,.75);
}
.lightbox__close, .lightbox__nav {
  position: fixed; background: none; border: 1px solid rgba(255,255,255,.3);
  color: #fff; cursor: pointer; font: 400 22px/1 var(--font-display);
  width: 44px; height: 44px; display: flex; align-items: center; justify-content: center;
  transition: background .25s, border-color .25s;
}
.lightbox__close:hover, .lightbox__nav:hover,
.lightbox__close:focus-visible, .lightbox__nav:focus-visible { background: rgba(255,255,255,.12); border-color: rgba(255,255,255,.6); }
.lightbox__close { top: 24px; right: 24px; }
.lightbox__nav--prev { left: 24px; top: 50%; translate: 0 -50%; }
.lightbox__nav--next { right: 24px; top: 50%; translate: 0 -50%; }

/* Related-categories strip at the foot of each gallery page */
.gallery-related { padding-block: var(--section-space); }
.gallery-related h2 { font-size: clamp(28px, 3vw, 40px); font-weight: 400; margin: 0 0 28px; }
.gallery-related__grid { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: var(--grid-gap); }
.gallery-related__item { text-decoration: none; color: inherit; display: block; }
.gallery-related__media { aspect-ratio: 1.2; overflow: hidden; }
.gallery-related__media img { transition: transform .5s var(--ease-editorial); }
.gallery-related__item:hover .gallery-related__media img,
.gallery-related__item:focus-visible .gallery-related__media img { transform: scale(1.04); }
.gallery-related__item h3 { font-size: 18px; font-weight: 400; margin: 14px 0 0; }

@media (max-width: 900px) {
  .gallery__grid { columns: 2 220px; }
  .gallery-related__grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
}
@media (max-width: 600px) {
  .gallery__grid { columns: 1; }
  .gallery-related__grid { grid-template-columns: 1fr; }
  .lightbox__nav { width: 38px; height: 38px; font-size: 18px; }
  .lightbox__close { top: 14px; right: 14px; }
  .lightbox__nav--prev { left: 8px; }
  .lightbox__nav--next { right: 8px; }
}

/* ---------- Archive index (/work/index.html) ---------- */
.archive { padding-block: 0 var(--section-space); }
.archive__grid { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: clamp(32px, 4vw, 56px) var(--grid-gap); }
.archive__item { text-decoration: none; color: inherit; display: block; position: relative; }
.archive__media { aspect-ratio: 1.3; overflow: hidden; }
.archive__media img { transition: transform .5s var(--ease-editorial); }
.archive__item:hover .archive__media img, .archive__item:focus-visible .archive__media img { transform: scale(1.04); }
.archive__index { display: block; margin-top: 14px; font: 400 11px/1 var(--font-mono); letter-spacing: .1em; color: var(--color-oxblood); }
.archive__item h2 { font-size: clamp(22px, 2vw, 28px); font-weight: 400; margin: 6px 0 0; transition: transform .3s var(--ease-editorial); }
.archive__item:hover h2 { transform: translateX(4px); }

@media (max-width: 900px) {
  .archive__grid { grid-template-columns: repeat(2, minmax(0,1fr)); }
}
@media (max-width: 560px) {
  .archive__grid { grid-template-columns: 1fr; }
  /* Same fix as Selected Work's mobile cards: pull "(0N)" onto the
     same line as the heading instead of its own line above it.
     .archive__index here holds literal "(01)" text (not a CSS
     counter), so hide it and generate the number via counter() on
     .archive__grid/.archive__item instead — same mechanism, works
     regardless of the span's actual text content. */
  .archive__grid { counter-reset: archive-index; }
  .archive__item { counter-increment: archive-index; }
  .archive__index { display: none; }
  .archive__item h2 {
    display: flex; align-items: baseline; gap: 8px; margin-top: 14px;
  }
  .archive__item h2::before {
    content: "(0" counter(archive-index) ")";
    font: 400 11px/1 var(--font-mono); letter-spacing: .1em; color: var(--color-oxblood);
  }
}

/* ---------- Responsive: 1199px and down ---------- */
@media (max-width: 1199px) {
  .hero { grid-template-columns: repeat(8, 1fr); }
  .hero__portrait { grid-column: 1 / 5; }
  .hero__copy { grid-column: 4 / 9; }
  .hero__travel { grid-column: 6 / 9; opacity: .9; }
  .hero__accent { display: none; }
}

/* ---------- Responsive: < 768px ---------- */
@media (max-width: 767px) {
  .site-header { padding-block: 22px; }
  .wordmark__rule { display: none; }
  /* .wordmark__rule normally carries margin-right:auto to push the nav
     to the header's right edge — hiding it here removes that pusher,
     so the toggle drifted to sit right next to the wordmark instead of
     the right edge. Put the auto-margin on the toggle itself instead. */
  .nav-toggle { display: flex; margin-left: auto; }
  /* Full-screen Deep Plum panel per the animation guide (section 7):
     reveals via clip-path (0-height inset growing to full), Warm
     Cream/Ivory links with a per-link rise + stagger, Powder Blue on
     hover/active. Colour guide: "Deep Plum background... Soft Ivory
     for links." */
  .site-header nav {
    position: fixed; inset: 0; z-index: 30;
    background: var(--color-plum); color: var(--color-ivory);
    flex-direction: column; justify-content: center; gap: 0;
    padding: 8px var(--page-gutter) 24px;
    clip-path: inset(0 0 100% 0);
    pointer-events: none;
    transition: clip-path .52s var(--ease-editorial);
  }
  .site-header nav[data-open="true"] {
    clip-path: inset(0);
    pointer-events: auto;
  }
  .site-header nav a {
    padding: 14px 0; border-top: 1px solid rgba(255,253,248,.18); font-size: 22px;
    opacity: 0; transform: translateY(24px);
    transition: opacity .4s var(--ease-editorial), transform .4s var(--ease-editorial), color .25s ease;
  }
  .site-header nav a:first-child { border-top: none; }
  .site-header nav[data-open="true"] a { opacity: 1; transform: none; }
  .site-header nav[data-open="true"] a:nth-child(1) { transition-delay: 70ms; }
  .site-header nav[data-open="true"] a:nth-child(2) { transition-delay: 140ms; }
  .site-header nav[data-open="true"] a:nth-child(3) { transition-delay: 210ms; }
  .site-header nav[data-open="true"] a:nth-child(4) { transition-delay: 280ms; }
  .site-header nav[data-open="true"] a:nth-child(5) { transition-delay: 350ms; }
  .site-header nav a:hover, .site-header nav a:focus-visible { color: var(--color-blue); }

  .hero { display: flex; flex-direction: column; align-items: stretch; min-height: 0; padding-block: 12px 56px; }
  .hero__portrait { width: 84%; }
  .hero__copy { margin-block: 22px; }
  .hero__copy h1 { font-size: clamp(48px, 13vw, 72px); }
  .hero__travel { width: 48%; align-self: flex-end; margin: 0; }
  .hero__botanical { display: none; }

  .section-title__meta { display: none; }

  .project-grid, .about, .footer__inner { grid-template-columns: 1fr; }
  /* Reference layout: each card stacks full-width photo, then "(01)
     Label" on one line right below it, one card after another — a
     single column, not a 2-up grid and not a photo/text side-by-side
     row (an earlier attempt at this read the reference wrong). Only
     change from the desktop stack is pulling the index number onto
     the same line as the heading instead of its own line above it.
     .project__index and h3 are separate block-level siblings in the
     markup, so hide the separate index span and render the same
     counter as an h3::before instead — guarantees number + label
     render as one line regardless of source order. */
  .project__index { display: none; }
  .project h3 {
    font-size: 20px; margin-top: 16px; display: flex; align-items: baseline; gap: 8px;
  }
  .project h3::before {
    content: "(0" counter(project-index) ")";
    font: 400 12px/1 var(--font-mono); letter-spacing: .1em; color: var(--color-oxblood);
  }
  .about { row-gap: 32px; min-height: auto; }
  .about__copy { order: 2; }
  .about__portrait { order: 1; }
  /* The desktop clamp() floors at 50px, which is too large for a
     narrow phone column — "Divisha Bhatia — Photographer" wrapped to
     3 lines with the desktop line-height's generous gaps between them. */
  .about__copy h2 { font-size: clamp(34px, 9vw, 46px); line-height: 1.08; }

  .footer__links { border-left: none; padding-left: 0; justify-items: start; margin-top: 24px; }
  .footer__bottom { flex-direction: column; gap: 6px; }
  .about__circle { display: none; }

  .testimonials__grid { grid-template-columns: 1fr; gap: 18px; }
}
@media (max-width: 1024px) and (min-width: 768px) {
  .testimonials__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ---------- Responsive: < 420px ---------- */
@media (max-width: 420px) {
  /* 20px read as nearly edge-to-edge on a narrow phone once compared
     against a reference with a clearly visible margin on both sides —
     28px gives the photos and text real breathing room from both
     edges without eating too much into the already-narrow column. */
  :root { --page-gutter: 28px; }
  .section-title__meta, .about__circle { display: none; }
  .hero__copy h1 { font-size: clamp(40px, 14vw, 56px); }
  .statement h2 { font-size: clamp(32px, 9vw, 44px); }
}
/* =========================================================
   About page (about.html) — rebuilt to pixel-match the client's
   approved mockup (about_page_mockup.png) and the accompanying
   animation guide (Divisha-Bhatia-About-Page-Animation-Guide.md).
   Supersedes the previous About page section entirely (3-photo hero
   row, .about-story, .about-stats, .about-focus 11-card grid,
   .about-pullquote, .about-cta) — see git history if any of that
   earlier structure is ever needed again.

   New page sequence: editorial hero (headline + 3-photo composition)
   → at-a-glance stats → philosophy/story → 4-card selected focus →
   testimonial → Beyond the Camera → contact CTA (working inquiry
   popup) → shared footer.

   Motion throughout reuses the site's existing [data-reveal] +
   IntersectionObserver system (see script.js) and .mask-reveal /
   .fade-up / .fade-in classes already defined above — only the
   page-specific pieces (.image-reveal, .about-editorial-hero__photo
   parallax, the count-up, the two clip-path wipes) are new, and all
   of them are plain CSS transition/animation declarations so the
   sitewide `@media (prefers-reduced-motion: reduce)` override earlier
   in this file already catches them automatically.
   ========================================================= */

/* ---------- Header entrance (About page only) ----------
   Animation guide section 4 "Header": wordmark + nav fade in from
   opacity:0/translateY(-10px), 0.7s, nav links staggered 60ms. Scoped
   to .about-header-intro (only present in about.html's own header
   markup) so index.html/contact.html/journal.html/work pages keep
   their current header behaviour completely untouched — this is
   additive, not a change to the shared .site-header rules above.
   Reuses .fade-in[data-reveal] (opacity-only, no translateY, since the
   guide's header entrance is a smaller -10px lift than the standard
   14px .fade-up) — just need to confirm the -10px specifically here
   since .fade-in normally has transform:none throughout. */
.about-header-intro .wordmark.fade-in[data-reveal],
.about-header-intro nav a.fade-in[data-reveal] {
  transform: translateY(-10px);
  transition: opacity .7s var(--ease-editorial), transform .7s var(--ease-editorial);
  transition-delay: var(--delay, 0ms);
}
.about-header-intro .wordmark.fade-in[data-reveal].is-visible,
.about-header-intro nav a.fade-in[data-reveal].is-visible {
  transform: none;
}

/* ---------- Shared reveal helpers for this page ----------
   .image-reveal: clip-path inset(100% 0 0 0) -> inset(0) — the
   guide's own suggested class name (section 5) for a photo that wipes
   open from the bottom, layered UNDER the existing [data-reveal]
   opacity/transform so a photo both fades up AND unclips as it
   settles in. */
.image-reveal[data-reveal] {
  clip-path: inset(100% 0 0 0);
  transition: opacity .9s var(--ease-editorial), transform .9s var(--ease-editorial), clip-path .9s var(--ease-editorial);
  transition-delay: var(--delay, 0ms);
}
.image-reveal[data-reveal].is-visible {
  clip-path: inset(0 0 0 0);
}

/* Philosophy portrait: interpreted as a vertical wipe (the mask's
   own edge travels along the horizontal axis while the reveal
   progresses top-to-bottom in feel) — the guide's "rounded vertical
   mask" wording is ambiguous between "a mask shaped by rounded
   corners, revealed along a vertical axis" and "a vertical-format
   mask growing vertically"; this session reads it as the former,
   since the photo itself already has rounded top corners (the
   arched frame) and a plain top-to-bottom clip (identical to
   .image-reveal above) would double up on the same axis the frame's
   arch already implies. So instead this variant wipes left-to-right
   (inset 0 100% 0 0 -> inset 0), giving a distinct "curtain" reveal
   axis from the hero photos' bottom-up wipe, while the arched
   corners handle the "rounded" half of the description. */
.image-reveal--vertical[data-reveal] {
  clip-path: inset(0 100% 0 0);
}
.image-reveal--vertical[data-reveal].is-visible {
  clip-path: inset(0 0 0 0);
}

@media (prefers-reduced-motion: reduce) {
  .image-reveal[data-reveal], .image-reveal--vertical[data-reveal] { clip-path: inset(0) !important; }
}

/* ---------- Editorial hero ----------
   Two-column: eyebrow + mask-reveal 4-line headline + paragraph +
   text-link on the left; a layered 3-photo composition on the right
   (large arched portrait, smaller overlapping landscape photo,
   narrow tall arched accent with a handwritten caption). */
.about-editorial-hero {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: center;
  padding-block: clamp(40px, 6vw, 72px) var(--section-space);
}
.about-editorial-hero__copy { max-width: 46ch; }
.about-editorial-hero__eyebrow { display: block; margin-bottom: 18px; color: var(--color-oxblood); }
/* Headline: Cormorant Garamond, the mockup's exact 4-line break. Each
   .line is its own overflow-hidden wrapper (see the shared
   .mask-reveal rule earlier in this file) so the inner span can slide
   up from translateY(105%) independently per line. The mockup shows
   "looks." in the same weight/style as the rest of the sentence (not
   bold/italic) — confirmed by zooming into the reference image, so no
   special styling is applied to that last word. */
.about-editorial-hero__headline {
  font-size: clamp(40px, 5vw, 64px); line-height: 1.1; font-weight: 400;
  margin: 0 0 22px;
}
.about-editorial-hero__copy p { color: var(--color-muted); line-height: 1.7; font-size: 16px; margin: 0 0 20px; }
.about-editorial-hero__tagline {
  font-family: "Cormorant Garamond", serif; font-style: italic;
  font-size: 19px; color: var(--color-plum); margin: -6px 0 24px;
}

/* Photo composition: a positioned stack rather than a plain grid, so
   the smaller photo can overlap the main photo's bottom-left corner
   the way the mockup shows. */
.about-editorial-hero__photos {
  position: relative;
  display: grid; grid-template-columns: 1fr auto;
  align-items: start; gap: clamp(16px, 2vw, 28px);
  min-height: clamp(360px, 42vw, 560px);
}
.about-editorial-hero__photo {
  margin: 0; overflow: hidden; background: var(--color-ivory);
  border-radius: 120px 120px 0 0; /* arched top, matches the hero row's existing language */
}
.about-editorial-hero__photo--main {
  grid-column: 1 / 2; grid-row: 1 / 2;
  aspect-ratio: .68; width: 100%;
}
.about-editorial-hero__photo--support-lower {
  grid-column: 1 / 2; grid-row: 1 / 2;
  align-self: end; justify-self: start;
  width: 58%; aspect-ratio: 1.15;
  /* Overlaps the main photo's bottom-left corner, offset up/left of
     the grid cell's natural position, with a slight rotation per the
     mockup's "slightly rotated/offset" description. */
  margin: 0 0 -8% -12%;
  border-radius: 28px; /* small rounded corners, not arched — distinct from the two arch-topped photos */
  transform: rotate(-2deg);
  box-shadow: 0 18px 40px rgba(36, 31, 35, .22);
  position: relative; z-index: 2;
}
.about-editorial-hero__photo--support-upper {
  grid-column: 2 / 3; grid-row: 1 / 2;
  align-self: start;
  width: clamp(96px, 11vw, 148px); aspect-ratio: .58;
}
.about-editorial-hero__caption {
  grid-column: 2 / 3; grid-row: 1 / 2;
  align-self: start; justify-self: start;
  margin: calc(clamp(96px, 11vw, 148px) / .58 + 18px) 0 0;
  font: 600 22px/1.25 "Caveat", cursive;
  color: var(--color-plum); text-align: left;
  transform: rotate(-2deg);
}
.about-editorial-hero__caption::after {
  content: ""; display: block; width: 30px; height: 1px; margin-top: 10px;
  background: var(--color-rule-strong);
}

@media (max-width: 900px) {
  /* Mobile hero composition, per the guide's section 7: stack copy
     above the photography, then one dominant image + two smaller
     images in a two-column row — the same "simplify the multi-photo
     composition" technique the homepage's own .collage-hero already
     uses at its own 640px breakpoint (see .collage-hero__cluster
     above), applied here to this page's simpler 3-photo layout. */
  .about-editorial-hero { grid-template-columns: 1fr; gap: 28px; }
  .about-editorial-hero__copy { max-width: none; }
  .about-editorial-hero__photos {
    grid-template-columns: 1fr; min-height: 0; gap: 14px;
  }
  .about-editorial-hero__photo--main {
    grid-column: 1; grid-row: 1; aspect-ratio: 1.1;
  }
  .about-editorial-hero__photo--support-lower,
  .about-editorial-hero__photo--support-upper {
    grid-row: 2; width: 100%; margin: 0; transform: none; box-shadow: none;
  }
  .about-editorial-hero__photo--support-lower { grid-column: 1; aspect-ratio: 1; border-radius: 20px; }
  .about-editorial-hero__photo--support-upper { grid-column: 2; aspect-ratio: 1; border-radius: 60px 60px 0 0; }
  .about-editorial-hero__photos { grid-template-columns: 1fr 1fr; }
  .about-editorial-hero__caption { display: none; } /* no room at this width without crowding the two-up row */
}

/* ---------- At-a-glance statistics ----------
   Thin horizontal bar, 4 items, vertical rule dividers, big
   Cormorant Garamond numeral + small uppercase mono label + a small
   decorative dash underneath each — per the mockup. Dividers animate
   scaleY(0)->scaleY(1) on the same [data-reveal] the numbers use. */
.about-glance { padding-block: clamp(12px, 2vw, 24px) 0; }
.about-glance__grid {
  display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  margin: 0; padding: clamp(26px, 3.6vw, 40px) 0;
  border-top: 1px solid var(--color-rule); border-bottom: 1px solid var(--color-rule);
  text-align: center;
}
.about-glance__item {
  position: relative; padding: 0 clamp(8px, 1.6vw, 20px);
}
.about-glance__item + .about-glance__item::before {
  content: ""; position: absolute; left: 0; top: 50%; height: 60%;
  width: 1px; background: var(--color-rule-strong);
  transform: translateY(-50%) scaleY(0); transform-origin: center;
  transition: transform .7s var(--ease-editorial);
  transition-delay: var(--delay, 0ms);
}
.about-glance__grid.is-visible .about-glance__item + .about-glance__item::before { transform: translateY(-50%) scaleY(1); }
.about-glance__item dt { font: 400 clamp(30px, 3.4vw, 46px)/1 var(--font-display); color: var(--color-oxblood); margin: 0; }
.about-glance__item dd { font: 400 11px/1.4 var(--font-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--color-muted); margin: 10px 0 0; }
.about-glance__dash { display: block; width: 18px; height: 1px; margin: 8px auto 0; background: var(--color-rule-strong); }

@media (max-width: 640px) {
  .about-glance__grid { grid-template-columns: repeat(2, minmax(0,1fr)); row-gap: 24px; }
  .about-glance__item:nth-child(3)::before { display: none; } /* only the first item of each row gets a divider */
}

/* ---------- Philosophy / story section ----------
   Two-column: arched portrait + lower-left handwritten note on the
   left, heading + paragraphs + signature on the right. The photo
   column is a fixed aspect-ratio while the copy column runs to
   several paragraphs, so the two are top-aligned (not centered) —
   centering a short photo against a tall text block leaves an
   awkward empty gap above/below the photo. */
.about-philosophy {
  display: grid; grid-template-columns: minmax(0, .82fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 72px);
  align-items: start;
  padding-block: var(--section-space);
}
.about-philosophy__media { position: relative; }
.about-philosophy__photo {
  margin: 0; overflow: hidden; background: var(--color-ivory);
  border-radius: 120px 120px 0 0;
  aspect-ratio: .78;
}
.about-philosophy__note {
  position: absolute; left: -6px; bottom: -34px;
  font: 500 20px/1.3 "Caveat", cursive;
  color: var(--color-plum); text-align: left;
  transform: rotate(-3deg);
  max-width: 9ch;
}
.about-philosophy__copy h2 {
  font-size: clamp(32px, 3.4vw, 48px); line-height: 1.14; font-weight: 400; margin: 0 0 20px;
}
.about-philosophy__copy p { color: var(--color-muted); line-height: 1.7; font-size: 16px; max-width: 52ch; margin: 0 0 16px; }
.about-philosophy__signature {
  font: 600 34px/1 "Caveat", cursive;
  color: var(--color-plum); margin: 10px 0 0;
}

@media (max-width: 767px) {
  .about-philosophy { grid-template-columns: 1fr; gap: 56px; }
  .about-philosophy__note { bottom: -26px; }
}

/* ---------- Testimonial ----------
   Centered pull-quote, large decorative opening quotation mark, one
   generic "— A Client" attribution (matches the mockup exactly, not
   one of the site's named testimonials elsewhere). */
.about-testimonial { text-align: center; padding-block: 0 var(--section-space); }
.about-testimonial__mark {
  display: block; font: 400 64px/1 var(--font-display); color: var(--color-oxblood);
  margin-bottom: 4px;
}
.about-testimonial__quote { margin: 0 auto; max-width: 46ch; }
.about-testimonial__quote p {
  font: 400 clamp(20px, 2.2vw, 28px)/1.5 var(--font-display);
  color: var(--color-charcoal); margin: 0;
}
.about-testimonial__cite {
  display: block; margin-top: 18px; font-style: normal;
  font: 400 12px/1 var(--font-mono); letter-spacing: .1em; text-transform: uppercase;
  color: var(--color-muted);
}

/* ---------- Beyond the Camera ----------
   A dark-plum panel INSET within the page's normal content width
   (page-shell already constrains it — not full-bleed) with rounded
   corners on the panel itself. Split: B&W-treated photo left, copy
   right. Panel background reveals left-to-right via clip-path, text
   fades in after (staggered --delay values already push the copy's
   reveal behind the panel's own ~700ms wipe). */
.about-agency { padding-block: 0 var(--section-space); }
.about-agency__inner {
  position: relative;
  display: grid; grid-template-columns: minmax(0, .62fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 56px);
  align-items: center;
  background: var(--color-plum); color: var(--color-cream);
  border-radius: 28px;
  padding: clamp(20px, 3vw, 32px);
  overflow: hidden;
}
/* Left-to-right wipe: clip-path inset(0 100% 0 0) -> inset(0), gated
   on [data-reveal] like everything else so it fires once on scroll
   and respects reduced-motion via the sitewide override. */
.about-agency__inner.image-reveal--wipe[data-reveal] {
  clip-path: inset(0 100% 0 0);
  transition: clip-path .9s var(--ease-editorial);
}
.about-agency__inner.image-reveal--wipe[data-reveal].is-visible {
  clip-path: inset(0 0 0 0);
}
@media (prefers-reduced-motion: reduce) {
  .about-agency__inner.image-reveal--wipe[data-reveal] { clip-path: inset(0) !important; }
}
.about-agency__photo {
  margin: 0; overflow: hidden; border-radius: 20px;
  aspect-ratio: .9; background: var(--color-ivory);
}
/* Deliberate reuse-with-different-treatment: the same real photo used
   in color in the philosophy section above, grayscale-filtered here so
   the two uses read as distinct rather than an accidental duplicate —
   see the long comment on this <img> in about.html for the full
   rationale (no second real photo of Divisha at a laptop exists yet). */
.about-agency__photo img { filter: grayscale(1); object-position: top; }
.about-agency__eyebrow { color: var(--color-blue); display: block; }
.about-agency__copy h2 {
  font-size: clamp(30px, 3vw, 42px); line-height: 1.1; font-weight: 400;
  margin: 12px 0 0; color: var(--color-cream);
}
.about-agency__copy p {
  color: rgba(248, 231, 201, .82); line-height: 1.7; font-size: 15px;
  margin: 16px 0 0; max-width: 46ch;
}
.about-agency__copy p.about-agency__tagline {
  font-family: "Cormorant Garamond", serif; font-style: italic;
  font-size: 18px; color: var(--color-cream); margin: 10px 0 0;
}
.about-agency__cta {
  color: var(--color-cream); margin-top: 18px;
}

@media (max-width: 767px) {
  .about-agency__inner { grid-template-columns: 1fr; }
  .about-agency__photo { aspect-ratio: 1.4; }
}

/* ---------- Contact CTA panel ----------
   Dark-plum, headline reveals by line via .mask-reveal (reused
   verbatim from the hero), pill-shaped outlined button on the right
   that opens the real inquiry popup (.hero-cta's existing fill/
   text-reverse hover already matches the guide's "fill left-to-right,
   reverse text colour" spec — see .hero-cta:hover above, not
   reinvented here). */
.about-cta-panel {
  padding-block: var(--section-space);
}
.about-cta-panel__inner {
  background: var(--color-plum); color: var(--color-cream);
  border-radius: 28px;
  padding: clamp(32px, 5vw, 56px) clamp(24px, 4vw, 56px);
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  flex-wrap: wrap;
}
.about-cta-panel__inner h2 {
  font-size: clamp(32px, 4vw, 50px); line-height: 1.1; font-weight: 400; margin: 0;
  color: var(--color-cream);
}
.about-cta-panel__cta {
  color: var(--color-cream); border-color: var(--color-cream);
  flex-shrink: 0; background: transparent;
}
.about-cta-panel__cta:hover, .about-cta-panel__cta:focus-visible {
  background: var(--color-cream); color: var(--color-plum);
}

@media (max-width: 640px) {
  .about-cta-panel__inner { flex-direction: column; align-items: flex-start; }
}
