/* =========================================================
   UGC by Karaked — styles
   Palette: bright pink-white / baby pastel pink / deep brown
   ========================================================= */

:root {
  --bg: #FFF7FA;          /* bright, barely-there pink */
  --bg-alt: #FDE7EE;      /* baby pastel pink panel */
  --surface: #FFFFFF;
  --ink: #3E2B2A;         /* warm deep brown, still the text colour */
  --ink-soft: #7C5A58;
  --brown: #4A332F;       /* the About panel */
  --blush: #F9C5D5;       /* baby pastel pink */
  --blush-deep: #CC5580;  /* the pop — 3.9:1 on --bg, display type and links */
  --tan: #F0B9C6;
  --beige: #F7EFE6;       /* the hero title on the pink band */
  --line: rgba(62, 43, 42, 0.13);

  --serif: "Fraunces", Georgia, "Times New Roman", serif;
  --sans: "Instrument Sans", system-ui, -apple-system, "Segoe UI", sans-serif;

  --wrap: 1200px;
  --gutter: clamp(20px, 5vw, 64px);
  --section-y: clamp(88px, 12vw, 160px);
  --radius: 4px;
  --nav-h: 72px;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  /* body already clips, but Safari has a long history of ignoring overflow-x
     on body alone and letting the page pinch out past the viewport. Clipping
     both is the reliable form. Safe here: the nav is fixed, not sticky, so
     this cannot break a sticky descendant. */
  overflow-x: hidden;
  scroll-behavior: smooth;
  scroll-padding-top: var(--nav-h);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video { display: block; max-width: 100%; }
a { color: inherit; }
em { font-style: italic; }

/* The browser's own [hidden] rule is a plain `display: none`, so any
   component that sets its own display wins over it — .btn did, which left
   "Show more" on screen with nothing left to show. */
[hidden] { display: none !important; }

::selection { background: var(--blush); color: var(--ink); }

:focus-visible {
  outline: 2px solid var(--blush-deep);
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: 16px;
  top: -60px;
  z-index: 100;
  padding: 10px 16px;
  background: var(--ink);
  color: var(--bg);
  text-decoration: none;
}
.skip-link:focus { top: 16px; }

/* ---------- Type ---------- */

h1, h2, h3 {
  font-family: var(--serif);
  font-weight: 300;
  line-height: 1.1;
  margin: 0;
  font-variation-settings: "opsz" 144;
}

h1 em, h2 em { color: var(--blush-deep); font-weight: 300; }

.eyebrow {
  margin: 0 0 18px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-soft);
  display: flex;
  align-items: center;
  gap: 12px;
}
.eyebrow::before {
  content: "";
  width: 28px;
  height: 1px;
  background: var(--tan);
}

.section-title {
  font-size: clamp(36px, 5vw, 60px);
  letter-spacing: -0.01em;
}

/* ---------- Buttons & links ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 16px 30px;
  border: 1px solid var(--ink);
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font: 500 15px/1 var(--sans);
  letter-spacing: 0.02em;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.25s, color 0.25s, border-color 0.25s, transform 0.25s;
}
.btn:hover {
  background: var(--blush-deep);
  border-color: var(--blush-deep);
  transform: translateY(-1px);
}
.btn--small { padding: 11px 20px; font-size: 14px; }
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--bg); border-color: var(--ink); }

.link-arrow {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 500;
  font-size: 15px;
  text-decoration: none;
  border-bottom: 1px solid var(--tan);
  padding-bottom: 3px;
  transition: gap 0.25s, border-color 0.25s;
}
.link-arrow::after { content: "→"; }
.link-arrow:hover { gap: 16px; border-color: var(--ink); }

/* ---------- Media placeholders ----------
   Every <figure class="media"> shows a warm gradient + label until
   the real image exists. If the <img> 404s it's removed (onerror).  */

.media {
  position: relative;
  margin: 0;
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 30% 20%, #FFE3EC 0%, transparent 60%),
    linear-gradient(160deg, #FDDDE7 0%, #F8C3D4 55%, #EFA8BF 100%);
  border-radius: var(--radius);
}
.demo .media::after {
  content: attr(data-label);
  position: absolute;
  inset: var(--label-pos, auto 0 0 0);
  padding: 16px;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: rgba(58, 42, 34, 0.55);
  z-index: 0;
}
.media img,
.media video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
}

