/* ==========================================================================
   Grasslands Flower Co.
   Type: Fraunces (display serif, variable) + Inter (labels, variable)
   Colour is pulled from the photography itself — warm ink, bone, deep foliage.
   ========================================================================== */

@font-face {
  font-family: 'Fraunces';
  src: url('/assets/fonts/fraunces-var.woff2') format('woff2-variations');
  font-weight: 300 900;
  font-display: swap;
}
@font-face {
  font-family: 'Inter';
  src: url('/assets/fonts/inter-var.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-display: swap;
}

:root {
  --ink:        #14120E;
  --ink-2:      #221F19;
  --ink-soft:   #565048;
  --bone:       #F2EEE6;
  --bone-2:     #E7E1D5;
  --bone-dim:   #CFC7B8;
  --sage:       #2A3327;
  --clay:       #A0583C;

  /* themed slots — flipped per branch */
  --bg:    var(--bone);
  --fg:    var(--ink);
  --muted: var(--ink-soft);
  --rule:  rgba(20, 18, 14, .16);
  --accent: var(--clay);

  --serif: 'Fraunces', 'Iowan Old Style', Georgia, serif;
  --sans:  'Inter', system-ui, -apple-system, sans-serif;

  --display-vf: 'SOFT' 40, 'WONK' 1, 'opsz' 144;
  --ease: cubic-bezier(.16, 1, .3, 1);

  --step--2: clamp(.62rem, .6rem + .08vw,  .68rem);
  --step--1: clamp(.7rem,  .67rem + .12vw, .78rem);
  --step-0:  clamp(.95rem, .91rem + .2vw,  1.06rem);
  --step-1:  clamp(1.15rem,1.03rem + .6vw, 1.5rem);
  --step-2:  clamp(1.6rem, 1.3rem + 1.5vw, 2.6rem);
  --step-3:  clamp(2.1rem, 1.5rem + 3vw,   4.2rem);
  --step-4:  clamp(2.8rem, 1.6rem + 5.6vw, 7rem);
  --step-5:  clamp(3.2rem, 1.3rem + 8.6vw, 10.5rem);

  --gut: clamp(1.25rem, 4.5vw, 5rem);
  --sec: clamp(5rem, 12vh, 11rem);
}

[data-theme='dark'] {
  --bg: var(--ink);
  --fg: var(--bone);
  --muted: #9A9184;
  --rule: rgba(242, 238, 230, .18);
  --accent: #C98A63;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--serif);
  font-size: var(--step-0);
  font-weight: 350;
  line-height: 1.62;
  font-variation-settings: 'SOFT' 20, 'WONK' 0, 'opsz' 14;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* height:auto so the width/height attributes (kept for CLS) never dictate the
   rendered box; the .ph/.hero rules below still win where a fill is wanted. */
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }

::selection { background: var(--fg); color: var(--bg); }

/* ---------- primitives ---------- */

.eyebrow {
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0;
}

.display {
  font-family: var(--serif);
  font-weight: 300;
  font-variation-settings: var(--display-vf);
  line-height: .93;
  letter-spacing: -.02em;
  margin: 0;
  text-wrap: balance;
}

.lede {
  font-size: var(--step-1);
  font-weight: 300;
  line-height: 1.45;
  font-variation-settings: 'SOFT' 30, 'WONK' 0, 'opsz' 40;
  text-wrap: pretty;
}

.rule { height: 1px; background: var(--rule); border: 0; margin: 0; }

.wrap { padding-inline: var(--gut); }
.measure { max-width: 62ch; }

/* progressive image: blurred seed underneath, sharp file fades over it */
.ph {
  position: relative;
  overflow: hidden;
  background-color: var(--bone-2);
  background-size: cover;
  background-position: center;
}
.ph > img {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .9s var(--ease);
}
/* When .ph is the fill layer of a full-bleed block it must inherit the full
   height — otherwise height:100% on the img resolves against an auto-height
   parent and the photo sizes to its own aspect ratio, leaving a gap. */
.gate__media > .ph,
.hero__media > .ph,
.crossover__media > .ph { height: 100%; }
.ph > img.is-loaded { opacity: 1; }

/* scroll reveal */
.rv {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 1.1s var(--ease), transform 1.1s var(--ease);
  transition-delay: var(--d, 0ms);
}
.rv.is-in { opacity: 1; transform: none; }

.rv-clip { clip-path: inset(0 0 100% 0); transition: clip-path 1.3s var(--ease); transition-delay: var(--d, 0ms); }
.rv-clip.is-in { clip-path: inset(0 0 0 0); }

/* ==========================================================================
   SPLASH GATE
   ========================================================================== */

.gate {
  height: 100svh;
  display: flex;
  overflow: hidden;
  background: var(--ink);
}

.gate__panel {
  position: relative;
  /* fixed halves — the centre rule must never move; hover scales the
     photograph inside the frame instead */
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  isolation: isolate;
  color: var(--bone);
}

.gate__media { position: absolute; inset: 0; z-index: -2; overflow: hidden; }
.gate__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transform: scale(1);
  filter: saturate(.82);
  transition: transform 1.6s var(--ease), filter 1.15s var(--ease);
}
.gate__panel::after {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(to top, rgba(12,11,8,.88) 0%, rgba(12,11,8,.42) 42%, rgba(12,11,8,.30) 100%);
  transition: opacity 1.15s var(--ease);
}

/* The botanical panel is a high-key image — a lighter, bottom-weighted scrim
   keeps it luminous against the forest panel while the caption stays legible. */
