/* ============================================================================
   template.css — structure and components. Client-agnostic.
   Reads every value from tokens.css. You should not need to edit this file
   to re-skin the template.
   ========================================================================== */

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

html {
  /* ref: html { font-size: 62.5% } -> 1rem = 10px. NOT a fluid vw root. */
  font-size: 62.5%;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: auto;
}

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-text);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  letter-spacing: var(--ls);
  text-transform: uppercase;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overscroll-behavior-y: none;
}

img,
picture,
video,
canvas,
svg { display: block; max-width: 100%; }

img { height: auto; }

button,
input,
textarea,
select { font: inherit; letter-spacing: inherit; color: inherit; }

a { color: inherit; text-decoration: none; }

h1, h2, h3, h4, h5, h6, p, blockquote, figure, ul, ol { margin: 0; padding: 0; }
ul, ol { list-style: none; }

[hidden] { display: none !important; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.sr-only--focusable:focus {
  position: fixed; top: 1rem; left: 1rem;
  width: auto; height: auto;
  clip-path: none;
  padding: 1rem 1.6rem;
  background: var(--c-accent);
  color: var(--c-black);
  z-index: 999;
}

:focus-visible {
  outline: 1px solid var(--c-accent);
  outline-offset: 3px;
}

/* --------------------------------------------------------- leading-trim
   Trims a line box down to the cap height, so display type can be aligned
   optically instead of by its (font-dependent) line box.
   ref implementation, reproduced verbatim:
     :before margin-bottom: calc((var(--lh) - 1em) / -2 + var(--fos))
     :after  margin-top:    calc((var(--lh) - 1em) / -2 + var(--foe))
   --fos / --foe are per-font vertical metrics from tokens.css.            */
.leading-trim::before,
.leading-trim::after {
  content: '';
  display: block;
  height: 0;
  overflow: hidden;
}
.leading-trim::before { margin-bottom: calc((var(--lh, 1) * 1em - 1em) / -2 + var(--fos, 0em)); }
.leading-trim::after { margin-top: calc((var(--lh, 1) * 1em - 1em) / -2 + var(--foe, 0em)); }
.leading-trim--block { display: block; }

/* ------------------------------------------------------------------ type */
.h1, .h2, .h3, .h4 {
  font-family: var(--font-display);
  font-weight: 200;
  color: var(--c-title);
  text-transform: uppercase;
  letter-spacing: var(--ls);
  /* letter-spacing also appends a phantom space after the LAST glyph, which
     pushes centred display type off-centre. Cancel it. */
  margin-right: calc(var(--ls) * -1);
  --fos: var(--display-fos);
  --foe: var(--display-foe);
}
.h1 { font-size: var(--fs-d1); line-height: var(--lh-d1); --lh: var(--lh-d1); }
.h2 { font-size: var(--fs-d2); line-height: var(--lh-d2); --lh: var(--lh-d2); }
.h3 { font-size: var(--fs-d3); line-height: var(--lh-d3); --lh: var(--lh-d3); }
.h4 { font-size: var(--fs-d4); line-height: var(--lh-d4); --lh: var(--lh-d4); }

.body-text {
  --lh: var(--lh-body);
  --fos: var(--text-fos);
  --foe: var(--text-foe);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  max-width: 46ch;
}
.text-small { font-size: var(--fs-small); }

/* Reading text in sentence case. The house style is uppercase everywhere
   (set on body); long-form copy reads more easily without it. Headings,
   labels, nav and buttons keep the uppercase. Delete this block to revert. */
.body-text,
.hero__tagline,
.intro__quote p,
.quotes__item p,
.services__desc,
.statement__copy {
  text-transform: none;
  letter-spacing: 0.01em;
}
/* body copy is 16px everywhere (client request); these two used the label size */
/* html-prefixed so it outranks the component rules further down the file */
html .services__desc,
html .statement__copy { font-size: var(--fs-body); line-height: 1.5; }
.text-accent { color: var(--c-accent); }
.text-white { color: var(--c-white); }
.text-center { text-align: center; }

/* ------------------------------------------------------------------ grid
   12 / 8 / 6 columns, zero gutter, edge to edge. Composition comes from
   column offsets, not from a page gutter — the reference has no gutter.  */
.section {
  position: relative;
  width: 100%;
  /* A title waiting to reveal sits at scale(1.35). On a full-width wrapper
     that pushes ~17% past the viewport on each side and produces REAL
     horizontal scroll (worst at short landscape sizes).
     overflow-x: clip contains it WITHOUT creating a scroll container, so
     position: sticky inside still works. overflow: hidden would break it —
     see the pitfalls note in the README. */
  overflow-x: clip;
}
.section--clip { overflow: hidden; }

.row {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: 0 var(--grid-gutter);
  width: 100%;
}

/* span helpers: .col-1 .. .col-12 (capped by the active column count) */
.col-1 { grid-column: span 1; } .col-2 { grid-column: span 2; }
.col-3 { grid-column: span 3; } .col-4 { grid-column: span 4; }
.col-5 { grid-column: span 5; } .col-6 { grid-column: span 6; }
.col-7 { grid-column: span 7; } .col-8 { grid-column: span 8; }
.col-9 { grid-column: span 9; } .col-10 { grid-column: span 10; }
.col-11 { grid-column: span 11; } .col-12 { grid-column: span 12; }

.start-2 { grid-column-start: 2; } .start-3 { grid-column-start: 3; }
.start-4 { grid-column-start: 4; } .start-5 { grid-column-start: 5; }
.start-6 { grid-column-start: 6; } .start-7 { grid-column-start: 7; }
.start-8 { grid-column-start: 8; }

/* ref: .title-offset { margin-left: var(--grid-col) } with .5 step modifiers */
.title-offset { margin-left: var(--grid-col); }
.title-offset--0\.5 { margin-left: calc(var(--grid-col) * 0.5); }
.title-offset--1 { margin-left: calc(var(--grid-col) * 1); }
.title-offset--1\.5 { margin-left: calc(var(--grid-col) * 1.5); }
.title-offset--2 { margin-left: calc(var(--grid-col) * 2); }
.title-offset--2\.5 { margin-left: calc(var(--grid-col) * 2.5); }
.title-offset--3 { margin-left: calc(var(--grid-col) * 3); }
.title-offset--3\.5 { margin-left: calc(var(--grid-col) * 3.5); }
.title-offset--4 { margin-left: calc(var(--grid-col) * 4); }

/* split-line heading: each line its own colour + indent (ref signature).
   leading-trim removes the line box's natural descender space, so a heading
   needs explicit separation from whatever follows it. */
.title-lines { display: block; width: fit-content; margin-bottom: var(--sp-2); }
.title-lines__line { display: block; }
.title-lines__line--accent { color: var(--c-accent); }
.title-lines__line--white { color: var(--c-white); }

/* --------------------------------------------------------------- buttons
   ref: large SQUARE outline buttons (180px in the hero, 240px in the intro)
   with two stacked SVG rects. The second rect draws itself on hover by
   animating stroke-dashoffset. The label/icon is duplicated and rolls up.  */
.btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  font-family: var(--font-text);
  font-size: var(--fs-btn);
  line-height: var(--lh-btn);
  letter-spacing: var(--ls);
  text-transform: uppercase;
  color: var(--c-white);
  background: none;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  /* touch target floor — applies on every device, costs nothing on desktop */
  min-width: 44px;
  min-height: 44px;
}

.btn__outline {
  position: absolute;
  inset: 0;
  /* An <svg> with no viewBox is a replaced element with an intrinsic 300x150
     size, and `inset: 0` does NOT override that while width/height are auto —
     the outline renders 150px tall regardless of the button. Set both. */
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.btn__outline rect {
  fill: none;
  stroke: var(--c-accent);
  stroke-width: 1;
  width: calc(100% - 2px);
  height: calc(100% - 2px);
  x: 1px;
  y: 1px;
  vector-effect: non-scaling-stroke;
}
/* resting outline */
.btn__outline rect:first-child { stroke: var(--c-white-20); }
/* drawing outline — dash length is set from JS once the box is measured */
.btn__outline rect + rect {
  stroke: var(--c-accent);
  stroke-dasharray: var(--path-length, 1000px);
  stroke-dashoffset: var(--path-length, 1000px);
  transition: stroke-dashoffset var(--d-slow) var(--e-out);
}
.has-hover .btn:hover .btn__outline rect + rect,
.btn.is-active .btn__outline rect + rect,
.btn:focus-visible .btn__outline rect + rect { stroke-dashoffset: 0; }

/* label / icon roll — ref: two stacked clones, the second offset below */
.btn__content {
  position: relative;
  display: block;
  overflow: hidden;
  line-height: var(--lh-btn);
}
.btn__label {
  display: block;
  transition: transform var(--d-slow) var(--e-out);
}
.btn__label--clone {
  position: absolute;
  inset: 0;
  transform: translateY(100%);
}
.has-hover .btn:hover .btn__label { transform: translateY(-100%); }
.has-hover .btn:hover .btn__label--clone { transform: translateY(0); }

.btn--square {
  width: var(--btn-size, 18rem);
  height: var(--btn-size, 18rem);
  flex-direction: column;
}
.btn--square-lg { --btn-size: 24rem; }

.btn--inline {
  padding: 1.4rem 2.4rem;
  min-height: 44px;
}

.btn__icon {
  display: block;
  width: 3rem;
  height: 3rem;
  stroke: currentColor;
  fill: none;
}

/* ---------------------------------------------------------------- header */
.header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: var(--z-header);
  min-height: var(--header-h);
  display: grid;
  /* AR&C: brand LEFT, nav right (two tracks). The previous client centred the
     lockup between a meta column and the nav; this brand reads better ranged
     left and the meta column is gone. */
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  padding: 2.4rem var(--sp-1) 1.2rem;   /* breathing room above the logo */
  border-bottom: 1px solid transparent;
  transition: min-height var(--d-slow) var(--e-out), background-color var(--d-base) var(--e-out), padding var(--d-slow) var(--e-out), border-color var(--d-base) var(--e-out), backdrop-filter var(--d-base) var(--e-out);
}
/* Frosted glass once the page scrolls: the content blurs through a dark tint,
   with a hairline underneath, so the nav stays readable over titles and video.
   The tint alone (no blur) is the fallback where backdrop-filter is missing. */
.is-scrolled .header {
  padding-top: 1.2rem;
  background-color: rgb(0 0 0 / 0.72);
  border-bottom-color: var(--c-white-20);
}
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .is-scrolled .header {
    background-color: rgb(0 0 0 / 0.42);
    -webkit-backdrop-filter: blur(18px) saturate(140%);
            backdrop-filter: blur(18px) saturate(140%);
  }
}
/* Brand lockup: monogram over wordmark, centred. Once the page scrolls the
   wordmark collapses away and only the mark is left, so the header stays out
   of the way of the content. */
/* AR&C lockup: the mark sits directly above the wordmark and BOTH ARE THE SAME
   WIDTH. One container width drives both (each image is width:100%), which is
   the only way to keep them flush as the mark shrinks on scroll.
   The wordmark is stacked onto two lines to get there: as the single line it is
   drawn, "AGRIVENTURES CORPORATION" is 22.6:1, so matching the mark's 150px
   would leave it 7px tall. Two lines make it 4:1, which lands at ~18px a line. */