/* ---------- Nav ---------- */

.nav {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 50;
  height: var(--nav-h);
  transition: background 0.3s, box-shadow 0.3s;
}
.nav.is-scrolled {
  background: rgba(255, 247, 250, 0.9);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  box-shadow: 0 1px 0 var(--line);
}
.nav__inner {
  max-width: var(--wrap);
  height: 100%;
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: flex;
  align-items: center;
  gap: 32px;
}
.nav__logo {
  font-family: var(--serif);
  font-size: 22px;
  font-weight: 400;
  text-decoration: none;
  white-space: nowrap;
  margin-right: auto;
}
.nav__logo em { color: var(--blush-deep); }

.nav__links {
  display: flex;
  gap: 28px;
}
.nav__links a:not(.btn) {
  position: relative;
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  color: var(--ink-soft);
  transition: color 0.2s;
}
.nav__links a:not(.btn)::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -6px;
  height: 1px;
  background: var(--blush-deep);
  transform: scaleX(0);
  transition: transform 0.25s;
}
.nav__links a:not(.btn):hover,
.nav__links a.is-active { color: var(--ink); }
.nav__links a.is-active::after,
.nav__links a:not(.btn):hover::after { transform: scaleX(1); }

.nav__cta-mobile { display: none; }

.nav__toggle {
  display: none;
  width: 44px;
  height: 44px;
  border: 0;
  background: transparent;
  cursor: pointer;
  position: relative;
  margin-right: -10px;
}
.nav__toggle span {
  position: absolute;
  left: 11px;
  right: 11px;
  height: 1.5px;
  background: var(--ink);
  transition: transform 0.3s, top 0.3s;
}
.nav__toggle span:first-child { top: 18px; }
.nav__toggle span:last-child { top: 25px; }
.nav__toggle[aria-expanded="true"] span:first-child { top: 21px; transform: rotate(45deg); }
.nav__toggle[aria-expanded="true"] span:last-child { top: 21px; transform: rotate(-45deg); }

@media (max-width: 900px) {
  .nav__cta { display: none; }
  .nav__toggle { display: block; }

  .nav__links {
    position: fixed;
    inset: var(--nav-h) 0 auto 0;
    flex-direction: column;
    gap: 0;
    padding: 12px var(--gutter) 28px;
    background: var(--bg);
    box-shadow: 0 12px 24px -16px rgba(58, 42, 34, 0.3);
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s, transform 0.25s, visibility 0.25s;
  }
  .nav.is-open { background: var(--bg); }
  .nav.is-open .nav__links { opacity: 1; transform: none; visibility: visible; }
  .nav__links a:not(.btn) {
    padding: 14px 0;
    font-family: var(--serif);
    font-size: 26px;
    font-weight: 300;
    color: var(--ink);
    border-bottom: 1px solid var(--line);
  }
  .nav__links a:not(.btn)::after { display: none; }
  .nav__cta-mobile { display: inline-flex; margin-top: 24px; align-self: flex-start; }
}

/* ---------- Sections ---------- */

.section {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: var(--section-y) var(--gutter);
}
.section-head { margin-bottom: clamp(40px, 6vw, 72px); max-width: 640px; }

/* ---------- Hero ----------
   The band is the pink that used to be the name; the name is beige on it.
   Nothing on this band is the page's normal ink, so everything inside it -
   and the nav sitting over it - gets its colours restated here. */

.hero {
  position: relative;
  min-height: 100svh;
  max-width: var(--wrap);
  margin: 0 auto;
  padding: calc(var(--nav-h) + 40px) var(--gutter) 80px;
  display: grid;
  /* "Chaliaowai" can't break, so the text column's min-content width is the
     whole word: size the type to fit this column or it squeezes the photo. */
  grid-template-columns: 1.25fr 1fr;
  align-items: center;
  gap: clamp(32px, 6vw, 88px);
}
.hero__title {
  font-size: clamp(64px, 9vw, 108px);
  line-height: 0.92;
  letter-spacing: -0.03em;
  margin-bottom: 28px;
}
.hero__title em { display: block; padding-left: 0.5em; }
/* "Chaliaowai" is one unbreakable 10-character word: at the 64px floor above
   it runs past the gutter on a small phone and drags the whole page into
   horizontal scroll. Scale it with the viewport down here instead. */