.gate__panel--light::after {
  background:
    linear-gradient(to top, rgba(12,11,8,.86) 0%, rgba(12,11,8,.40) 34%, rgba(12,11,8,.06) 66%, rgba(12,11,8,0) 100%);
}
.gate__panel--light .gate__media img { object-position: 64% 46%; filter: saturate(.95); }
/* insurance for white type crossing pale blooms, without darkening the image.
   Set on the container so the index marker and ENTER inherit it too. */
.gate__panel--light .gate__inner { text-shadow: 0 1px 20px rgba(12,11,8,.6); }
.gate__panel--light .gate__index::after { background: rgba(242,238,230,.6); }

.gate__inner {
  padding: var(--gut);
  padding-bottom: clamp(2.6rem, 7vh, 4.5rem);
  max-width: 34rem;
}

.gate__index {
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: rgba(242,238,230,.72);
  display: flex; align-items: center; gap: .9rem;
  margin: 0 0 clamp(.9rem, 2vh, 1.6rem);
}
.gate__index::after {
  content: ''; height: 1px; flex: 1;
  background: rgba(242,238,230,.34);
  max-width: 5.5rem;
  transform-origin: left;
  transform: scaleX(.4);
  transition: transform 1.15s var(--ease);
}

.gate__title {
  font-size: var(--step-4);
  margin: 0;
  font-weight: 300;
  font-variation-settings: var(--display-vf);
  line-height: .92;
  letter-spacing: -.025em;
}
.gate__title em {
  display: block;
  font-style: normal;
  font-size: .56em;
  letter-spacing: -.01em;
  color: rgba(242,238,230,.86);
}

.gate__desc {
  margin: clamp(1rem, 2.4vh, 1.6rem) 0 0;
  font-size: var(--step-0);
  font-weight: 300;
  line-height: 1.5;
  color: rgba(242,238,230,.78);
  max-width: 30ch;
  text-wrap: pretty;
}

.gate__enter {
  display: inline-flex; align-items: center; gap: .75rem;
  margin-top: clamp(1.4rem, 3.2vh, 2.2rem);
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
}
.gate__enter span {
  position: relative;
  padding-bottom: .35rem;
}
.gate__enter span::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0;
  height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: left;
  transition: transform .9s var(--ease);
}
.gate__arrow { transition: transform .9s var(--ease); }

/* The halves stay fixed so the centre rule never moves; the photograph grows
   inside its own frame instead. Keyed to layout width only — `(hover: hover)`
   was excluding real desktop browsers, since remote sessions and some Firefox
   builds report no pointer at all.
   `.is-hover` / `.is-hovering` mirror the :has() rules for browsers without it. */
@media (min-width: 861px) {
  .gate:has(.gate__panel:hover) .gate__panel:not(:hover)::after,
  .gate.is-hovering .gate__panel:not(.is-hover)::after { opacity: 1; }

  .gate:has(.gate__panel:hover) .gate__panel:not(:hover) .gate__media img,
  .gate.is-hovering .gate__panel:not(.is-hover) .gate__media img {
    filter: saturate(.4) brightness(.74);
  }

  .gate__panel:hover::after,
  .gate__panel.is-hover::after { opacity: .74; }

  .gate__panel:hover .gate__media img,
  .gate__panel.is-hover .gate__media img { transform: scale(1.11); filter: saturate(1.02); }
}
.gate__panel:hover .gate__index::after,
.gate__panel:focus-within .gate__index::after { transform: scaleX(1); }
.gate__panel:hover .gate__enter span::after,
.gate__panel:focus-within .gate__enter span::after { transform: scaleX(1); }
.gate__panel:hover .gate__arrow,
.gate__panel:focus-within .gate__arrow { transform: translateX(6px); }

.gate__link { position: absolute; inset: 0; z-index: 3; }
.gate__link:focus-visible { outline: 2px solid var(--bone); outline-offset: -6px; }

.gate__divide {
  position: absolute; top: 0; bottom: 0; left: 50%;
  width: 1px; background: rgba(242,238,230,.28);
  z-index: 4; pointer-events: none;
  transform: scaleY(0); transform-origin: top;
  animation: divideIn 1.5s var(--ease) .5s forwards;
}
@keyframes divideIn { to { transform: scaleY(1); } }