.header__brand {
  grid-column: 1;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 0.7rem;
  width: 10.5rem;              /* client asked for ~30% smaller on desktop */
  min-height: 44px;
  transition: width var(--d-slow) var(--e-out);
}
.is-scrolled .header__brand { width: 6.6rem; }
.header__mark {
  width: 100%;
  height: auto;
  transition: height var(--d-slow) var(--e-out);
}
.header__wordmark {
  width: 100%;
  height: auto;
  opacity: 1;
  transition:
    opacity var(--d-base) var(--e-out),
    margin var(--d-slow) var(--e-out);
}
/* Scrolled: the container narrows (above) and the wordmark fades out, leaving
   just the mark. The wordmark's row also collapses to zero (grid 1fr -> 0fr,
   with the flex gap cancelled), otherwise its invisible box keeps pushing the
   mark ~11px above the header's centre line. */
.header__wordmark-wrap {
  display: grid;
  grid-template-rows: 1fr;
  overflow: hidden;
  transition: grid-template-rows var(--d-slow) var(--e-out), margin var(--d-slow) var(--e-out);
}
.header__wordmark-wrap > * { min-height: 0; }
/* scrolledHeaderHeight() in app.js measures the compact header synchronously */
.header-measuring .header,
.header-measuring .header * { transition: none !important; }
.is-scrolled .header__wordmark-wrap {
  grid-template-rows: 0fr;
  margin-top: -0.7rem;
}
.is-scrolled .header__wordmark {
  opacity: 0;
  pointer-events: none;
}
.header__nav {
  grid-column: 2;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--sp-2);
}
/* --------------------------------------------------- Call / Text action pair
   ONE component, TWO homes: the desktop header nav and the phone's sticky
   bottom bar (app.js actionPair()). Call is filled and carries the number on
   its face, because AR&C takes orders by phone — the number is the call to
   action, not a detail below one. Text is the outlined partner.
   The previous client had a single solid "Book" pill here.                  */
.act {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.7rem;
  min-height: 44px;
  padding: 0 1.4rem;
  border: 1px solid var(--c-accent);
  border-radius: 0;
  font-size: 1.25rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  overflow: hidden;
  isolation: isolate;
  -webkit-tap-highlight-color: transparent;
  transition: background-color var(--d-base) var(--e-out), color var(--d-base) var(--e-out),
    transform var(--d-base) var(--e-out);
}
.act svg { width: 16px; height: 16px; flex: 0 0 auto; }
.act__num {
  font-size: 1.4rem;
  letter-spacing: 0.04em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.act--call {
  background: var(--c-accent);
  color: #000;
  animation: cta-glow 2.8s ease-in-out infinite;
}
/* hairline between the word and the number */
.act--call .act__label { padding-right: 0.7rem; border-right: 1px solid var(--c-black-30); }
.act--call::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  left: -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgb(255 255 255 / 0.5), transparent);
  transform: skewX(-20deg);
  animation: cta-shine 3.2s ease-in-out infinite;
  z-index: -1;
}
.act--text { background: transparent; color: var(--c-accent); }
.has-hover .act--call:hover { background: var(--c-accent-light); transform: translateY(-1px); }
.has-hover .act--text:hover { background: var(--c-accent); color: #000; }
.act--call:active { background: var(--c-accent-light); }
.act--text:active { background: var(--c-accent); color: #000; }
.act:focus-visible { outline: 1px solid var(--c-white); outline-offset: 3px; }

.header__actions { display: inline-flex; align-items: center; gap: 8px; }

/* -------------------------------------------------------- "coming soon" tag
   A nav entry with no href yet. app.js renders it as a <span>, not an <a>, so
   it cannot be tapped through to nowhere, and hangs a speech-bubble beside the
   label. Sized in rem, not em: the header nav sets 10px labels, so an em-based
   bubble would come out at about 4px.                                       */
.header__link--soon,
.menu__link--soon {
  display: inline-flex;
  align-items: center;
  gap: 1rem;
  cursor: default;
  color: var(--c-white-56);
}
.soon {
  position: relative;
  font-style: normal;
  font-size: 1rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--c-accent);
  background: var(--c-accent-20);
  border: 1px solid var(--c-accent-40);
  border-radius: 999px;
  padding: 0.45em 0.9em;
  line-height: 1.2;
  animation: soon-pulse 2.8s ease-in-out infinite;
}
/* the bubble's little tail, pointing back at the label */
.soon::before {
  content: '';
  position: absolute;
  left: -4px;
  top: 50%;
  width: 7px;
  height: 7px;
  transform: translateY(-50%) rotate(45deg);
  background: var(--c-accent-20);
  border-left: 1px solid var(--c-accent-40);
  border-bottom: 1px solid var(--c-accent-40);
}
@keyframes soon-pulse {
  0%, 100% { opacity: 0.7; }
  50% { opacity: 1; }
}
.menu__link--soon .soon { font-size: 1.3rem; }
@media (prefers-reduced-motion: reduce) {
  .soon { animation: none; opacity: 1; }
}


/* ------------------------------------------------------------- brand gleam
   The same sweep the Call button runs (cta-shine), applied to the ARC MARK
   ONLY at the client's request — the wordmark below it stays still. The
   wrapper is MASKED with the mark's own PNG, so the highlight travels across
   the letterforms and the fish instead of sweeping a rectangle over them.
   Only rendered where mask-image is supported — without it the gleam would be
   a plain white bar crossing the header.                                    */
/* plain wrapper: the wordmark carries no gleam. Its display:grid (the scroll
   collapse) is set with the scrolled rules above — don't reset it here. */
.header__wordmark-wrap { width: 100%; }

.brandshine {
  position: relative;
  display: block;
  width: 100%;
  -webkit-mask-image: var(--logo-mask);
          mask-image: var(--logo-mask);
  -webkit-mask-size: 100% 100%;
          mask-size: 100% 100%;
  -webkit-mask-repeat: no-repeat;
          mask-repeat: no-repeat;
}

@supports ((mask-image: linear-gradient(#000, #000)) or (-webkit-mask-image: linear-gradient(#000, #000))) {
  .brandshine::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: -60%;
    width: 55%;
    /* a touch stronger and wider than the button's sweep: the logo is small,
       and the gleam has to read across thin letterforms rather than a slab */
    background: linear-gradient(100deg, transparent, rgb(255 255 255 / 0.92), transparent);
    transform: skewX(-20deg);
    animation: cta-shine 3.2s ease-in-out infinite;
    pointer-events: none;
  }
}

@keyframes cta-shine {
  0%, 55% { left: -60%; }
  100% { left: 130%; }
}
/* soft blurred glow — a hard spread ring read as a dark box over photos */
@keyframes cta-glow {
  0%, 100% { box-shadow: 0 0 6px 0 var(--c-accent-25); }
  50% { box-shadow: 0 0 22px 2px var(--c-accent-60); }
}
@keyframes cta-nudge {
  0%, 100% { transform: translateX(0); }
  50% { transform: translateX(4px); }
}
@media (prefers-reduced-motion: reduce) {
  .act, .act::before, .act svg { animation: none; }
  .brandshine::after { animation: none; opacity: 0; }
}

/* Kept for templates that still set header.meta; AR&C does not render one. */
.header__meta {
  grid-column: 1;
  font-size: var(--fs-small);
  color: var(--c-accent);
}
.header__link {
  font-size: var(--fs-small);
  color: var(--c-white);
  position: relative;
  padding: 1rem 0;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
}
.header__link::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0.6rem;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--d-base) var(--e-out);
}
.has-hover .header__link:hover::after { transform: scaleX(1); }

/* burger — phone only */
.header__burger {
  display: none;
  width: 44px; height: 44px;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  cursor: pointer;
}
.header__burger span {
  display: block;
  width: 22px; height: 1px;
  background: var(--c-white);
  position: relative;
  transition: background var(--d-base) var(--e-out);
}
.header__burger span::before,
.header__burger span::after {
  content: '';
  position: absolute;
  left: 0; width: 22px; height: 1px;
  background: var(--c-white);
  transition: transform var(--d-base) var(--e-out);
}
.header__burger span::before { top: -6px; }
.header__burger span::after { top: 6px; }
/* nav doesn't fit beside the logo (narrow desktop, browser zoom, large
   default font): fall back to the burger at ANY width */
/* "Tilapia tools" beside the burger — only when the nav has collapsed */
.header__tools { display: none; }
.header--compact .header__tools {
  display: inline-flex; grid-column: 2; justify-self: end; margin-right: 8px;
}
.header__tools {
  align-items: center; min-height: 40px; padding: 0 1.2rem;
  border: 1px solid var(--c-accent); color: var(--c-accent);
  font-size: 1.2rem; font-weight: 500; letter-spacing: 0.1em; text-transform: uppercase; white-space: nowrap;
  transition: background-color var(--d-base) var(--e-out), color var(--d-base) var(--e-out);
}
.header__tools:active { background: var(--c-accent); color: #000; }
.has-hover .header__tools:hover { background: var(--c-accent); color: #000; }
/* Same motion language as the Call button: a soft pulsing glow plus the
   diagonal shimmer (cta-glow / cta-shine), tinted blue for an outline button. */
.header__tools {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  animation: cta-glow 2.8s ease-in-out infinite;
}
.header__tools::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  left: -60%;
  width: 45%;
  background: linear-gradient(100deg, transparent, rgb(111 195 228 / 0.45), transparent);
  transform: skewX(-20deg);
  animation: cta-shine 3.2s ease-in-out infinite;
  z-index: -1;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .header__tools, .header__tools::before { animation: none; }
}
.header--compact .header__nav { display: none; }
.header--compact .header__burger { display: flex; grid-column: 3; justify-self: end; }
.is-menu-open .header__burger span { background: transparent; }
.is-menu-open .header__burger span::before { transform: translateY(6px) rotate(45deg); }
.is-menu-open .header__burger span::after { transform: translateY(-6px) rotate(-45deg); }

/* full-screen menu (phone / tablet) */
.menu {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--c-ink);
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: 0 var(--sp-2) calc(var(--sp-3) + env(safe-area-inset-bottom, 0px));
  /* it now carries nav + contact + actions, so it must be able to scroll */
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  transform: translateY(-100%);
  visibility: hidden;
  transition: transform var(--d-slow) var(--e-in-out), visibility 0s linear var(--d-slow);
}
.is-menu-open .menu {
  transform: translateY(0);
  visibility: visible;
  transition: transform var(--d-slow) var(--e-in-out), visibility 0s;
}

/* top bar: brand + the menu's own close control. The menu sits ABOVE the
   header, so the burger underneath cannot be reached while it is open. */
.menu__top {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  min-height: var(--header-h);
  margin: 0 calc(var(--sp-2) * -1);
  padding: 0 var(--sp-2);
  background: var(--c-ink);
  border-bottom: 1px solid var(--c-rule);
}
.menu__brand {
  display: flex;
  align-items: center;
  min-width: 44px;
  min-height: 44px;
}
.menu__brand img { height: 3.6rem; width: auto; }
.menu__close {
  width: 44px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  border-radius: 0;
  color: var(--c-white);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  box-shadow: inset 0 0 0 1px var(--c-white-20);
  transition: color var(--d-base) var(--e-out), box-shadow var(--d-base) var(--e-out);
}
.menu__close svg { width: 18px; height: 18px; }
.has-hover .menu__close:hover,
.menu__close:focus-visible { color: var(--c-accent); box-shadow: inset 0 0 0 1px var(--c-accent); }