@media (max-width: 440px) {
  .hero__title { font-size: clamp(38px, 12.5vw, 64px); }
  .hero__title em { padding-left: 0.25em; }
}
.hero__lede {
  max-width: 440px;
  margin: 0 0 40px;
  font-size: clamp(17px, 1.6vw, 20px);
  color: var(--ink-soft);
}
.hero__actions { display: flex; align-items: center; gap: 28px; flex-wrap: wrap; }
.hero__media {
  aspect-ratio: 4 / 5;
  width: 100%;
  max-height: calc(100svh - var(--nav-h) - 120px);
  border-radius: 999px 999px var(--radius) var(--radius);
}

.hero__links {
  list-style: none;
  margin: 32px 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.hero__links a {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 10px 18px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  font-size: 14px;
  font-weight: 500;
  text-decoration: none;
  transition: background 0.2s, border-color 0.2s, color 0.2s;
}
.hero__links a:hover {
  background: var(--blush-deep);
  border-color: var(--blush-deep);
  color: #FFFFFF;
}
.hero__links .icon { width: 17px; height: 17px; flex: none; }

.scroll-cue {
  position: absolute;
  left: var(--gutter);
  bottom: 28px;
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--ink-soft);
}
.scroll-cue i {
  position: relative;
  width: 1px;
  height: 44px;
  background: var(--line);
  overflow: hidden;
}
.scroll-cue i::after {
  content: "";
  position: absolute;
  left: 0; top: -50%;
  width: 1px;
  height: 50%;
  background: var(--ink);
  animation: scroll-line 2s ease-in-out infinite;
}
@keyframes scroll-line {
  0% { top: -50%; }
  100% { top: 100%; }
}

@media (max-width: 800px) {
  .hero {
    grid-template-columns: 1fr;
    padding-top: calc(var(--nav-h) + 16px);
    padding-bottom: 96px;
    gap: 36px;
  }
  .hero__media {
    order: -1;
    aspect-ratio: 4 / 4.4;
    max-height: 62svh;
    border-radius: 200px 200px var(--radius) var(--radius);
  }
  .hero__title { margin-bottom: 20px; }
  .hero__lede { margin-bottom: 32px; }
  .scroll-cue { display: none; }
}

/* ---------- About ---------- */

.about {
  background: var(--brown);
  color: var(--blush);
  padding: var(--section-y) 0;
}
.about__inner {
  max-width: var(--wrap);
  margin: 0 auto;
  padding: 0 var(--gutter);
  display: grid;
  grid-template-columns: 0.9fr 1fr;
  gap: clamp(40px, 8vw, 120px);
  align-items: center;
}
.about__media { aspect-ratio: 3 / 4; }
.about .eyebrow { color: var(--blush); opacity: 0.8; }
.about .eyebrow::before { background: var(--blush); }
.about .section-title { color: var(--blush); }
.about .section-title em { color: #FFFFFF; }
.about__text p { max-width: 480px; color: var(--blush); opacity: 0.9; }
.about .link-arrow { color: var(--blush); border-bottom-color: rgba(249, 197, 213, 0.45); }
.about .link-arrow:hover { border-bottom-color: var(--blush); }
.about__text .section-title { margin-bottom: 28px; }
.about__text .link-arrow { margin-top: 16px; }

@media (max-width: 800px) {
  .about__inner { grid-template-columns: 1fr; }
  .about__media { aspect-ratio: 4 / 5; max-width: 420px; }
}

/* ---------- Insights ---------- */

.insights__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px;
}
.insight {
  padding: 32px 28px;
  background: var(--bg-alt);
  border-radius: var(--radius);
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-height: 220px;
}
.insight__num {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(56px, 6vw, 80px);
  line-height: 1;
  color: var(--ink);
  margin-top: auto;
}
.insight__label {
  font-size: 14px;
  color: var(--ink-soft);
  line-height: 1.5;
}
.insight--list .insight__label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.insight ul {
  list-style: none;
  margin: auto 0 0;
  padding: 0;
  font-family: var(--serif);
  font-size: 21px;
  font-weight: 300;
  line-height: 1.5;
}

@media (max-width: 960px) {
  .insights__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
  .insights__grid { grid-template-columns: 1fr; }
  .insight { min-height: 0; }
}

/* The raw Insights screens under the figures. They are phone screenshots on a
   designed page, so they get a frame and a caption rather than sitting loose. */