/* gate chrome — wordmark left, place right, spanning the centre rule */
.gate__head {
  position: absolute; top: 0; left: 0; right: 0;
  z-index: 5; pointer-events: none;
  padding: clamp(1.4rem, 3.2vh, 2.4rem) var(--gut);
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
}
/* the right panel is high-key, so the chrome needs its own scrim */
.gate__head::before {
  content: '';
  position: absolute; inset: -1px 0 auto 0; height: 190%;
  background: linear-gradient(to bottom, rgba(12,11,8,.5), rgba(12,11,8,0));
  pointer-events: none; z-index: -1;
}
.gate__head a { pointer-events: auto; }
.gate__logo {
  width: clamp(9rem, 15vw, 14rem);
  opacity: 0;
  animation: fadeUp 1.5s var(--ease) .85s forwards;
}
.gate__place {
  font-family: var(--sans);
  font-size: var(--step--1);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(242,238,230,.74);
  text-align: right;
  opacity: 0;
  animation: fadeUp 1.5s var(--ease) 1s forwards;
}
.gate__foot {
  position: absolute; bottom: 0; left: 0; right: 0;
  z-index: 5; pointer-events: none;
  padding: 0 var(--gut) clamp(1rem, 2.4vh, 1.6rem);
  display: flex; justify-content: center;
  font-family: var(--sans);
  font-size: var(--step--1);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(242,238,230,.55);
  opacity: 0;
  animation: fadeUp 1.5s var(--ease) 1.15s forwards;
}
@keyframes fadeUp { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* entrance */
.gate__panel { animation: panelIn 1.5s var(--ease) both; }
.gate__panel:nth-child(1) { animation-delay: .05s; }
.gate__panel:nth-child(2) { animation-delay: .2s; }
@keyframes panelIn { from { clip-path: inset(0 0 100% 0); } to { clip-path: inset(0 0 0 0); } }
.gate__inner > * { animation: fadeUp 1.2s var(--ease) both; }
.gate__inner > *:nth-child(1) { animation-delay: 1.0s; }
.gate__inner > *:nth-child(2) { animation-delay: 1.1s; }
.gate__inner > *:nth-child(3) { animation-delay: 1.2s; }
.gate__inner > *:nth-child(4) { animation-delay: 1.3s; }
.gate__inner > *:nth-child(5) { animation-delay: 1.4s; }

@media (max-width: 860px) {
  .gate { flex-direction: column; height: auto; min-height: 100svh; }
  .gate__panel { min-height: 62svh; flex: 1 1 auto; }
  .gate__divide { display: none; }
  /* head/foot follow the panels in the DOM; flex order puts the wordmark
     first on a stacked layout where it reads as the introduction. */
  .gate__head {
    position: static; order: -1; background: var(--ink);
    padding-block: clamp(1.4rem, 4vh, 2rem);
    align-items: flex-end;
  }
  .gate__head::before { display: none; }
  .gate__logo { width: 9.5rem; opacity: 1; animation: none; }
  .gate__place { opacity: 1; animation: none; font-size: .62rem; letter-spacing: .14em; }
  .gate__foot {
    position: static; order: 1; background: var(--ink);
    padding-top: 1.2rem; padding-bottom: 1.5rem;
    text-align: center;
    opacity: 1; animation: none;
  }
  .gate__title { font-size: clamp(2.6rem, 12vw, 4rem); }
}

/* ==========================================================================
   SITE CHROME (interior pages)
   ========================================================================== */

/* Sits over full-bleed heroes. A soft scrim guarantees legibility on light and
   dark photography alike — blend modes were unreliable over pale imagery. */
.head {
  position: fixed; top: 0; left: 0; right: 0; z-index: 60;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem;
  padding: clamp(1rem, 2.4vh, 1.6rem) var(--gut);
  transition: transform .7s var(--ease);
}
.head::before {
  content: '';
  position: absolute; inset: -1px 0 auto 0; height: 200%;
  background: linear-gradient(to bottom, rgba(12,11,8,.55), rgba(12,11,8,0));
  pointer-events: none; z-index: -1;
}
.head--hidden { transform: translateY(-110%); }
.head a { color: #F2EEE6; }

/* Pages that open on a flat background rather than a hero. */
.head--ink::before { display: none; }
.head--ink a { color: var(--ink); }
.head__logo img { width: clamp(7rem, 11vw, 10.5rem); }
.head__nav {
  display: flex; gap: clamp(1rem, 2.6vw, 2.4rem);
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
}
.head__nav a { position: relative; padding-bottom: .25rem; }
.head__nav a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: currentColor; transform: scaleX(0); transform-origin: right;
  transition: transform .6s var(--ease);
}
.head__nav a:hover::after, .head__nav a[aria-current]::after { transform: scaleX(1); transform-origin: left; }

/* The mobile trigger. A word rather than an icon, because the site already
   speaks in letterspaced caps — and an <a href="/"> rather than a <button>, so
   with no JS it still reaches the entry page, which indexes the whole site. */
.head__menu {
  display: none;
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding-bottom: .25rem;
  border-bottom: 1px solid currentColor;
}

@media (max-width: 700px) {
  /* Three columns so the logo is centred on the viewport, not merely between
     its neighbours — the empty first column balances the trigger's width. */
  .head { display: grid; grid-template-columns: 1fr auto 1fr; gap: .5rem; }
  .head__logo { grid-column: 2; justify-self: center; }
  .head__logo img { width: clamp(7.5rem, 32vw, 9.5rem); }
  .head__nav { display: none; }
  .head__menu { grid-column: 3; justify-self: end; display: inline-block; }
}

/* ---------- the menu overlay ---------- */

/* Compound selectors, not bare .navmodal: the .modal block that sets a capped
   width and max-height sits further down this file, so at equal specificity it
   would win on source order and the menu would open as a small centred panel. */
.modal.navmodal {
  width: 100vw;
  max-width: none;
  height: 100dvh;
  max-height: none;
  background: var(--ink);
  color: var(--bone);
}
.modal.navmodal::backdrop { background: var(--ink); }
/* a full-screen panel should fade, not slide — a translate on something already
   the height of the viewport just pushes its own bottom edge off-screen */
.modal.navmodal[open] { animation: modal-fade .5s var(--ease) both; }
.modal.navmodal .navmodal__panel {
  height: 100%;
  max-height: none;
  overflow-y: auto;
  padding: clamp(1.4rem, 5vw, 2.4rem);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.2rem;
}
.navmodal__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: clamp(.6rem, 2.4vh, 1.2rem);
}
.navmodal__list a {
  font-family: var(--serif);
  font-variation-settings: var(--display-vf);
  font-size: clamp(2rem, 11vw, 3.2rem);
  font-weight: 300;
  line-height: 1.02;
  color: var(--bone);
  text-wrap: balance;
}
/* the current page is stated, not offered */
.navmodal__list a[aria-current] { color: var(--bone-dim); }
.navmodal__social {
  margin-top: 1.2rem;
  align-self: start;
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--bone);
  padding-bottom: .3rem;
  border-bottom: 1px solid rgba(242,238,230,.45);
}
.navmodal .modal__close {
  position: absolute;
  top: clamp(1rem, 4vw, 1.8rem);
  right: clamp(1rem, 4vw, 1.8rem);
  margin: 0;
  background: transparent;
  border-color: rgba(242,238,230,.35);
  color: var(--bone);
}