.menu__nav { display: block; padding-top: var(--sp-1); }
.menu__link {
  display: block;
  font-family: var(--font-display);
  font-weight: 200;
  font-size: var(--fs-d4);
  line-height: 1.1;
  color: var(--c-accent);
  padding: 0.8rem 0;
  min-height: 48px;
}

/* contact block — same row anatomy as the contact section */
.menu__heading {
  color: var(--c-accent);
  padding-bottom: var(--sp-1);
  border-bottom: 1px solid var(--c-rule);
}
.menu__details { display: block; }
.menu__row {
  display: grid;
  grid-template-columns: 40px 1fr;
  align-items: center;
  gap: var(--sp-1);
  padding: 1.2rem 0;
  border-bottom: 1px solid var(--c-rule);
}
.menu__text { display: grid; gap: 0.2rem; min-width: 0; }
.menu__label { color: var(--c-accent); }
.menu__value {
  color: var(--c-white);
  display: flex;
  align-items: center;
  /* a tappable phone/social link must clear the 44px floor on its own */
  min-height: 44px;
  word-break: break-word;
}
a.menu__value { text-decoration: underline; text-underline-offset: 4px; text-decoration-thickness: 1px; }
.has-hover a.menu__value:hover { color: var(--c-accent); }
/* whole row is the tap target where there is a link */
.menu__row:has(a.menu__value) { min-height: 56px; }

.ico {
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  color: var(--c-accent);
  box-shadow: inset 0 0 0 1px var(--c-accent-20);
}
.ico svg { width: 18px; height: 18px; }

.menu__actions { display: grid; gap: var(--sp-1); padding-top: var(--sp-1); }
.menu__book { width: 100%; }
.menu__quick { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--sp-1); }
.menu__quick-btn { width: 100%; }

/* ------------------------------------------------------------------ hero
   ref: one viewport tall, centred, media overscanned to 111% of viewport. */
.hero {
  position: relative;
  /* min-height, not height: if the stack ever needs more room than one
     screen (short viewport), the hero grows instead of overlapping the logo */
  min-height: max(100svh, 520px);  /* svh, not vh — see README */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.hero__bg {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
}
/* Overscan written in vw so it stays a fraction of the VIEWPORT.
   ref: hero iframe 160rem wide on a 144rem viewport, full height.         */
.hero__media {
  position: absolute;
  top: 0;
  left: 50%;
  width: var(--overscan);
  /* the global img reset caps width at 100% — overscan must opt out */
  max-width: none;
  height: 100%;
  /* Centred with a margin offset, never with a CSS transform — a transform
     here would compound with the parallax transform and push it off centre. */
  margin-left: calc(var(--overscan) / -2);
  object-fit: cover;
  will-change: transform;
}
/* Scrim strength is a legibility requirement, not decoration: the display
   type is thin, light-weight and gold, and real client footage is rarely as
   dark as a design comp. A vertical wash plus a centre vignette keeps the
   title readable over any frame. Tune the alphas, not the type colour. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgb(0 0 0 / 0.72) 0%, rgb(0 0 0 / 0.42) 42%, rgb(0 0 0 / 0.82) 100%),
    radial-gradient(120% 78% at 50% 42%, rgb(0 0 0 / 0.1) 0%, rgb(0 0 0 / 0.6) 100%);
  z-index: 1;
}
/* The reference does NOT centre the hero stack — it places three bands at
   fixed fractions of the viewport height. Measured at 1440x900:
     title   y=298  -> 33.1%
     button  y=389  -> 43.2%   (overlaps the title's descender band)
     tagline y=689  -> 76.6%
   Reproduced as absolutely positioned rows. Each row centres its child with
   flexbox, never with a transform, so nothing compounds with the reveal
   transform on .animation--title.                                         */
.hero__inner {
  position: relative;
  flex: 1 0 auto;
  width: 100%;
  min-height: max(100svh, 520px);
  z-index: 2;
  text-align: center;
}
.hero__row {
  position: absolute;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
}
/* Title, CTA and tagline flow as ONE centred column with fixed gaps, so
   none of them can touch at any viewport height (the reference's fixed
   percentage bands overlapped). */
.hero__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  /* clear the full header (logo + wordmark), measured in app.js */
  padding: calc(var(--header-full, 13rem) + var(--sp-2)) var(--sp-2) var(--sp-3);
}
.hero__row { position: static; }
/* the scroll cue is a hint, not a feature — keep it small */
.hero__cta .btn { --btn-size: 8rem; }
.hero__row--main {
  flex-direction: column;
  align-items: center;
  gap: var(--sp-3);
}

.hero__title { color: var(--c-accent); }

/* ---- hero typography treatment ------------------------------------------
   kicker with hairlines / letter-by-letter title with a slow gold shine /
   drawn rule / tagline ending in a cycling gold word                      */
.hero__kicker {
  display: flex;
  align-items: center;
  gap: 1.6rem;
  margin-bottom: calc(var(--sp-2) * -1);   /* sit close over the title */
  font-size: var(--fs-small);
  letter-spacing: 0.32em;
  color: var(--c-accent-light);
}
.hero__kicker::before,
.hero__kicker::after {
  content: '';
  width: 4.8rem;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--c-accent));
}
.hero__kicker::after { transform: scaleX(-1); }

/* The shine is painted per letter (a parent background-clip:text would not
   paint through letters that are mid-transform). Every letter carries the
   same gradient offset by its index, and one animated length (--shine)
   slides the light band across all of them in step. */
@property --shine {
  syntax: '<length>';
  inherits: true;
  initial-value: 0em;
}
.hero__title {
  --shine: 0em;
  filter: drop-shadow(0 2px 24px rgb(0 0 0 / 0.35));
}
.hero__title.is-revealed { animation: hero-shine 6s ease-in-out 1.8s infinite; }
.hero__char,
.hero__space { display: inline-block; white-space: pre; }
.hero__char {
  background: linear-gradient(100deg,
    var(--c-accent) 0, var(--c-accent) 44%,
    var(--c-accent-shine) 50%,
    var(--c-accent) 56%, var(--c-accent) 100%);
  /* tiles: solid accent everywhere, one soft light band per 30em period —
     wider than the title, so only one band is ever on the letters */
  background-size: 30em 100%;
  background-repeat: repeat-x;
  background-position: calc(var(--shine) - var(--i, 0) * 0.5em) 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  opacity: 0;
  filter: blur(10px);
  transform: translateY(0.35em) scale(1.08);
  transition:
    opacity 0.9s var(--e-out),
    filter 0.9s var(--e-out),
    transform 1.1s var(--e-out);
  transition-delay: calc(var(--i, 0) * 55ms + 100ms);
}
.hero__title.is-revealed .hero__char { opacity: 1; filter: none; transform: none; }
@keyframes hero-shine {
  0% { --shine: 0em; }
  40%, 100% { --shine: -30em; }
}

.hero__rule {
  display: block;
  width: 12rem;
  height: 1px;
  margin-top: calc(var(--sp-1) * -1);
  background: linear-gradient(90deg, transparent, var(--c-accent), transparent);
  transform: scaleX(0);
  transition: transform 1.2s var(--e-out) 0.5s, opacity 0.4s var(--e-out);
}
.hero__rule.is-revealed { transform: scaleX(1); }

.hero__tagline--rotate { font-size: calc(var(--fs-body) * 1.15); }
.hero__words {
  display: inline-grid;
  vertical-align: bottom;
  overflow: hidden;
  text-align: left;
}
.hero__word {
  grid-area: 1 / 1;
  color: var(--c-accent-light);
  font-style: italic;
  opacity: 0;
  transform: translateY(100%);
  transition: transform 0.7s var(--e-out), opacity 0.5s var(--e-out);
}
.hero__word.is-active { opacity: 1; transform: none; }
.hero__word.is-leaving { opacity: 0; transform: translateY(-100%); }

@media (prefers-reduced-motion: reduce) {
  .hero__title.is-revealed { animation: none; }
  .hero__char { opacity: 1; filter: none; transform: none; transition: none; }
  .hero__rule { transform: none; }
}
@media (max-width: 667px) {
  .hero__kicker { letter-spacing: 0.14em; gap: 0.8rem; font-size: 1.1rem; white-space: nowrap; }
  .hero__kicker::before, .hero__kicker::after { width: 1.6rem; }
  .hero__tagline--rotate { font-size: var(--fs-body); max-width: 30ch; margin-inline: auto; }
}
.hero__tagline {
  font-size: var(--fs-body);   /* ref: .entrance__text is 13px */
  font-weight: 500;
  color: var(--c-white);
  line-height: 1.5;
}

/* ----------------------------------------------------------------- intro */
.intro { padding: var(--sp-4) 0; }
/* sp-2, not sp-3: the jar video starts near the top of its frame and the
   client wanted it close under the title */
.intro__head { position: relative; padding-bottom: var(--sp-2); }
.intro__kicker {
  font-size: var(--fs-small);
  color: var(--c-accent);
  margin-bottom: var(--sp-2);
  margin-left: calc(var(--grid-col) * 0.5);
}
.intro__body {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  align-items: start;
}
/* All three children share grid row 1 so the copy and the quote sit OVER
   the picture, as they do on the reference. Without an explicit grid-row
   auto-placement pushes the picture to a second row and the overlap is lost.
   ref geometry inside this block: picture y=180 / copy y=660 / quote y=1053. */
.intro__media {
  grid-column: 3 / span 8;
  grid-row: 1;
  align-self: start;
  position: relative;
  overflow: hidden;
  aspect-ratio: 96 / 132;     /* ref: 960x1320 picture box */
}
.intro__media img,
.intro__media video { display: block; width: 100%; height: 100%; object-fit: cover; will-change: transform; }
/* The jar clip is framed edge to edge (collar at the very top). The scroll
   zoom and reveal zoom both scale it up, which clipped the top of the jar —
   the client wants the whole jar visible, so this video never scales. */
.intro__media video { transform: none !important; object-position: 50% 0; }
/* ...and the box takes the clip's own 3:4 shape at every width (the photo
   box is 96:132), so object-fit:cover has nothing to trim on any side. */
.intro__media:has(video) { aspect-ratio: 3 / 4; }
/* The copy and the quote sit OVER this picture, so it needs a scrim — a
   bright client photograph (a white outfit, a pale studio wall) otherwise
   swallows the text completely. Weighted to the left and the bottom, where
   the copy, quote and stats actually land. Tune the alphas, not the type. */
.intro__media::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background:
    linear-gradient(180deg, rgb(0 0 0 / 0.3) 0%, rgb(0 0 0 / 0.22) 38%, rgb(0 0 0 / 0.88) 100%),
    linear-gradient(90deg, rgb(0 0 0 / 0.72) 0%, rgb(0 0 0 / 0.18) 42%, rgb(0 0 0 / 0.55) 100%);
}
.intro__copy {
  grid-column: 1 / span 4;
  grid-row: 1;
  align-self: start;
  z-index: 2;
  padding-left: calc(var(--grid-col) * 0.5);
  margin-top: 36rem;
}
/* the gold lead line needs air under it — leading-trim on the paragraph
   below removes the space it would otherwise inherit */