.proof { margin: clamp(48px, 6vw, 72px) 0 0; }
.proof__shots {
  list-style: none;
  margin: 0 0 20px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(16px, 2vw, 28px);
}
.proof__shots li {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 18px 40px -28px rgba(62, 43, 42, 0.5);
}
.proof__shots img { width: 100%; height: auto; }
.proof figcaption {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

@media (max-width: 700px) {
  .proof__shots { grid-template-columns: 1fr; max-width: 420px; }
}

/* ---------- Clients ---------- */

/* The section's content is now one 72px strip, so the full section rhythm
   below it reads as a hole. */
.clients { padding-bottom: clamp(56px, 7vw, 96px); }

/* The brand row runs as a marquee: two copies of the list side by side, the
   track slid half its width, so the seam lands exactly where copy one began
   and the loop never shows an edge. */
.brands {
  overflow: hidden;
  /* The track is ~1200px wide, so this is the one box on the page whose
     content cannot shrink. overflow:hidden already clips it; max-width pins
     the box itself to its column so it can never widen the layout either. */
  max-width: 100%;
  border-top: 1px solid var(--line);
  padding-top: 44px;
  /* Softens the cut at both ends so logos fade rather than clip. */
  -webkit-mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
  mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent);
}
.brands__track {
  display: flex;
  align-items: center;
  gap: clamp(44px, 6vw, 88px);
  width: max-content;
  list-style: none;
  margin: 0;
  padding: 0;
  animation: brand-scroll 34s linear infinite;
}
.brands:hover .brands__track,
.brands:focus-within .brands__track { animation-play-state: paused; }
@keyframes brand-scroll {
  to { transform: translateX(-50%); }
}
/* Motion off: a static row that wraps, not a strip people drag.

   The old fallback set overflow-x:auto here, which left a ~1480px scroller
   with no overscroll containment — so a sideways swipe on the brands row
   scrolled it AND chained to the page, which reads as the whole site
   scrolling sideways. It also still held the marquee's clones, so every
   brand appeared twice in it.

   Wrapping instead: the clones are hidden, the five real logos wrap and
   centre, and nothing on the page scrolls horizontally except the portfolio
   gallery, which is meant to. */
@media (prefers-reduced-motion: reduce) {
  /* The marquee keeps running here on request: the logos scrolling is the
     point of this row, and a phone with Reduce Motion on was showing a dead
     static row instead. It stays slow and horizontal and still pauses on
     hover and on keyboard focus.

     !important is needed because the global reduce rule further down zeroes
     every animation-duration with !important; `.brands__track` outranks `*`,
     so this wins on specificity.

     overflow stays hidden either way — a draggable row is what used to chain
     into the page and read as the whole site scrolling sideways. */
  .brands { overflow: hidden; }
  .brands__track { animation: brand-scroll 34s linear infinite !important; }
}

.client {
  transition: color 0.25s, padding 0.25s;
}
.client:hover { color: var(--blush-deep); padding-left: 8px; }
.client a {
  display: inline-block;
  color: inherit;
  text-decoration: none;
}

/* A logo takes its own name's place as soon as its file loads — see
   script.js. A brand with no file keeps its name in type. */
.client__logo { display: none; }
.client.has-logo { line-height: 1; }
.client.has-logo .client__logo {
  display: block;
  /* Taller than it looks like it needs: three of these marks are stacked
     lockups, and at the height of a single-line wordmark they read as specks
     next to a brand still set in 48px type. */
  height: clamp(48px, 5.2vw, 72px);
  width: auto;
  max-width: min(100%, 250px);
  object-fit: contain;
  object-position: left center;
}
.client.has-logo .client__name {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}

/* ---------- Portfolio ---------- */

.pf-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: clamp(28px, 4vw, 44px);
}
.pf-tab {
  padding: 11px 22px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-soft);
  font: 500 15px/1 var(--sans);
  cursor: pointer;
  transition: background 0.2s, color 0.2s, border-color 0.2s;
}
.pf-tab:hover { border-color: var(--ink); color: var(--ink); }
.pf-tab[aria-selected="true"] {
  background: var(--blush-deep);
  border-color: var(--blush-deep);
  color: #FFFFFF;
}
.pf-tab__count { opacity: 0.65; margin-left: 7px; font-size: 12px; }