/* ---------- hero ---------- */

.hero {
  position: relative;
  height: 100svh;
  min-height: 34rem;
  display: flex; align-items: flex-end;
  overflow: hidden;
  background: var(--ink);
  color: var(--bone);
}
.hero__media { position: absolute; inset: 0; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; }
.hero::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(12,11,8,.86), rgba(12,11,8,.30) 55%, rgba(12,11,8,.44));
}
.hero__inner {
  position: relative; z-index: 2;
  padding: var(--gut);
  padding-bottom: clamp(3rem, 9vh, 6rem);
  width: 100%;
}
.hero__title {
  font-size: var(--step-5);
  font-weight: 300;
  font-variation-settings: var(--display-vf);
  line-height: .88;
  letter-spacing: -.03em;
  margin: .3em 0 0;
}
.hero__title em { display: block; font-style: normal; font-size: .52em; color: rgba(242,238,230,.82); letter-spacing: -.015em; }
.hero__meta {
  margin-top: clamp(1.2rem, 3vh, 2rem);
  display: flex; flex-wrap: wrap; gap: .5rem 1.6rem;
  font-family: var(--sans); font-size: var(--step--1);
  letter-spacing: .16em; text-transform: uppercase;
  color: rgba(242,238,230,.68);
}
.hero .eyebrow { color: rgba(242,238,230,.72); }

.scrollcue {
  position: absolute; z-index: 3; right: var(--gut); bottom: clamp(3rem, 9vh, 6rem);
  font-family: var(--sans); font-size: var(--step--1);
  letter-spacing: .18em; text-transform: uppercase;
  color: rgba(242,238,230,.6);
  display: flex; align-items: center; gap: .7rem;
}
.scrollcue::after {
  content: ''; width: 3.5rem; height: 1px; background: currentColor;
  transform-origin: left; animation: cue 2.6s var(--ease) infinite;
}
@keyframes cue { 0%,100% { transform: scaleX(.35); opacity: .5 } 50% { transform: scaleX(1); opacity: 1 } }
@media (max-width: 700px) { .scrollcue { display: none; } }

/* ---------- sections ---------- */

.sec { padding-block: var(--sec); }
.sec--tight { padding-block: calc(var(--sec) * .58); }

.statement {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  max-width: 90rem; margin-inline: auto;
}
@media (min-width: 900px) {
  .statement { grid-template-columns: 14rem minmax(0, 1fr); }
}
.statement__body p { margin: 0 0 1.1em; max-width: 46ch; }
.statement__body p:last-child { margin-bottom: 0; }
.statement__big {
  font-size: var(--step-2);
  font-weight: 300;
  line-height: 1.24;
  font-variation-settings: 'SOFT' 34, 'WONK' 1, 'opsz' 90;
  letter-spacing: -.015em;
  max-width: 22ch;
  margin: 0 0 1.4rem;
  text-wrap: balance;
}

/* ---------- service index with image reveal ---------- */

.index { max-width: 90rem; margin-inline: auto; position: relative; }
.index__list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.index__item { border-bottom: 1px solid var(--rule); }
.index__row {
  display: grid;
  grid-template-columns: 3.5rem minmax(0,1fr);
  align-items: baseline;
  gap: clamp(.8rem, 2vw, 2rem);
  padding: clamp(1.1rem, 2.6vw, 2rem) 0;
  width: 100%;
  background: none; border: 0; color: inherit;
  font: inherit; text-align: left; cursor: pointer;
  transition: opacity .6s var(--ease);
}
@media (min-width: 900px) {
  .index__row { grid-template-columns: 3.5rem minmax(0,22rem) minmax(0,1fr); }
}
.index__num {
  font-family: var(--sans); font-size: var(--step--1);
  letter-spacing: .12em; color: var(--muted);
}
.index__name {
  font-size: var(--step-2);
  font-weight: 300;
  font-variation-settings: var(--display-vf);
  letter-spacing: -.02em;
  line-height: 1.05;
  transition: transform .8s var(--ease), color .5s var(--ease);
}
.index__blurb {
  /* Narrow screens give the row two columns for three children, so the blurb
     wraps to a second row — pin it under the name instead of letting it fall
     into the 3.5rem number column, where it sets one word per line. */
  grid-column: 2 / -1;
  margin: .6rem 0 0;
  color: var(--muted);
  max-width: 44ch;
  font-size: var(--step-0);
  line-height: 1.55;
}
@media (min-width: 900px) {
  .index__blurb { grid-column: auto; margin-top: 0; }
  .index:has(.index__row:hover) .index__row:not(:hover) { opacity: .38; }
  .index__row:hover .index__name { transform: translateX(14px); }
}
/* Fallback for browsers without :has() — dim via a JS-applied class instead. */
.index.is-hovering .index__row:not(.is-hover) { opacity: .38; }