.intro__copy .text-small { display: block; margin-bottom: var(--sp-1); }
.intro__quote {
  grid-column: 7 / span 5;
  grid-row: 1;
  align-self: end;
  z-index: 2;
  padding-bottom: var(--sp-3);
}
.intro__quote p {
  font-size: var(--fs-quote);
  line-height: 1.45;
  color: var(--c-white);
  --lh: 1.45;
  --fos: var(--text-fos);
  --foe: var(--text-foe);
}
.intro__quote footer {
  margin-top: var(--sp-2);
  font-size: var(--fs-small);
  color: var(--c-accent);
}
.intro__btn { margin-top: var(--sp-3); }

/* --------------------------------------------------- pinned horizontal slider
   Desktop: the section is N viewports tall, an inner sticky pane holds the
   track, and the track translates on scroll progress (ref: .sticky-slider,
   5580px tall / 6.2 viewports at 1440).
   Phone: NOT pinned. Becomes a native scroll-snap swipe carousel — the page
   never freezes under the thumb. See README.                              */
.hslider { position: relative; }
.hslider__sticky {
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  display: flex;
  align-items: center;
}
.hslider__track {
  display: flex;
  height: 100%;
  align-items: center;
  will-change: transform;
}
.hslider__panel {
  flex: 0 0 var(--vw100);
  height: 100%;
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  /* one explicit row filling the pane; both children are placed into it and
     centred individually. Relying on auto-placement here lets the row size
     itself to the media and the copy drifts to the bottom of the viewport. */
  grid-template-rows: 100%;
  position: relative;
}
.hslider__panel-media {
  grid-row: 1;
  grid-column: 7 / span 5;
  align-self: center;
  justify-self: start;
  height: 68svh;
  width: auto;
  aspect-ratio: 96 / 132;
  overflow: hidden;
}
.hslider__panel-media img,
.hslider__panel-media video { display: block; width: 100%; height: 100%; object-fit: cover; will-change: transform; }
.hslider__panel-body {
  grid-row: 1;
  grid-column: 2 / span 4;
  align-self: center;
  z-index: 2;
}
.hslider__index {
  font-size: var(--fs-small);
  color: var(--c-accent);
  margin-bottom: var(--sp-2);
}
.hslider__panel-body p { margin-top: var(--sp-2); }
.hslider__progress {
  position: absolute;
  left: 0; right: 0; bottom: var(--sp-2);
  height: 1px;
  background: var(--c-white-20);
}
.hslider__progress span {
  display: block;
  height: 100%;
  background: var(--c-accent);
  transform-origin: left;
  transform: scaleX(var(--hs-progress, 0));
}

/* -------------------------------------------------------------- services */
.services { padding: var(--sp-4) 0; }
.services__list { border-top: 1px solid var(--c-rule); }
.services__item {
  position: relative;
  border-bottom: 1px solid var(--c-rule);
}
.services__link {
  display: grid;
  /* num | thumb | name | description | arrow */
  grid-template-columns: auto 104px 1fr minmax(0, 30ch) auto;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-1);
  min-height: 64px;
  transition: color var(--d-base) var(--e-out);
}
/* AR&C has no per-row photography, so the rows ship without thumbnails. The
   thumb column is a fixed track, not auto — leaving it in place with nothing
   in it shunts every other cell one column to the right. app.js sets this
   modifier when no item carries an `img`. */
.services__list--nothumb .services__link {
  grid-template-columns: auto 1fr minmax(0, 30ch) auto;
}

.services__thumb {
  display: block;
  width: 104px;
  height: 104px;
  overflow: hidden;
}
.services__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05);
  transform: scale(1.01);
  transition: filter var(--d-slow) var(--e-out), transform var(--d-slow) var(--e-out);
}
.has-hover .services__item:hover .services__thumb img {
  filter: grayscale(0) contrast(1);
  transform: scale(1.06);
}
.services__num { font-size: var(--fs-small); color: var(--c-accent); }
.services__name {
  font-family: var(--font-display);
  font-weight: 200;
  font-size: var(--fs-d4);
  line-height: 1;
  color: var(--c-white);
  --lh: 1;
  --fos: var(--display-fos);
  --foe: var(--display-foe);
  transition: color var(--d-base) var(--e-out), transform var(--d-slow) var(--e-out);
}
/* ref technique: hovering one row dims the others. Gated on real hover
   capability, never on width — touch devices keep every row at full
   strength and the description is shown inline instead.                   */
.has-hover .services__list:hover .services__item:not(:hover) .services__name { color: var(--c-white-56); }
.has-hover .services__item:hover .services__name { color: var(--c-accent); transform: translateX(var(--sp-1)); }
.services__desc {
  font-size: var(--fs-small);
  color: var(--c-white-56);
  max-width: 34ch;
}

/* --------------------------------------------------------------- gallery */
.gallery { padding: var(--sp-4) 0; }
.gallery__grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  align-items: start;
}
.gallery__card { position: relative; overflow: hidden; will-change: transform; }
.gallery__card img { width: 100%; height: auto; }
.gallery__card:nth-child(1) { grid-column: 2 / span 3; }
.gallery__card:nth-child(2) { grid-column: 6 / span 4; margin-top: var(--sp-4); }
.gallery__card:nth-child(3) { grid-column: 10 / span 2; margin-top: calc(var(--sp-4) * 2); }
.gallery__caption {
  margin-top: var(--sp-1);
  font-size: var(--fs-small);
  color: var(--c-white-56);
}

/* ----------------------------------------------------------- stats counters
   Values roll up from 0 when they enter view (data-counter in app.js).     */
.stats {
  display: flex;
  gap: var(--sp-4);
  margin-top: var(--sp-3);
  padding-top: var(--sp-2);
  border-top: 1px solid var(--c-rule);
}
.stats__item { display: grid; gap: 0.4rem; }
.stats__value {
  color: var(--c-accent);
  font-family: var(--font-display);
  font-weight: 200;
  line-height: 1;
  --lh: 1;
  --fos: var(--display-fos);
  --foe: var(--display-foe);
}
.stats__label { color: var(--c-white-56); }
/* Currency / plus sign ahead of a counter. Set in the text face at roughly
   half the numeral size and lifted to sit against the cap line, so a glyph the
   display face does not carry (₱) still reads as part of the figure. */
.stats__prefix {
  font-family: var(--font-text);
  font-size: 0.46em;
  font-weight: 400;
  letter-spacing: 0;
  margin-right: 0.08em;
  vertical-align: 0.34em;
  opacity: 0.85;
}

/* ------------------------------------------------------------------ impact
   ADDED FOR AR&C. A full-width band of four production counters. The intro
   blockquote's two-up .stats row could not carry four figures — and
   "₱151,200,000" alone is wider than that column — so the same markup is
   re-laid out here on the page grid.                                       */
.impact { padding: var(--sp-4) var(--sp-1); }
.impact__head { max-width: 62ch; }
.impact__kicker { color: var(--c-accent); margin-bottom: var(--sp-1); }
.impact__head p { margin-top: var(--sp-2); }
.stats--band {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--sp-2);
  margin-top: var(--sp-3);
  padding-top: var(--sp-3);
}
.stats--band .stats__item {
  gap: var(--sp-1);
  padding-left: var(--sp-1);
  border-left: 1px solid var(--c-rule);
}
.stats--band .stats__item:first-child { border-left: 0; padding-left: 0; }
.stats--band .stats__label { max-width: 22ch; }
/* These figures are the loudest thing on the page, so they are set a full step
   up from --fs-d4 to --fs-d3. The vw cap is what actually binds: the longest
   string is "30,000,000" at ten glyphs, and it has to clear its quarter-column
   (296px of usable width at 1440, ~190px at 980) without spilling. */
.stats--band .stats__value { font-size: min(var(--fs-d3), 6.6vw); }

/* Two-up from tablet down: four of these figures side by side stop fitting
   well before the 667px phone breakpoint. */
@media (max-width: 979px) {
  .stats--band { grid-template-columns: repeat(2, 1fr); gap: var(--sp-3) var(--sp-1); }
  .stats--band .stats__item:nth-child(odd) { border-left: 0; padding-left: 0; }
  .stats--band .stats__value { font-size: min(var(--fs-d2), 12vw); }
}
@media (max-width: 667px) {
  .impact { padding: var(--sp-3) var(--sp-2); }
}

/* ------------------------------------------------------------- credentials
   A heading and copy, a feature image, and a horizontal strip of photographs
   (AR&C: the five hatchery stages). The strip is a native scroll-snap
   carousel on EVERY viewport — a picture strip is naturally browsed sideways,
   and it needs no pin, no JS and no hover.                                  */
.creds { padding: var(--sp-4) var(--sp-1); }

/* feature image | heading + copy + index */
.creds__intro {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  align-items: center;
  margin-bottom: var(--sp-4);
}
/* AR&C: run wider (7 columns, was 6) and LANDSCAPE. The previous client's
   feature was a 3:4 studio portrait; this one is a 4:3 photograph of the fish,
   and a portrait frame cropped its head and tail off. */
.creds__feature { grid-column: 1 / span 7; margin: 0; }
.creds__feature-frame {
  overflow: hidden;
  border: 1px solid var(--c-accent-20);
  aspect-ratio: 4 / 3;
}
.creds__feature-frame img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 50%;   /* AR&C: the tank fills the frame — centre it */
  will-change: transform;
}
.creds__feature-cap {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  margin-top: var(--sp-1);
  color: var(--c-white-56);
  letter-spacing: 0.08em;
}
.creds__feature-cap::before {
  content: '';
  width: 3.2rem;
  height: 1px;
  background: var(--c-accent);
}
/* The grid has no gutters, so with the feature now running to column 7 the
   photograph butted straight into this copy. Pad the text column instead of
   shrinking the picture. Reset in the stacked layout below. */
.creds__head { grid-column: 8 / span 5; padding-left: var(--sp-2); }
.creds__head > p { max-width: 46ch; margin-top: var(--sp-2); }

.creds__index { margin-top: var(--sp-3); }
.creds__index-head {
  display: flex;
  justify-content: space-between;
  color: var(--c-accent);
  letter-spacing: 0.08em;
  padding-bottom: var(--sp-1);
  border-bottom: 1px solid var(--c-rule);
}
.creds__list { list-style: none; margin: 0; padding: 0; }
.creds__row {
  display: grid;
  grid-template-columns: 4ch 1fr auto;
  align-items: center;
  gap: var(--sp-1);
  width: 100%;
  min-height: 52px;
  padding: 1.2rem 0;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--c-rule);
  color: var(--c-white);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: color var(--d-base) var(--e-out), padding var(--d-base) var(--e-out);
}
.creds__row-n { color: var(--c-accent); font-size: var(--fs-small); }
.creds__row-year { color: var(--c-white-56); font-size: var(--fs-small); }
/* Key/value fact rows (credentials.facts) — same rules and rhythm as the
   index rows, but static text rather than buttons. */