.pf-strip {
  display: flex;
  align-items: center;
  gap: clamp(8px, 1.4vw, 18px);
}
.pf-panel .grid {
  display: flex;
  flex: 1;
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  gap: clamp(12px, 1.4vw, 20px);
  /* The arrows are the control now; the bar underneath was doing the same job
     twice. Scrolling by touch or trackpad still works. */
  scrollbar-width: none;
}
.pf-panel .grid::-webkit-scrollbar { display: none; }
.pf-panel .grid > .tile {
  flex: 0 0 clamp(230px, 27vw, 340px);
  scroll-snap-align: start;
}

.pf-arrow {
  flex: none;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.2s, color 0.2s, border-color 0.2s, opacity 0.2s;
}
.pf-arrow svg { width: 22px; height: 22px; }
.pf-arrow:hover:not(:disabled) {
  background: var(--blush-deep);
  border-color: var(--blush-deep);
  color: #FFFFFF;
}
.pf-arrow:disabled { opacity: 0.25; cursor: default; }

/* A slot held for a clip that hasn't arrived. Flat grey rather than the warm
   placeholder gradient, so it reads as reserved and not as a photo that
   failed to load. */
.tile--placeholder .media--empty {
  aspect-ratio: 3 / 4;
  background: #EAE4E6;
  border-radius: var(--radius);
}

.grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}
.tile { animation: tile-in 0.45s ease both; }
.tile button {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  text-align: left;
  cursor: pointer;
  color: inherit;
  font: inherit;
}
.tile .media {
  aspect-ratio: 3 / 4;
  transition: transform 0.4s ease;
}
.tile button:hover .media { transform: scale(0.985); }
.tile__play {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: rgba(251, 247, 243, 0.85);
  display: grid;
  place-items: center;
}
.tile__play::before {
  content: "";
  margin-left: 3px;
  border-left: 10px solid var(--ink);
  border-top: 6px solid transparent;
  border-bottom: 6px solid transparent;
}
.tile__meta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 2px 0;
  font-size: 14px;
}
.tile__title { font-weight: 500; }
.tile__client { color: var(--ink-soft); white-space: nowrap; }

@keyframes tile-in {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}

.portfolio__empty {
  display: none;
  padding: clamp(40px, 6vw, 72px);
  background: var(--bg-alt);
  border-radius: var(--radius);
  text-align: center;
}
.portfolio__empty p {
  max-width: 440px;
  margin: 0 auto 28px;
  font-family: var(--serif);
  font-size: clamp(20px, 2.2vw, 26px);
  font-weight: 300;
  line-height: 1.4;
}
.portfolio.is-empty .portfolio__empty { display: block; }
.portfolio.is-empty .pf-tabs,
.portfolio.is-empty #portfolio-panels { display: none; }

@media (max-width: 1000px) { .grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 700px) {
  .grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
  .tile__meta { flex-direction: column; gap: 0; font-size: 13px; }

  /* On a phone the strip is barely wider than one tile, so a fixed 230px tile
     left a four-pixel scrap of the next one clipped at the edge, with its
     caption cut to a single letter — it read as a rendering fault, not as a
     peek. One tile to a screen: the arrows are the affordance, and the snap
     lands each tile flush. */
  .pf-panel .grid > .tile { flex-basis: 100%; }
}

/* ---------- Contact ---------- */

/* The photo is the section on this one: full bleed to the left and to the
   top and bottom edges, no radius, no gutter. */
.contact {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  background: var(--bg-alt);
}
.contact__media {
  --label-pos: 0 0 auto 0;
  border-radius: 0;
  min-height: 100%;
}
.contact__body {
  padding: var(--section-y) var(--gutter);
  max-width: 560px;
}
.contact__body .section-title { margin-bottom: 8px; }

.contact__methods {
  list-style: none;
  margin: 32px 0 44px;
  padding: 0;
  display: grid;
  gap: 18px;
}
.contact__methods a {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  font-family: var(--serif);
  font-size: clamp(19px, 2.1vw, 26px);
  font-weight: 300;
  text-decoration: none;
  overflow-wrap: anywhere;
  transition: color 0.2s;
}
.contact__methods .icon {
  width: 26px;
  height: 26px;
  flex: none;
  color: var(--blush-deep);
  transition: color 0.2s;
}
.contact__methods a:hover .icon { color: var(--ink); }
.contact__methods a:hover { color: var(--blush-deep); }