/* floating preview that follows the pointer */
.index__preview {
  position: fixed; top: 0; left: 0;
  width: clamp(15rem, 21vw, 24rem);
  aspect-ratio: 4 / 5;
  z-index: 40;
  pointer-events: none;
  opacity: 0;
  transform: translate(-50%, -50%) scale(.94);
  transition: opacity .55s var(--ease), transform .8s var(--ease);
  overflow: hidden;
}
.index__preview.is-on { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.index__preview img {
  width: 100%; height: 100%; object-fit: cover;
  position: absolute; inset: 0;
  opacity: 0; transition: opacity .5s var(--ease);
}
.index__preview img.is-on { opacity: 1; }
/* Width-gated only; the JS decides whether a real mouse is driving. */
@media (max-width: 899px) { .index__preview { display: none; } }

/* ---------- galleries ---------- */

.bleed { position: relative; width: 100%; }
.bleed .ph { aspect-ratio: 16 / 8; }
@media (max-width: 700px) { .bleed .ph { aspect-ratio: 4 / 5; } }

.bleed__cap, .fig__cap {
  margin: .85rem 0 0;
  font-family: var(--sans); font-size: var(--step--1);
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted);
}
.bleed__cap { padding-inline: var(--gut); }

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: clamp(.6rem, 1.6vw, 1.6rem) clamp(.6rem, 1.6vw, 1.6rem);
  max-width: 100rem; margin-inline: auto;
}
.grid figure { margin: 0; }
.grid .ph { width: 100%; }

/* deliberate, asymmetric placements rather than a uniform grid */
.g-a { grid-column: 1 / span 7; }
.g-a .ph { aspect-ratio: 4 / 5; }
.g-b { grid-column: 9 / span 4; align-self: end; }
.g-b .ph { aspect-ratio: 3 / 4; }
.g-c { grid-column: 2 / span 4; }
.g-c .ph { aspect-ratio: 3 / 4; }
.g-d { grid-column: 7 / span 6; }
.g-d .ph { aspect-ratio: 4 / 3; }
.g-e { grid-column: 1 / span 5; align-self: start; }
.g-e .ph { aspect-ratio: 1 / 1; }
.g-f { grid-column: 7 / span 5; }
.g-f .ph { aspect-ratio: 4 / 5; }
.g-wide { grid-column: 1 / -1; }
.g-wide .ph { aspect-ratio: 16 / 7; }

@media (max-width: 860px) {
  .g-a, .g-b, .g-c, .g-d, .g-e, .g-f { grid-column: 1 / -1; }
  .g-a .ph, .g-b .ph, .g-c .ph, .g-d .ph, .g-e .ph, .g-f .ph { aspect-ratio: 4 / 5; }
  .g-wide .ph { aspect-ratio: 4 / 3; }
}

/* horizontal filmstrip */
.strip {
  display: flex; gap: clamp(.6rem, 1.4vw, 1.2rem);
  overflow-x: auto;
  padding-inline: var(--gut);
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.strip::-webkit-scrollbar { display: none; }
.strip figure { margin: 0; flex: 0 0 auto; scroll-snap-align: center; }
.strip .ph { width: clamp(15rem, 30vw, 30rem); aspect-ratio: 3 / 4; }
.strip figure:nth-child(even) .ph { aspect-ratio: 4 / 5; width: clamp(13rem, 25vw, 25rem); }

/* ---------- feature split ---------- */

.feature {
  display: grid; gap: clamp(1.6rem, 4vw, 4rem);
  align-items: center;
  max-width: 100rem; margin-inline: auto;
}
@media (min-width: 900px) {
  .feature { grid-template-columns: 1.05fr .95fr; }
  .feature--flip .feature__media { order: 2; }
}
.feature__media .ph { aspect-ratio: 4 / 5; }
.feature__body { max-width: 46ch; }
.feature__title {
  font-size: var(--step-3);
  font-weight: 300;
  font-variation-settings: var(--display-vf);
  line-height: .98; letter-spacing: -.025em;
  margin: .5rem 0 1.2rem;
}

/* ---------- process ---------- */

.steps {
  display: grid; gap: clamp(1.6rem, 3vw, 2.5rem);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  max-width: 100rem; margin-inline: auto;
}
.step { border-top: 1px solid var(--rule); padding-top: 1.1rem; }
.step__n { font-family: var(--sans); font-size: var(--step--1); letter-spacing: .16em; color: var(--muted); }
.step__t {
  font-size: var(--step-1); font-weight: 350; margin: .5rem 0 .6rem;
  font-variation-settings: 'SOFT' 30, 'WONK' 1, 'opsz' 40;
  letter-spacing: -.01em;
}
.step p { margin: 0; color: var(--muted); font-size: calc(var(--step-0) * .96); line-height: 1.6; }

/* ---------- forms ---------- */

.form-sec { max-width: 100rem; margin-inline: auto; }
.form-grid { display: grid; gap: clamp(1.6rem, 5vw, 5rem); }
@media (min-width: 950px) { .form-grid { grid-template-columns: 1fr 1.25fr; } }

.form { display: grid; gap: clamp(1.4rem, 2.6vw, 2rem); }
.field { position: relative; display: flex; flex-direction: column; gap: .45rem; }
.field > label, .fieldset > legend {
  font-family: var(--sans); font-size: var(--step--1);
  letter-spacing: .16em; text-transform: uppercase; color: var(--muted);
  padding: 0;
}
.field input, .field select, .field textarea {
  appearance: none;
  width: 100%;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--rule);
  border-radius: 0;
  padding: .55rem 0;
  font-family: var(--serif);
  font-size: var(--step-1);
  font-weight: 300;
  color: var(--fg);
  transition: border-color .5s var(--ease);
}
.field textarea { resize: vertical; min-height: 5.5rem; line-height: 1.5; }
.field select {
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: right 6px center, right 1px center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  cursor: pointer;
}
.field select option { background: var(--bg); color: var(--fg); }
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none; border-bottom-color: var(--fg);
}
.field input::placeholder, .field textarea::placeholder { color: var(--muted); opacity: .55; }