.creds__facts { margin: 0; }
.creds__fact {
  display: grid;
  grid-template-columns: 10ch 1fr;
  align-items: baseline;
  gap: var(--sp-1);
  min-height: 52px;
  padding: 1.2rem 0;
  border-bottom: 1px solid var(--c-rule);
}
.creds__fact dt { color: var(--c-accent); font-size: var(--fs-small); letter-spacing: 0.04em; }
/* body inherits uppercase + wide tracking; the values read as sentence case */
.creds__fact dd {
  margin: 0;
  color: var(--c-white);
  font-size: 1.125em;
  font-weight: 500;
  letter-spacing: 0.01em;
  text-transform: none;
}
/* optional caveat under a value, e.g. what the ADG figure depends on */
.creds__fact-note {
  display: block;
  margin-top: 0.4rem;
  color: var(--c-white-56);
  font-size: var(--fs-small);
  font-weight: 400;
  line-height: 1.5;
}

/* Stage name with a one-line description under it. The number and the icon
   sit on the name's first line rather than centring on the pair. */
.creds__row:has(.creds__row-desc) { align-items: start; }
.creds__row:has(.creds__row-desc) .creds__row-n { padding-top: 0.35em; }
.creds__row-text { display: flex; flex-direction: column; gap: 0.4rem; min-width: 0; }
.creds__row-desc {
  color: var(--c-white-56);
  font-size: var(--fs-small);
  line-height: 1.5;
  max-width: 46ch;
  transition: color var(--d-base) var(--e-out);
}
.creds__row-go {
  display: inline-flex;
  width: 1.6rem;
  height: 1.6rem;
  margin-top: 0.2em;
  color: var(--c-white-56);
  opacity: 0.6;
  transition: color var(--d-base) var(--e-out), opacity var(--d-base) var(--e-out);
}
.creds__row-go svg { width: 100%; height: 100%; }
.has-hover .creds__row:hover,
.creds__row:focus-visible { color: var(--c-accent); padding-left: 0.8rem; }
.has-hover .creds__row:hover .creds__row-desc,
.creds__row:focus-visible .creds__row-desc { color: var(--c-white); }
.has-hover .creds__row:hover .creds__row-go,
.creds__row:focus-visible .creds__row-go { color: var(--c-accent); opacity: 1; }

.creds__strip-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-2);
  padding-bottom: var(--sp-2);
  color: var(--c-accent);
  letter-spacing: 0.08em;
}
.creds__strip-hint { color: var(--c-white-56); }

/* continuously drifting strip — the track holds the set twice and wraps at
   the halfway point, so there is no start or end to bump against */
.creds__marquee {
  clear: both;
  overflow: hidden;
  padding-bottom: var(--sp-2);
  cursor: grab;
  /* fade the strip into the page edges rather than cutting it off */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  touch-action: pan-y;
}
.creds__marquee.is-dragging { cursor: grabbing; }
.creds__track {
  display: flex;
  gap: var(--sp-2);
  width: max-content;
  will-change: transform;
}
.creds__card { flex: 0 0 calc(var(--grid-col) * 3); }

.creds__open {
  display: block;
  width: 100%;
  padding: 0;
  background: none;
  border: 0;
  text-align: left;
  color: inherit;
  cursor: pointer;
  position: relative;
  -webkit-tap-highlight-color: transparent;
}
.creds__open img {
  width: 100%;
  height: auto;
  border: 1px solid var(--c-accent-20);
  transition: border-color var(--d-slow) var(--e-out), opacity var(--d-slow) var(--e-out);
}
.has-hover .creds__open:hover img,
.creds__open:focus-visible img { border-color: var(--c-accent); }

/* magnifier badge, revealed on hover / focus */
.creds__zoom {
  position: absolute;
  top: var(--sp-1);
  right: var(--sp-1);
  width: 40px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 0;
  color: var(--c-black);
  background: var(--c-accent);
  opacity: 0;
  transform: scale(0.8);
  transition: opacity var(--d-base) var(--e-out), transform var(--d-base) var(--e-out);
}
.creds__zoom svg { width: 18px; height: 18px; }
.has-hover .creds__open:hover .creds__zoom,
.creds__open:focus-visible .creds__zoom { opacity: 1; transform: scale(1); }

.creds__caption {
  margin-top: var(--sp-1);
  font-size: var(--fs-small);
  color: var(--c-white-56);
  display: flex;
  gap: 0.8rem;
}
.creds__n { color: var(--c-accent); flex: none; }

/* reduced motion: no drift, plain scrollable list */
.creds__marquee.is-static { overflow-x: auto; cursor: default; }
.creds__marquee.is-static .creds__track { transform: none !important; }

/* ============================================================ lightbox
   Built in the site's own language: gold hairlines, Big Shoulders numerals,
   the same square outline controls as the rest of the page.            */
.lb {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  opacity: 0;
  transition: opacity var(--d-base) var(--e-out);
}
.is-lightbox-open .lb { opacity: 1; }
.lb__backdrop {
  position: absolute;
  inset: 0;
  background: rgb(8 8 9 / 0.94);
  cursor: pointer;
}
.lb__panel {
  position: relative;
  width: min(104rem, 92vw);
  max-height: 92svh;
  display: grid;
  grid-template-rows: auto 1fr auto auto;
  gap: var(--sp-2);
  padding: var(--sp-2) 0;
  transform: translateY(1.6rem);
  transition: transform var(--d-slow) var(--e-out);
}
.is-lightbox-open .lb__panel { transform: translateY(0); }

.lb__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding-bottom: var(--sp-1);
  border-bottom: 1px solid var(--c-rule);
}
.lb__index {
  font-family: var(--font-display);
  font-weight: 200;
  font-size: 3.2rem;
  line-height: 1;
  color: var(--c-accent);
  letter-spacing: var(--ls);
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}
.lb__sep { color: var(--c-white-20); }
.lb__index span:last-child { color: var(--c-white-56); }

.lb__close {
  width: 48px; height: 48px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0; border-radius: 0;
  color: var(--c-white); cursor: pointer;
  box-shadow: inset 0 0 0 1px var(--c-white-20);
  transition: color var(--d-base) var(--e-out), box-shadow var(--d-base) var(--e-out);
}
.lb__close svg { width: 20px; height: 20px; }
.has-hover .lb__close:hover, .lb__close:focus-visible {
  color: var(--c-accent); box-shadow: inset 0 0 0 1px var(--c-accent);
}

.lb__stage {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--sp-2);
  min-height: 0;
}
.lb__figure { margin: 0; min-height: 0; display: grid; place-items: center; }
.lb__figure img {
  max-width: 100%;
  max-height: 62svh;
  width: auto;
  height: auto;
  border: 1px solid var(--c-accent-20);
  opacity: 0;
  transform: scale(1.03);
}
.lb__figure img.is-in {
  opacity: 1;
  transform: scale(1);
  transition: opacity var(--d-slow) var(--e-out), transform var(--d-slow) var(--e-in-out-long);
}

/* square outline controls, matching .btn--square */
.lb__nav {
  position: relative;
  width: 64px; height: 64px;
  display: flex; align-items: center; justify-content: center;
  background: none; border: 0;
  color: var(--c-white); cursor: pointer;
  box-shadow: inset 0 0 0 1px var(--c-white-20);
  transition: color var(--d-base) var(--e-out), box-shadow var(--d-base) var(--e-out);
}
.lb__nav svg { width: 22px; height: 22px; }
.has-hover .lb__nav:hover, .lb__nav:focus-visible {
  color: var(--c-accent); box-shadow: inset 0 0 0 1px var(--c-accent);
}

.lb__caption {
  display: flex;
  align-items: baseline;
  gap: var(--sp-1);
  font-size: var(--fs-small);
  color: var(--c-white);
}
.lb__year { color: var(--c-accent); }
.lb__progress { height: 1px; background: var(--c-white-20); }
.lb__progress span {
  display: block; height: 100%;
  background: var(--c-accent);
  transform-origin: left;
  transform: scaleX(0);
  transition: transform var(--d-slow) var(--e-out);
}

/* ------------------------------------------------------------ testimonials */
.testimonials { padding: var(--sp-4) 0; }
/* the heading needs room to breathe above the quotes — leading-trim removes
   the descender space a title would normally carry */
.testimonials .title-lines { margin-bottom: var(--sp-3); }
.quotes {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  row-gap: var(--sp-4);
  padding-top: var(--sp-1);
}
.quotes__item:nth-child(odd) { grid-column: 2 / span 4; }
.quotes__item:nth-child(even) { grid-column: 7 / span 4; }
.quotes__item blockquote { margin: 0; }
.quotes__item p {
  font-size: var(--fs-quote);
  line-height: 1.45;
  color: var(--c-white);
  --lh: 1.45;
  --fos: var(--text-fos);
  --foe: var(--text-foe);
}
.quotes__item footer {
  margin-top: var(--sp-1);
  font-size: var(--fs-small);
  color: var(--c-accent);
}

/* ------------------------------------------------------ statement section
   ref "PERFECTION": an oversized word sitting BEHIND a centred portrait.  */
.statement {
  position: relative;
  padding: var(--sp-4) 0;
  display: grid;
  place-items: center;
  overflow: hidden;
}
.statement__word {
  grid-area: 1 / 1;
  font-family: var(--font-display);
  font-weight: 200;
  font-size: var(--fs-d1);
  line-height: var(--lh-d1);
  color: var(--c-accent);
  letter-spacing: var(--ls);
  white-space: nowrap;
  z-index: 1;
  /* top of the stack, not centred: the portrait starts halfway down the
     letters (see .statement__portrait) so the word crosses only the top of
     the video, same as on phones */
  align-self: start;
  --lh: var(--lh-d1);
  --fos: var(--display-fos);
  --foe: var(--display-foe);
}
.statement__portrait {
  grid-area: 1 / 1;
  z-index: 2;
  position: relative;
  align-self: start;
  margin-top: calc(var(--statement-word-h, 0px) * 0.52);
  width: calc(var(--grid-col) * 4.25);
  max-width: 54rem;
  overflow: hidden;
}
/* Inner layer both word copies slide on (updateStatement in app.js). */
.statement__drift { display: inline-block; will-change: transform; }
/* Soft dark edges so the video sinks into the black ground rather than
   sitting on it as a flat rectangle. Above the video, below the ghost. */
.statement__portrait::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: radial-gradient(ellipse 75% 70% at 50% 45%, transparent 55%, rgb(0 0 0 / 0.55) 100%);
  box-shadow: inset 0 0 4rem 1rem rgb(0 0 0 / 0.45);
}
.statement__portrait video { will-change: transform; }
/* Solid black copy of the word, inside the portrait so the figure
   clips it to the video. Font metrics mirror .statement__word; size and
   position are set by fitStatementWord(). */
.statement__ghost {
  position: absolute;
  z-index: 2;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 200;
  line-height: var(--lh-d1);
  letter-spacing: var(--ls);
  white-space: nowrap;
  text-align: center;
  color: #000;   /* pure black, matching the section ground */
  pointer-events: none;
}
.statement__portrait img { width: 100%; height: auto; }
.statement__portrait video { display: block; width: 100%; height: auto; aspect-ratio: 3 / 4; object-fit: cover; }
.statement__copy {
  grid-area: 1 / 1;
  z-index: 3;
  align-self: end;
  justify-self: start;
  margin-left: var(--grid-col);
  max-width: 32ch;
  font-size: var(--fs-small);
  color: var(--c-white-56);
}