.form { display: grid; gap: 20px; }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
.form label { display: grid; gap: 6px; }
.form label span {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
}
.form input,
.form textarea {
  width: 100%;
  padding: 12px 0;
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: var(--ink);
  font: 400 17px/1.5 var(--sans);
  border-radius: 0;
  transition: border-color 0.2s;
}
.form textarea { resize: vertical; min-height: 110px; }
.form input:focus,
.form textarea:focus { outline: none; border-color: var(--ink); }
.form [aria-invalid="true"] { border-color: var(--blush-deep); }
.form .btn { justify-self: start; margin-top: 8px; }
.form__status { margin: 0; font-size: 14px; color: var(--ink-soft); min-height: 1.5em; }

@media (max-width: 800px) {
  .contact { grid-template-columns: 1fr; }
  /* The source is a 3:4 portrait. A 4/3 box cropped it to 56% of its height
     and cut her head off the top, which reads as the photo not being there.
     It now matches the image's own ratio and shows all of it.

     The height is set outright rather than left to aspect-ratio. This figure
     is a grid item inside align-items:stretch, and in any engine that
     resolves stretch before aspect-ratio the box collapses and the photo
     disappears entirely. 133.33vw IS the 3:4 of a full-bleed column, so this
     is the same shape by arithmetic instead of by a property that something
     else can win against. align-self:start keeps stretch off it either way. */
  .contact__media {
    align-self: start;
    height: 133.33vw;
    min-height: 0;
  }
  .contact__body { max-width: none; }
  .form__row { grid-template-columns: 1fr; }

  /* Tightened for a phone: stacked, the enquiry form ran to about two and a
     half screens. Every value below is spacing, not type — the fields keep
     their 17px, because anything under 16px makes iOS Safari zoom the whole
     page the moment someone taps into one, and that zoom does not come back. */
  .contact__body { padding: 56px var(--gutter) 64px; }
  .contact__methods { margin: 22px 0 28px; gap: 12px; }
  .form { gap: 14px; }
  .form__row { gap: 14px; }
  .form label { gap: 4px; }
  .form input,
  .form textarea { padding: 9px 0; }
  /* rows="4" in the markup gives the textarea a ~121px intrinsic height, and
     min-height only sets a floor — height is what actually shrinks it. It
     stays drag-resizable, so a long message is not trapped in a small box. */
  .form textarea { min-height: 0; height: 84px; }
  .form .btn { margin-top: 2px; }
  /* Only reserve the status line's height once there is something in it. */
  .form__status:empty { min-height: 0; }
}

/* ---------- Footer ---------- */

.footer {
  padding: 56px var(--gutter);
  background: var(--ink);
  color: rgba(245, 237, 230, 0.75);
  text-align: center;
  font-size: 14px;
}
.footer p { margin: 0 0 8px; }
.footer a { text-decoration: none; color: var(--bg); }
.footer a:hover { color: var(--blush); }
.footer__logo {
  font-family: var(--serif);
  font-size: 28px;
  color: var(--bg);
  margin-bottom: 16px !important;
}
.footer__logo em { color: var(--blush); }
.footer__small { font-size: 12px; opacity: 0.6; margin-top: 16px !important; }

/* ---------- Lightbox ---------- */

.lightbox {
  width: min(92vw, 900px);
  max-height: 92vh;
  max-height: 92dvh;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
}
.lightbox::backdrop { background: rgba(38, 27, 21, 0.88); }
.lightbox__stage {
  display: grid;
  place-items: center;
}
.lightbox__stage img,
.lightbox__stage video {
  max-height: 82vh;
  max-height: 82dvh;
  max-width: 100%;
  width: auto;
  border-radius: var(--radius);
}
.lightbox__stage .media {
  width: min(60vw, 380px);
  aspect-ratio: 9 / 16;
  max-height: 82vh;
  max-height: 82dvh;
}
.lightbox__caption {
  margin: 14px 0 0;
  text-align: center;
  color: var(--bg);
  font-size: 14px;
}
.lightbox__close {
  position: absolute;
  top: -8px;
  right: -8px;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 50%;
  background: var(--bg);
  color: var(--ink);
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
  z-index: 3;
}

/* ---------- Scroll reveal ---------- */

.js .reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.8s ease, transform 0.8s ease;
}
.js .reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
  .js .reveal { opacity: 1; transform: none; }
}