.row { display: grid; gap: clamp(1.4rem, 2.6vw, 2rem); }
@media (min-width: 620px) {
  .row--2 { grid-template-columns: 1fr 1fr; }
  .row--3 { grid-template-columns: 1fr 1fr 1fr; }
}

.fieldset { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .9rem; }
/* A <legend> is not a flex item — the fieldset's gap never applies to it, so a
   row of pills rides up and overlaps the label by a few pixels. Floating it at
   full width puts it back in normal flow, and the margin then stands in for the
   gap. Scoped to the pill row on purpose: the tick-box fieldsets sit flush
   against their legend already and are live, so they are left alone. */
.fieldset--pills > legend { float: left; width: 100%; margin-bottom: .35rem; }
.checks { display: grid; gap: .7rem; }
@media (min-width: 620px) { .checks--2 { grid-template-columns: 1fr 1fr; } }

.check { display: flex; align-items: center; gap: .7rem; cursor: pointer; font-size: var(--step-0); font-weight: 300; }
.check input { position: absolute; opacity: 0; width: 0; height: 0; }
.check__box {
  width: 1.05rem; height: 1.05rem; flex: 0 0 auto;
  border: 1px solid var(--rule);
  position: relative;
  transition: border-color .4s var(--ease), background-color .4s var(--ease);
}
.check__box::after {
  content: ''; position: absolute; inset: 3px;
  background: var(--fg);
  transform: scale(0);
  transition: transform .35s var(--ease);
}
.check input:checked + .check__box::after { transform: scale(1); }
.check input:checked + .check__box { border-color: var(--fg); }
.check input:focus-visible + .check__box { outline: 2px solid var(--fg); outline-offset: 2px; }

.btn {
  justify-self: start;
  display: inline-flex; align-items: center; gap: .9rem;
  background: var(--fg); color: var(--bg);
  border: 1px solid var(--fg);
  padding: .95rem 1.8rem;
  font-family: var(--sans); font-size: var(--step--1); font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase;
  cursor: pointer;
  transition: background-color .6s var(--ease), color .6s var(--ease);
}
.btn:hover { background: transparent; color: var(--fg); }
.btn svg { transition: transform .6s var(--ease); }
.btn:hover svg { transform: translateX(5px); }

.form-note {
  font-family: var(--sans); font-size: var(--step--1);
  letter-spacing: .04em; color: var(--muted); margin: 0;
  line-height: 1.7;
}

/* ---------- product order form ---------- */