/* ------------------------------------------------------------------ form */
.contact { padding: var(--sp-4) 0; }
.contact__grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: var(--sp-2) 0;
}
.contact__head { grid-column: 2 / span 5; }
.contact__cta { margin-top: var(--sp-3); }
.contact__details {
  grid-column: 8 / span 4;
  align-self: end;
  border-top: 1px solid var(--c-rule);
}
.contact__row {
  display: grid;
  grid-template-columns: 40px 1fr;
  gap: var(--sp-1);
  align-items: center;
  padding: 1.4rem 0;
  border-bottom: 1px solid var(--c-rule);
  min-height: 48px;
}
/* icon | stacked text — gold label on its own line above the value */
.contact__text { display: grid; gap: 0.2rem; min-width: 0; }
.contact__label {
  display: block;
  color: var(--c-accent);
  letter-spacing: 0.08em;
  line-height: 1.2;
}
.contact__text .contact__value { justify-self: start; word-break: break-word; }
.contact__value {
  color: var(--c-white);
  position: relative;
  /* inline-flex + min-height so the tappable box clears 44px even though the
     text itself is one short line */
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0.4rem 0;
}
.contact__value::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0.2rem;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--d-base) var(--e-out);
}
.has-hover a.contact__value:hover::after { transform: scaleX(1); }

.btn--lg { padding: 2rem 3.2rem; }

/* Booking CTA: same language as the header Book pill — gold fill, shimmer
   sweep, pulsing glow, nudging arrow. Keeps the label roll on hover. */
.btn--cta {
  gap: 1.2rem;
  background: var(--c-accent);
  color: #000;
  font-weight: 500;
  overflow: hidden;
  isolation: isolate;
  animation: cta-glow 2.8s ease-in-out infinite;
  transition: background-color var(--d-base) var(--e-out), transform var(--d-base) var(--e-out);
}
.btn--cta .btn__outline { display: none; }
.btn--cta::before {
  content: '';
  position: absolute;
  top: 0; bottom: 0;
  left: -60%;
  width: 40%;
  background: linear-gradient(100deg, transparent, rgb(255 255 255 / 0.55), transparent);
  transform: skewX(-20deg);
  animation: cta-shine 3.2s ease-in-out infinite;
  z-index: -1;
  pointer-events: none;
}
/* arrow drawn with a mask so it inherits the text colour */
.btn--cta::after {
  content: '';
  flex: none;
  width: 18px;
  height: 18px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13'/%3E%3Cpath d='m13 6 6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h13'/%3E%3Cpath d='m13 6 6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
  animation: cta-nudge 1.6s ease-in-out infinite;
}
.has-hover .btn--cta:hover { background: var(--c-accent-light); transform: translateY(-2px); }
.btn--cta:focus-visible { outline: 1px solid var(--c-white); outline-offset: 4px; }
@media (prefers-reduced-motion: reduce) {
  .btn--cta, .btn--cta::before, .btn--cta::after { animation: none; }
}

.contact__form { grid-column: 7 / span 4; display: grid; gap: var(--sp-2); }
.field { display: grid; gap: 0.8rem; }
.field label { font-size: var(--fs-small); color: var(--c-accent); }
.field input,
.field textarea {
  /* 16px floor on phones is enforced in tokens.css via --fs-body */
  font-size: max(var(--fs-body), 16px);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--c-rule);
  padding: 1.2rem 0;
  min-height: 44px;
  color: var(--c-white);
  transition: border-color var(--d-base) var(--e-out);
}
.field input:focus,
.field textarea:focus { outline: none; border-color: var(--c-accent); }
.field textarea { resize: vertical; min-height: 96px; }

/* ---------------------------------------------------------------- footer */
.footer {
  padding: var(--sp-3) var(--sp-1) var(--sp-2);
  border-top: 1px solid var(--c-rule);
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), 1fr);
  gap: var(--sp-2) 0;
  align-items: start;
}
/* three columns: mark | nav | visit (address + map) */
.footer__brand {
  grid-column: 1 / span 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}
/* Footer lockup, same construction as .header__brand: one width drives both
   images (each width:100%, height auto), so the mark can't be squashed when
   its grid column is narrow — the old fixed 12rem height did exactly that. */
.footer__lockup { display: flex; flex-direction: column; gap: 0.9rem; width: 16rem; max-width: 100%; }
.footer__mark, .footer__wordmark { display: block; width: 100%; height: auto; }
.footer__col { grid-column: 4 / span 2; }

.footer__visit { grid-column: 7 / span 6; }
.footer__visit h4 { font-size: var(--fs-small); color: var(--c-accent); margin-bottom: var(--sp-1); }
.footer__visit-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  flex-wrap: wrap;
  padding-bottom: var(--sp-1);
}
.footer__address {
  display: flex;
  align-items: center;
  gap: var(--sp-1);
  font-style: normal;
  color: var(--c-white);
  line-height: 1.5;
}
.footer__directions {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 1.8rem;
  border: 1px solid var(--c-accent-40);
  color: var(--c-accent);
  font-size: var(--fs-small);
  letter-spacing: 0.08em;
  transition: background-color var(--d-base) var(--e-out), color var(--d-base) var(--e-out);
}
.has-hover .footer__directions:hover { background: var(--c-accent); color: #000; }
.footer__map {
  position: relative;
  /* half the height of the original 16:9 frame; a plain height (not
     aspect-ratio + min-height) so it can never push wider than its column */
  width: 100%;
  height: clamp(180px, 14vw, 240px);
  border: 1px solid var(--c-rule);
  overflow: hidden;
  background: #111;
}
/* darken the stock Google tiles so the map sits in the black palette */
.footer__map iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  filter: grayscale(1) invert(0.92) contrast(0.9);
}

.footer__contact { grid-column: 7 / span 5; }
.footer__details { display: block; }
.footer__row {
  display: grid;
  grid-template-columns: 40px 1fr;
  align-items: center;
  gap: var(--sp-1);
  padding: 1rem 0;
  border-bottom: 1px solid var(--c-rule);
}
.footer__row:first-child { border-top: 1px solid var(--c-rule); }
.footer__text { display: grid; gap: 0.2rem; min-width: 0; }
.footer__label { color: var(--c-accent); }
.footer__value {
  color: var(--c-white);
  display: flex;
  align-items: center;
  min-height: 32px;
  word-break: break-word;
}
.has-hover a.footer__value:hover { color: var(--c-accent); }
.footer__col h4 { font-size: var(--fs-small); color: var(--c-accent); margin-bottom: var(--sp-1); }
.footer__col a { display: block; padding: 0.6rem 0; min-height: 44px; display: flex; align-items: center; }
.footer__legal {
  grid-column: 1 / -1;
  margin-top: var(--sp-2);
  padding-top: var(--sp-1);
  border-top: 1px solid var(--c-rule);
  font-size: var(--fs-small);
  color: var(--c-white-56);
  display: flex;
  justify-content: space-between;
  gap: var(--sp-2);
  flex-wrap: wrap;
}

/* ------------------------------------------------------------ intro loader
   Shown only while html.is-loading (set by the inline gate in index.html).
   Sequence: mark rises out of a mask -> wordmark resolves -> hairline fills
   -> .is-loaded lifts the whole panel up and the hero reveals begin.       */
.loader { display: none; }
.is-loading .loader {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
  transition: background-color 0.9s var(--e-in-out) 0.25s;
}
/* the header's own logo waits underneath until the loader's copy lands on it */
.is-loading .header__brand { opacity: 0; }
.is-loading:not(.is-loaded) body { overflow: hidden; }
.loader__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2rem;
  transition: opacity 0.5s var(--e-out), transform 0.8s var(--e-in-out);
}
/* Loader lockup: mark above wordmark, BOTH THE SAME WIDTH, exactly as the
   header does it. Sizing the mark by height and the wordmark by width left the
   two-line wordmark far wider than the mark and dominating the splash. */
.loader__mark { overflow: hidden; padding: 0.4rem 0; width: min(46vw, 240px); }
.loader__mark img {
  display: block;
  width: 100%;
  height: auto;
  animation: loader-rise 1.1s var(--e-out) 0.1s both;
}
.loader__word {
  width: min(46vw, 240px);   /* matches .loader__mark — see note above */
  height: auto;
  animation: loader-fade 0.9s var(--e-out) 0.65s both;
}
.loader__bar {
  width: 14rem;
  height: 1px;
  margin-top: 1rem;
  background: var(--c-white-20);
  overflow: hidden;
  animation: loader-fade 0.6s var(--e-out) 0.8s both;
}
.loader__bar span {
  display: block;
  height: 100%;
  background: var(--c-accent);
  transform-origin: left;
  transform: scaleX(0);
  /* creeps to 85% on its own; .is-loaded completes it */
  animation: loader-fill 1.8s var(--e-out) 0.9s forwards;
}
.is-loaded .loader__bar span { animation: none; transform: scaleX(1); transition: transform 0.3s var(--e-out); }
/* hand-off: ground fades, bar fades, mark + wordmark fly to the header */
.is-loaded .loader { background-color: rgb(0 0 0 / 0); pointer-events: none; }
.is-loaded .loader__bar { animation: none; opacity: 0; transition: opacity 0.3s var(--e-out); }
.is-loaded .loader__mark { overflow: visible; }
.is-loaded .loader__mark img,
.is-loaded .loader__word {
  animation: none;
  transform-origin: 50% 50%;
  transition: transform 1.1s var(--e-in-out), opacity 0.6s var(--e-out);
}
@keyframes loader-rise {
  from { transform: translateY(105%); }
  to { transform: translateY(0); }
}
@keyframes loader-fade {
  from { opacity: 0; transform: translateY(0.8rem); }
  to { opacity: 1; transform: none; }
}
@keyframes loader-fill {
  from { transform: scaleX(0); }
  to { transform: scaleX(0.85); }
}
@media (max-width: 667px) {
  .loader__mark { width: min(58vw, 200px); }
  .loader__word { width: min(58vw, 200px); }
}

/* ------------------------------------------------ mobile sticky Book Now */
.mbook { display: none; }
@media (max-width: 667px) {
  .mbook {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: calc(var(--z-header) + 1);
    display: block;
    padding: 0 0 env(safe-area-inset-bottom, 0px);
    background: #000;
    border-top: 1px solid var(--c-accent-40);
    transition: transform var(--d-slow) var(--e-out), opacity var(--d-base) var(--e-out);
  }
  /* Same .act pair as the header, just taller for thumbs. Call takes the room
     because it is what growers actually use to order. */
  .mbook__row {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px;
    padding: 8px 10px;
  }
  .mbook__row .act { min-height: 52px; }
  .mbook__row .act svg { width: 18px; height: 18px; }
  /* the menu and lightbox carry their own controls — step aside */
  .is-menu-open .mbook,
  .is-lightbox-open .mbook { transform: translateY(110%); opacity: 0; pointer-events: none; }
  /* keep the last of the page (footer legal line) clear of the bar */
  body { padding-bottom: calc(69px + env(safe-area-inset-bottom, 0px)); }
}

/* ==========================================================================
   MOTION — reveal states
   Every reveal is a CSS transition toggled by an IntersectionObserver, which
   is how the reference does it (no animation library anywhere on that site).
   Durations and curves below are the reference's, verbatim.
   ========================================================================== */

/* base — ref: .animation--* { transition-duration: .4s; timing: easeOut } */
[class*='animation--'] {
  transition-duration: var(--d-base);
  transition-timing-function: var(--e-out);
}

/* fade-in — ref: transition-property opacity */
.animation--fade-in { transition-property: opacity; will-change: opacity; }
.animation--fade-in--inactive { opacity: 0; }
.animation--fade-in-slow { transition-duration: var(--d-slow); }

/* title — the circular clip wipe.
   ref: clip-path circle(29.5% at 50% 250%) -> circle(70.7% at 50% 50%)
        transform scale(1.35) translateY(0) -> scale(1) translateY(0)
        1.6s on the house curve. 70.7% ~= sqrt(2)/2, the radius that just
        covers the corners of a square.                                    */
.animation--title {
  clip-path: circle(70.7% at 50% 50%);
  transform: scale(1) translateY(0);
  transition:
    transform var(--d-reveal) var(--e-out),
    clip-path var(--d-reveal) var(--e-out);
  will-change: transform, clip-path;
}
.animation--title--inactive {
  clip-path: circle(29.5% at 50% 250%);
  transform: scale(var(--title-scale)) translateY(var(--title-translate-y));
}

/* text — line-split slide up with the 2 degree tilt.
   ref: .line translateY(230%) rotate(-2deg) -> 0, 2.4s easeInOutLong      */
.animation--text,
.animation--text .line {
  /* house ease-out (fast start) instead of the ref's easeInOutLong, whose
     slow first half read as the text lagging behind the scroll */
  transition: transform var(--d-text) var(--e-out);
}
.animation--text .line-mask {
  display: block;
  overflow: hidden;
}
.animation--text .line {
  display: block;
  transform-origin: left top;
  will-change: transform;
  /* Each .line is a row splitToLines already measured as fitting. Re-rendering
     it as one text run can land a sub-pixel over the container (a line that
     measured 293.0 inside a 293.376 box), and the browser then wraps it,
     orphaning the last word onto a second row inside a "single line" element.
     nowrap holds the measured result; .line-mask clips any hair of overflow. */
  white-space: nowrap;
}
.animation--text--inactive .line {
  transform: translateY(var(--text-translate-y)) rotate(var(--text-rotate)) scale(var(--text-scale));
}

/* image-zoom-in — ref: scale(1.2) -> 1, 1.6s cubic-bezier(.7,0,.3,1) */
.animation--image-zoom-in {
  transition-duration: var(--d-reveal);
  transition-timing-function: var(--e-out);
  transition-property: transform;
  will-change: transform;
}
.animation--image-zoom-in--inactive { transform: scale(1.2); }

/* tape — masked slide-up of the inner content, 1.6s house curve, .4s delay */
.animation--tape { overflow: hidden; display: block; }
.animation--tape .btn__content,
.animation--tape .tape__inner {
  display: block;
  transform: translateY(0);
  transition: transform var(--d-reveal) var(--e-out);
  transition-delay: 0.1s;
}
.animation--tape--inactive .btn__content,
.animation--tape--inactive .tape__inner { transform: translateY(200%); }

/* button-in — outline draws, label fades */
.animation--button-in { transition-property: opacity; }
.animation--button-in--inactive { opacity: 0; }
.animation--button-in--inactive .btn__outline rect + rect { stroke-dashoffset: var(--path-length, 1000px); }

/* stagger helper */
[data-reveal-stagger] > * { transition-delay: calc(var(--i, 0) * 60ms); }

/* ==========================================================================
   RESPONSIVE
   ========================================================================== */

/* -------- tablet ---------------------------------------------------- */
@media (max-width: 979px) {
  /* Tablet: the desktop overlap (copy half on the photo, half on black) turns
     messy at this width. Photo left, copy + quote + stats right, no overlap. */
  .intro__body { align-items: start; column-gap: var(--sp-3); padding: 0 var(--sp-2); }
  .intro__media { grid-column: 1 / span 4; grid-row: 1 / span 2; aspect-ratio: 3 / 4; }
  .intro__media::after { display: none; }   /* no text on the photo, no scrim */
  .intro__copy {
    grid-column: 5 / span 4;
    grid-row: 1;
    margin-top: 0;
    padding-left: 0;
  }
  .intro__quote {
    grid-column: 5 / span 4;
    grid-row: 2;
    align-self: start;
    margin-top: var(--sp-3);
    padding-top: var(--sp-3);
    padding-bottom: 0;
    border-top: 1px solid var(--c-rule);
  }
  .hslider__panel-media { grid-column: 5 / span 4; }
  .hslider__panel-body { grid-column: 1 / span 4; padding-left: var(--sp-2); }
  .gallery__card:nth-child(1) { grid-column: 1 / span 4; }
  .gallery__card:nth-child(2) { grid-column: 5 / span 4; }
  .gallery__card:nth-child(3) { grid-column: 2 / span 4; }
  .services__link { grid-template-columns: auto 96px 1fr auto; }
  .services__list--nothumb .services__link { grid-template-columns: auto 1fr auto; }
  .services__desc { display: none; }
  .contact { padding-left: var(--sp-1); padding-right: var(--sp-1); }
  .contact__head { grid-column: 1 / span 8; }
  .contact__form { grid-column: 1 / span 8; }
  .contact__details { grid-column: 1 / span 8; margin-top: var(--sp-3); }
  /* too narrow for side by side: heading + index first, photo full width */
  .creds__intro { display: flex; flex-direction: column; align-items: stretch; }
  .creds__head { padding-left: 0; }   /* stacked — no photo beside it */
  .creds__head { order: 1; }
  .creds__feature { order: 2; width: 100%; margin-top: var(--sp-3); }
  .creds__card { flex: 0 0 calc(var(--grid-col) * 4.5); }
  .quotes__item:nth-child(odd) { grid-column: 1 / span 5; }
  .quotes__item:nth-child(even) { grid-column: 4 / span 5; }
  .footer__brand { grid-column: 1 / span 3; }
  .footer__col { grid-column: 4 / span 3; }
  .footer__visit { grid-column: 1 / -1; }
}

/* -------- phone -----------------------------------------------------
   Designed as its own composition, not a reflow. See README.          */
@media (max-width: 667px) {
  .header { padding: 2rem var(--sp-1) 0.8rem; }
  .is-scrolled .header { padding-top: 0.8rem; }
  /* phones have the width to spare and no nav beside it */
  .header__brand { width: 10.4rem; }   /* 20% smaller at the client's request (was 13rem) */
  .is-scrolled .header__brand { width: 8rem; }
  .header__meta { display: none; }
  .header__nav { display: none; }
  .header__burger { display: flex; grid-column: 3; justify-self: end; }
  .header__tools { display: inline-flex; grid-column: 2; justify-self: end; margin-right: 8px; }

  .hero { min-height: 100svh; }
  .hero__cta .btn { --btn-size: 6.4rem; }

  /* single readable column everywhere */
  .intro { padding: var(--sp-3) 0; }
  .intro__kicker { margin-left: var(--sp-2); }
  .intro__body { display: block; }
  .intro__media {
    grid-column: auto;
    width: 100%;
    aspect-ratio: 3 / 4;
    margin-bottom: var(--sp-3);
  }
  /* The jar clip fills its 3:4 frame top to bottom — keep the full box so
     neither the collar nor the base is cut; just tighten the gap below. */
  .intro__media:has(video) { margin-bottom: var(--sp-1); }
  .intro__copy,
  .intro__quote {
    grid-column: auto;
    padding: 0 var(--sp-2);
    max-width: none;
  }
  /* must clear the desktop rule's 36rem top offset, which exists only to push
     the copy down over the bleeding picture. On a stacked phone layout it is
     360px of dead space. */
  .intro__copy {
    padding-top: 0;
    margin-top: 0;
    margin-bottom: var(--sp-3);
  }
  .intro__copy .text-small { margin-bottom: var(--sp-1); }
  .intro__quote { padding-bottom: 0; margin-top: 0; padding-top: 0; border-top: 0; }
  /* undo the tablet side-by-side rules (they sit in the max-width: 979px block) */
  .intro__body { padding: 0; }
  .intro__btn { --btn-size: auto; width: 100%; }

  /* services: descriptions are always visible on touch — never hover-gated */
  .services { padding: var(--sp-3) 0; }
  /* thumb on the left, number + name + description stacked to its right */
  .services__link {
    grid-template-columns: 76px 1fr;
    grid-template-areas:
      'thumb num'
      'thumb name'
      'thumb desc';
    column-gap: var(--sp-1);
    row-gap: 0.4rem;
    padding: var(--sp-2);
    align-items: start;
    align-content: center;
  }
  .services__list--nothumb .services__link {
    grid-template-columns: 1fr;
    grid-template-areas: 'num' 'name' 'desc';
  }
  .services__thumb { grid-area: thumb; width: 76px; height: 76px; align-self: center; }
  .services__thumb img { filter: none; transform: none; }
  .services__num { grid-area: num; }
  .services__name { grid-area: name; }
  /* display:block is REQUIRED here — the tablet block above hides the
     description, and that rule also matches at phone widths. Descriptions
     must never be hidden on touch; there is no hover to reveal them. */
  .services__desc { grid-area: desc; display: block; max-width: none; }
  .services__arrow { display: none; }

  /* gallery: one column, size variation kept for rhythm */
  .gallery { padding: var(--sp-3) 0; }
  .gallery__grid { display: block; padding: 0 var(--sp-2); }
  .gallery__card { margin: 0 0 var(--sp-3) !important; }
  .gallery__card:nth-child(2) { width: 78%; margin-left: auto !important; }
  .gallery__card:nth-child(3) { width: 62%; }

  /* statement: word above the portrait rather than behind it — at phone
     width the overlap makes both illegible */
  .statement { display: block; padding: var(--sp-3) var(--sp-2); }
  .statement__word {
    display: block;
    font-size: var(--fs-d2);   /* fallback; fitStatementWord() sets the real size */
    white-space: nowrap;       /* one line, scaled to the width */
    text-align: center;
    margin-bottom: 0;
    position: relative;
    z-index: 1;
  }
  /* Phones overlap too: the portrait rides up over the lower half of the
     word, and the black ghost letters cut through the top of the video.
     --statement-word-h is the word's rendered height, set by
     fitStatementWord(); with no JS the margin falls back to 0. */
  .statement__portrait {
    width: 84%;
    max-width: none;
    margin: calc(var(--statement-word-h, 0px) * -0.48) auto 0;
    position: relative;
    z-index: 2;
  }
  .statement__copy {
    margin: var(--sp-2) 0 0;
    max-width: none;
    text-align: center;
  }

  /* stats sit side by side but with breathing room */
  .stats { gap: var(--sp-3); margin-top: var(--sp-2); }
  /* bigger counters on phones: two equal columns, large gold numerals */
  .stats__item { flex: 1 1 0; gap: 0.8rem; }
  .stats__value { font-size: 8rem; }
  .stats__label { font-size: 1.6rem; letter-spacing: 0.06em; }

  /* credentials: heading stacks, feature photo becomes a normal block,
     certificate strip stays a swipe carousel (it already was one) */
  .creds { padding: var(--sp-3) var(--sp-2); }
  .creds__intro { display: flex; flex-direction: column; margin-bottom: var(--sp-3); }
  .creds__feature { order: 2; width: 100%; margin-top: var(--sp-3); }
  .creds__head { order: 1; }
  .creds__strip-head { flex-direction: column; gap: 0.4rem; }
  .creds__marquee { margin-inline: calc(var(--sp-2) * -1); }
  .creds__track { gap: var(--sp-1); }
  .creds__card { flex: 0 0 76vw; }
  .creds__zoom { width: 36px; height: 36px; opacity: 1; transform: none; }

  /* lightbox: chevrons move below the image so the picture gets the width */
  .lb__panel { width: 94vw; gap: var(--sp-1); grid-template-rows: auto 1fr auto auto auto; }
  .lb__stage { grid-template-columns: 1fr; }
  .lb__figure img { max-height: 54svh; }
  .lb__nav {
    position: absolute;
    bottom: calc(var(--sp-2) * -1);
    width: 56px; height: 56px;
  }
  .lb__nav--prev { left: 0; }
  .lb__nav--next { right: 0; }
  .lb__caption { justify-content: center; flex-wrap: wrap; margin-top: var(--sp-3); text-align: center; }
  .lb__index { font-size: 2.6rem; }

  /* footer: mark centred above the details */
  .footer__brand { align-items: center; text-align: center; margin-bottom: var(--sp-3); }
  .footer__col { text-align: center; }
  .footer__col a { justify-content: center; }
  .footer__visit { margin-top: var(--sp-2); }
  .footer__visit h4 { text-align: center; }
  .footer__visit-row { flex-direction: column; align-items: stretch; }
  .footer__address { justify-content: center; text-align: left; }
  .footer__directions { justify-content: center; }
  .footer__map { height: 180px; }
  .footer__lockup { width: 15rem; }
  .footer__contact { grid-column: auto; margin-top: var(--sp-2); }

  .testimonials { padding: var(--sp-3) var(--sp-2); }
  .quotes { display: block; }
  .quotes__item { margin-bottom: var(--sp-3); }
  .quotes__item:nth-child(odd),
  .quotes__item:nth-child(even) { grid-column: auto; }

  .contact { padding: var(--sp-3) var(--sp-2); }
  .contact__grid { display: block; }
  .contact__head { margin-bottom: var(--sp-3); }
  .contact__cta { margin-top: var(--sp-2); }
  .contact__cta .btn { width: 100%; }
  .contact__details { grid-column: auto; margin-top: var(--sp-2); }
  .contact__row { grid-template-columns: 40px 1fr; }
  .contact__form { display: grid; gap: var(--sp-2); }

  .footer { display: block; padding: var(--sp-3) var(--sp-2) var(--sp-2); }
  .footer__brand { margin-bottom: var(--sp-2); }
  .footer__col { margin-bottom: var(--sp-2); }
  .footer__legal { flex-direction: column; align-items: center; text-align: center; gap: 0.8rem; }
}