.products { display: flex; flex-direction: column; }
.product {
  display: grid; grid-template-columns: 8rem 1fr; gap: 1.5rem;
  align-items: start;
  padding: 1.7rem 0;
  border-top: 1px solid var(--rule);
}
.products .product:first-child { border-top: 0; padding-top: 0; }
.product .ph { aspect-ratio: 4/5; }
.product__body { display: flex; flex-direction: column; gap: 1rem; }
.product__head { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.product__name { font-family: var(--serif); font-size: var(--step-1); font-weight: 300; margin: 0; }
.product__price { font-family: var(--sans); font-size: var(--step--1); color: var(--muted); margin: 0; white-space: nowrap; }

@media (max-width: 480px) {
  .product { grid-template-columns: 5.5rem 1fr; gap: 1rem; }
  .product__name { font-size: var(--step-0); }
}

.product__opts { display: flex; flex-wrap: wrap; gap: .5rem; }
.fulfillment { margin: -.4rem 0 .2rem; }
.pill { cursor: pointer; }
.pill input { position: absolute; opacity: 0; width: 0; height: 0; }
.pill span {
  display: inline-block;
  padding: .4rem .85rem;
  border: 1px solid var(--rule);
  font-family: var(--sans); font-size: var(--step--2);
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
  transition: border-color .4s var(--ease), color .4s var(--ease);
}
.pill input:checked + span { border-color: var(--fg); color: var(--fg); }
.pill input:focus-visible + span { outline: 2px solid var(--fg); outline-offset: 2px; }

.qty { display: inline-flex; align-items: stretch; border: 1px solid var(--rule); align-self: flex-start; }
.qty__btn {
  width: 2.1rem;
  display: flex; align-items: center; justify-content: center;
  background: transparent; border: 0; color: var(--fg);
  font-family: var(--sans); font-size: var(--step-0); line-height: 1;
  cursor: pointer;
  transition: background-color .4s var(--ease);
}
.qty__btn:hover { background: color-mix(in srgb, var(--fg) 8%, transparent); }
.qty__n {
  width: 2.6rem; text-align: center;
  background: transparent; border: 0;
  border-left: 1px solid var(--rule); border-right: 1px solid var(--rule);
  font-family: var(--serif); font-size: var(--step-0); font-weight: 300; color: var(--fg);
  appearance: textfield;
}
.qty__n::-webkit-outer-spin-button, .qty__n::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.qty__n:focus { outline: none; }

/* ---------- pop-up form ----------
   A form section marked as a pop-up. Note there is no .rv inside: a closed
   <dialog> never intersects the viewport, so the reveal observer would never
   fire and the panel would open invisible. */

.modal {
  /* the UA stylesheet centres dialogs with auto margins and caps their size;
     both are restated here so the panel is predictable on small screens */
  width: min(46rem, calc(100vw - 2 * var(--gut)));
  max-width: none;
  max-height: calc(100dvh - 2rem);
  margin: auto;
  padding: 0;
  border: 0;
  background: var(--bg);
  color: var(--fg);
  overflow: hidden;
}
/* The page behind the dialog must not scroll with it. Keyed off the open
   attribute rather than a class the JS adds and removes: Esc closes a dialog
   natively, and a lock that depends on catching that event leaves the page
   unscrollable for good if it is ever missed. */
html:has(dialog.modal[open]) { overflow: hidden; }

.modal::backdrop {
  background: color-mix(in srgb, var(--ink) 62%, transparent);
  backdrop-filter: blur(3px);
}
.modal[open] { animation: modal-in .5s var(--ease) both; }
.modal[open]::backdrop { animation: modal-fade .5s var(--ease) both; }
@keyframes modal-in   { from { opacity: 0; transform: translateY(14px); } }
@keyframes modal-fade { from { opacity: 0; } }

.modal__panel {
  /* the panel scrolls, not the page behind it — a tall form on a short phone
     is the normal case, not the exception */
  max-height: calc(100dvh - 2rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: clamp(1.8rem, 5vw, 3.2rem);
  display: grid;
  gap: 1.1rem;
}
.modal__title {
  font-family: var(--serif); font-weight: 300;
  font-size: var(--step-2); line-height: 1.05;
  margin: 0; text-wrap: balance;
}
.modal__body { color: var(--muted); margin: 0; max-width: 46ch; }
.modal__panel .form { margin-top: .6rem; }

.modal__close {
  position: sticky; top: 0;
  justify-self: end;
  /* pulled back over the panel padding so it sits in the corner without
     reserving a row of its own in the grid */
  margin: calc(-1 * clamp(.4rem, 2vw, 1.2rem)) calc(-1 * clamp(.4rem, 2vw, 1.2rem)) 0 0;
  width: 2.4rem; height: 2.4rem;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg); border: 1px solid var(--rule); border-radius: 50%;
  color: var(--fg); cursor: pointer;
  transition: border-color .4s var(--ease), transform .4s var(--ease);
  z-index: 1;
}
.modal__close:hover { border-color: var(--fg); transform: rotate(90deg); }
.modal__close:focus-visible { outline: 2px solid var(--fg); outline-offset: 2px; }

/* ---------- footer ---------- */

.foot {
  background: var(--ink); color: var(--bone);
  padding: clamp(3.5rem, 9vh, 7rem) var(--gut) clamp(1.6rem, 4vh, 2.6rem);
}
.foot__top {
  display: grid; gap: clamp(2rem, 5vw, 4rem);
  max-width: 100rem; margin-inline: auto;
  padding-bottom: clamp(2.5rem, 6vh, 5rem);
}
@media (min-width: 800px) { .foot__top { grid-template-columns: 1.4fr 1fr 1fr; } }
.foot__logo { width: clamp(10rem, 18vw, 16rem); margin-bottom: 1.4rem; }
.foot h3 {
  font-family: var(--sans); font-size: var(--step--1); font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase;
  color: rgba(242,238,230,.55); margin: 0 0 1rem;
}
.foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .55rem; }
.foot a:hover { color: var(--accent); }
.foot__bottom {
  border-top: 1px solid rgba(242,238,230,.16);
  padding-top: 1.6rem;
  max-width: 100rem; margin-inline: auto;
  display: flex; flex-wrap: wrap; gap: .6rem 1.5rem; justify-content: space-between;
  font-family: var(--sans); font-size: var(--step--1);
  letter-spacing: .14em; text-transform: uppercase;
  color: rgba(242,238,230,.5);
}

/* ---------- next-branch link ---------- */

.crossover {
  position: relative;
  display: block;
  min-height: clamp(20rem, 46svh, 34rem);
  display: flex; align-items: center; justify-content: center;
  overflow: hidden;
  color: var(--bone);
  text-align: center;
}
.crossover__media { position: absolute; inset: 0; }
.crossover__media img { width: 100%; height: 100%; object-fit: cover; transform: scale(1.03); transition: transform 1.6s var(--ease); }
.crossover::after { content: ''; position: absolute; inset: 0; background: rgba(12,11,8,.55); transition: background-color .9s var(--ease); }
.crossover:hover .crossover__media img { transform: scale(1.09); }
.crossover:hover::after { background: rgba(12,11,8,.42); }
.crossover__inner { position: relative; z-index: 2; padding: var(--gut); }
.crossover__title {
  font-size: var(--step-3); font-weight: 300;
  font-variation-settings: var(--display-vf);
  line-height: .98; letter-spacing: -.02em; margin: .4rem 0 0;
}
.crossover .eyebrow { color: rgba(242,238,230,.7); }
.crossover__cta {
  display: inline-flex; align-items: center; gap: .7rem;
  margin-top: 1.4rem;
  font-family: var(--sans); font-size: var(--step--1); font-weight: 500;
  letter-spacing: .2em; text-transform: uppercase;
}
.crossover__cta svg { transition: transform .7s var(--ease); }
.crossover:hover .crossover__cta svg { transform: translateX(6px); }