/* -------- short landscape (phone on its side) ------------------------
   ref gates this with a 13/9 aspect ratio; same idea here. A 100svh hero
   plus a long pin is the worst case on a short viewport.                */
@media (max-height: 500px) and (min-aspect-ratio: 13/9) {
  /* The hero's fixed-percentage bands do not survive a 390px-tall viewport —
     the tagline at 76.6% lands below the fold. Fall back to normal flow. */
  .hero {
    height: auto;
    min-height: 100svh;
    padding: calc(var(--header-h) + var(--sp-2)) 0 var(--sp-3);
    justify-content: center;
  }
  .hero__inner {
    position: relative;
    inset: auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--sp-1);
  }
  .hero__row { position: relative; top: auto; left: auto; right: auto; }
  .hero__cta .btn { --btn-size: 5.6rem; }
  .hero__tagline { margin-top: 0; }

  .menu { padding-top: calc(var(--header-h) + var(--sp-1)); overflow-y: auto; }
  .menu__link { font-size: 2.6rem; }
}

/* -------- pinned slider -> carousel -------------------------------------
   Applies to phones AND to short landscape viewports. A 6-viewport pin on a
   390px-tall screen freezes the page for thousands of pixels of scrolling.
   The JS uses the same condition (see isCarousel() in app.js).           */
@media (max-width: 667px), (max-height: 500px) and (min-aspect-ratio: 13/9), (hover: none) and (pointer: coarse) {
  .hslider { height: auto !important; }
  .hslider__sticky {
    position: static;
    display: block;
    height: auto;
    overflow: visible;
  }
  .hslider__track {
    display: flex;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    transform: none !important;
    gap: var(--sp-2);
    padding: 0 var(--sp-2);
    height: auto;
  }
  .hslider__track::-webkit-scrollbar { display: none; }
  .hslider__panel {
    flex: 0 0 calc(var(--vw100) * 0.82);
    scroll-snap-align: center;
    display: block;
    height: auto;
  }
  .hslider__panel-media {
    grid-column: auto;
    height: auto;
    width: 100%;
    aspect-ratio: 3 / 4;
    max-height: none;
    margin-bottom: var(--sp-2);
  }
  .hslider__panel-body { grid-column: auto; padding: 0; }
  .hslider__progress { position: static; margin: var(--sp-2) var(--sp-2) 0; }
}

/* ---- swipe cue (carousel only) ---------------------------------------- */
.hslider__hint { display: none; }
@media (max-width: 667px), (max-height: 500px) and (min-aspect-ratio: 13/9), (hover: none) and (pointer: coarse) {
  .hslider__sticky { position: relative; }
  .hslider__hint {
    position: absolute;
    right: var(--sp-2);
    /* vertical middle of the 3:4 image: 82vw wide -> 109vw tall -> half */
    top: calc(var(--vw100) * 0.82 * 4 / 3 / 2);
    transform: translateY(-50%);
    z-index: 3;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.6rem;
    padding: 0;
    background: none;
    border: 0;
    color: var(--c-accent);
    cursor: pointer;
    transition: opacity var(--d-slow) var(--e-out);
    -webkit-tap-highlight-color: transparent;
  }
  .hslider__hint-ring {
    position: relative;
    width: 56px;
    height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 0;
    border: 1px solid var(--c-accent);
    background: rgb(0 0 0 / 0.55);
    -webkit-backdrop-filter: blur(6px);
    backdrop-filter: blur(6px);
  }
  /* soft expanding halo */
  .hslider__hint-ring::after {
    content: '';
    position: absolute;
    inset: -1px;
    border-radius: 0;
    border: 1px solid var(--c-accent);
    animation: hs-halo 2.2s var(--e-out) infinite;
  }
  .hslider__hint-ring svg {
    width: 22px;
    height: 22px;
    animation: hs-nudge 1.6s ease-in-out infinite;
  }
  .hslider__hint-label {
    font-size: 1.1rem;
    letter-spacing: 0.18em;
    color: var(--c-white);
    text-shadow: 0 1px 6px rgb(0 0 0 / 0.8);
  }
  /* previous arrow sits on the left edge; its nudge runs the other way */
  .hslider__hint--prev { right: auto; left: var(--sp-2); }
  .hslider__hint--prev .hslider__hint-ring svg { animation-direction: reverse; }
  /* the display:flex above would otherwise override the hidden attribute */
  .hslider__hint[hidden] { display: none !important; }
}

/* Touch tablets (iPad, portrait or landscape): the swipe carousel, but with
   panels sized so two or more show at once and the image never grows taller
   than the screen. --hs-w is the panel (and image) width. */
@media (hover: none) and (pointer: coarse) and (min-width: 668px) and (min-height: 501px) {
  .hslider { --hs-w: min(44vw, 46svh); padding: var(--sp-3) 0; }
  /* flex-start: the desktop track centres its panels vertically, which
     staggered them here (each panel's copy is a different length) */
  .hslider__track { align-items: flex-start; scroll-padding-inline: var(--sp-2); }
  .hslider__panel { flex: 0 0 var(--hs-w); scroll-snap-align: start; }
  /* The desktop title size (~110px) is far wider than a tablet panel and was
     cut off; size it to the panel instead. */
  .hslider__panel-body .h3 { font-size: calc(var(--hs-w) * 0.15); line-height: 1; overflow-wrap: anywhere; }
  .hslider__index { margin-bottom: var(--sp-1); }
  .hslider__panel-media { aspect-ratio: 3 / 4; }
  .hslider__hint { top: calc(var(--sp-3) + var(--hs-w) * 4 / 3 / 2); }
}
@keyframes hs-nudge {
  0%, 100% { transform: translateX(-3px); }
  50% { transform: translateX(5px); }
}
@keyframes hs-halo {
  0% { transform: scale(1); opacity: 0.7; }
  100% { transform: scale(1.55); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .hslider__hint-ring::after,
  .hslider__hint-ring svg { animation: none; }
}
@media (max-height: 500px) and (min-aspect-ratio: 13/9) {
  /* landscape: 46vw panels at 16:10 */
  .hslider__hint { top: calc(var(--vw100) * 0.46 * 10 / 16 / 2); }
}

/* landscape phones are wide enough for two panels side by side */
@media (max-height: 500px) and (min-aspect-ratio: 13/9) {
  .hslider__panel { flex: 0 0 calc(var(--vw100) * 0.46); }
  .hslider__panel-media { aspect-ratio: 16 / 10; }
}

/* ==========================================================================
   FALLBACKS
   ========================================================================== */

/* <noscript> content: the page is rendered from site.config.js, so with
   scripting off this is all there is. Make it look deliberate. */
.noscript {
  max-width: 62ch;
  margin: 0 auto;
  padding: 12vh var(--sp-2) var(--sp-4);
  display: grid;
  gap: var(--sp-2);
  font-size: max(var(--fs-body), 16px);
}
.noscript a { color: var(--c-accent); text-decoration: underline; }

/* If the JS never runs, nothing may stay invisible. */
.no-js [class*='--inactive'],
.no-js .animation--title--inactive,
.no-js .animation--text--inactive .line {
  opacity: 1 !important;
  transform: none !important;
  clip-path: none !important;
}
.no-js .hslider { height: auto !important; }
.no-js .hslider__sticky { position: static; height: auto; }
.no-js .hslider__track { flex-wrap: wrap; transform: none !important; }
.no-js .hslider__panel { flex: 0 0 100%; }

/* Reduced motion: no smooth scroll, no reveals, no parallax, no pin.
   Scrubbed values jump to their final state. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  [class*='--inactive'] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
  }
  .animation--text--inactive .line { transform: none !important; }
  .hero__media,
  .intro__media img,
  .intro__media video,
  .gallery__card,
  .hslider__panel-media img,
  .hslider__panel-media video { transform: none !important; }
  .hslider { height: auto !important; }
  .hslider__sticky { position: static; height: auto; overflow: visible; }
  .hslider__track { flex-wrap: wrap; transform: none !important; }
  .hslider__panel { flex: 0 0 100%; }
}