/* ---------- misc ---------- */

.skip {
  position: absolute; left: -9999px;
  background: var(--fg); color: var(--bg); padding: .8rem 1.2rem; z-index: 100;
  font-family: var(--sans); font-size: var(--step--1); letter-spacing: .12em; text-transform: uppercase;
}
.skip:focus { left: var(--gut); top: 1rem; }

/* ==========================================================================
   ANNOUNCEMENT BAR
   Optional site-wide notice, switched on from the editor. Fixed above the
   header, which shifts down by its height so the two never overlap.
   ========================================================================== */

.announce {
  position: fixed; top: 0; left: 0; right: 0; z-index: 70;
  background: var(--ink);
  color: var(--bone);
  text-align: center;
  padding: .6rem var(--gut);
}
.announce p {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--step--1);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(242,238,230,.86);
}
.announce a {
  border-bottom: 1px solid rgba(242,238,230,.45);
  padding-bottom: 1px;
  transition: border-color .5s var(--ease);
}
.announce a:hover { border-bottom-color: var(--bone); }

/* push the fixed site header below the bar when one is showing */
body:has(.announce) .head { top: 2.4rem; }
body:has(.announce) .gate__head { top: 2.4rem; }

/* ==========================================================================
   GALLERY ARRANGEMENTS
   The editorial grid above stays the default; these are the uniform options.
   ========================================================================== */

.gal { max-width: 100rem; margin-inline: auto; }
.gal figure { margin: 0; }

.gal--gap-tight  { --gal-gap: clamp(.25rem, .5vw, .5rem); }
.gal--gap-normal { --gal-gap: clamp(.6rem, 1.6vw, 1.6rem); }
.gal--gap-roomy  { --gal-gap: clamp(1.2rem, 3.4vw, 3.4rem); }

/* even columns, every photo cropped to the same shape */
.gal--grid {
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
  gap: var(--gal-gap);
}

/* natural heights, flowing down columns */
.gal--masonry {
  column-count: var(--cols, 3);
  column-gap: var(--gal-gap);
}
.gal--masonry figure { break-inside: avoid; margin-bottom: var(--gal-gap); }

/* one per row, full width */
.gal--stack { display: grid; gap: var(--gal-gap); }

@media (max-width: 900px) {
  .gal--grid { grid-template-columns: repeat(min(var(--cols, 3), 2), minmax(0, 1fr)); }
  .gal--masonry { column-count: min(var(--cols, 3), 2); }
}
@media (max-width: 560px) {
  .gal--grid { grid-template-columns: 1fr; }
  .gal--masonry { column-count: 1; }
}

/* ==========================================================================
   MAINTENANCE / UNDER CONSTRUCTION
   Shown in place of every page while the site is switched off in the editor.
   ========================================================================== */

.maint {
  position: relative;
  min-height: 100svh;
  display: grid;
  place-items: center;
  text-align: center;
  padding: var(--gut);
  background: var(--ink);
  color: var(--bone);
  overflow: hidden;
}
.maint__media { position: absolute; inset: 0; z-index: 0; }
.maint__media .ph { height: 100%; }
.maint__media img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.7); }
.maint__media::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(12,11,8,.92), rgba(12,11,8,.74) 55%, rgba(12,11,8,.82));
}
.maint__inner {
  position: relative; z-index: 1;
  max-width: 34rem;
  display: grid;
  justify-items: center;
  gap: 0;
  animation: fadeUp 1.4s var(--ease) .2s both;
}
.maint__logo {
  width: clamp(11rem, 26vw, 18rem);
  margin-bottom: clamp(2rem, 6vh, 3.5rem);
}
.maint__title {
  font-family: var(--serif);
  font-size: var(--step-3);
  font-weight: 300;
  font-variation-settings: var(--display-vf);
  line-height: 1;
  letter-spacing: -.025em;
  margin: 0 0 clamp(.9rem, 2.4vh, 1.4rem);
}
.maint__msg {
  margin: 0;
  font-size: var(--step-1);
  font-weight: 300;
  line-height: 1.5;
  color: rgba(242,238,230,.8);
  text-wrap: pretty;
}
.maint__mail {
  display: inline-block;
  margin-top: clamp(1.6rem, 4vh, 2.4rem);
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding-bottom: .35rem;
  border-bottom: 1px solid rgba(242,238,230,.45);
  transition: border-color .5s var(--ease);
}
.maint__mail:hover { border-bottom-color: var(--bone); }

/* the way back, on the 404 page — same visual language as .maint__mail */
.notfound__nav {
  list-style: none;
  margin: clamp(1.6rem, 4vh, 2.4rem) 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.4rem;
}
.notfound__nav a {
  font-family: var(--sans);
  font-size: var(--step--1);
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  padding-bottom: .35rem;
  border-bottom: 1px solid rgba(242,238,230,.45);
  transition: border-color .5s var(--ease);
}
.notfound__nav a:hover { border-bottom-color: var(--bone); }
.maint__place {
  margin: clamp(2.4rem, 7vh, 4rem) 0 0;
  font-family: var(--sans);
  font-size: var(--step--1);
  letter-spacing: .18em;
  text-transform: uppercase;
  color: rgba(242,238,230,.45);
}

/* honeypot — offscreen rather than display:none, which some bots skip */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.cf-turnstile { margin: .4rem 0; }
.form-status { margin-top: .2rem; }
.form-status.is-bad { color: var(--accent); }
