/* ==========================================================================
   Nine Pines Renovation and Design
   Landing page styles. Plain CSS, no build step.
   Ported from the Claude Design canvas "Nine Pines Landing".
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Greens — one brand green across every dark surface (hero, custom band,
     reviews panel, contact panel, footer). Keep these two in step; the second
     name is kept only so existing rules don't need rewriting. */
  --green-900: #16281f;
  --green-800: #16281f;
  --ink: #1b2b23;
  --ink-muted: #4a5c51;
  /* Was #7c8b81, which measured 3.2:1 on both light surfaces and failed AA
     everywhere it was used (step labels, review dates, field placeholders).
     #5f6f66 is 4.99:1 on --page and 4.80:1 on --cream. */
  --ink-faint: #5f6f66;

  /* Golds. Three jobs, three values — they are not interchangeable:
       --gold       decoration only (hairlines, rules, large display numerals).
                    3.2:1 on light, so never use it for text under 24px.
       --gold-cta   button fills. 6.3:1 against --green-900 text. The old fill
                    (--gold) cleared AA by 0.01, which is not a margin.
       --gold-ink   gold-coloured TEXT on light. 5.5:1 on --cream.
       --gold-light gold-coloured text/accents on the dark green. 6.3:1. */
  --gold: #a98545;
  --gold-cta: #c3a067;
  --gold-cta-hover: #d2b681;
  --gold-ink: #7a5d2b;
  --gold-light: #c3a067;
  --gold-dark: #7a5d2b;

  /* Neutrals */
  --page: #faf7f7;
  --cream: #f7f3ea;
  --stone: #dcd8cc;
  --stone-light: #e2dfd3;

  --rule: rgba(27, 43, 35, 0.14);
  --rule-strong: rgba(27, 43, 35, 0.28);
  --rule-on-dark: rgba(247, 243, 234, 0.18);

  --serif: "Cormorant Garamond", "Iowan Old Style", Georgia, serif;
  --sans: "Karla", system-ui, -apple-system, "Segoe UI", sans-serif;

  /* Type scale. The page previously rendered 19 distinct sizes, 17 of them
     under 11px. This is the whole set now: six steps plus the display clamps
     that live on the headings themselves. 11px is the floor — below that the
     tracked uppercase labels stop being readable for the 40+ audience this
     page is written for. */
  --fs-micro: 11px;   /* tracked uppercase labels: dt, step label, source */
  --fs-label: 12px;   /* eyebrow, buttons, quote link, back link */
  --fs-xs: 13px;
  --fs-sm: 14px;
  --fs-base: 15px;    /* body copy; 16px below 620px */
  --fs-md: 17px;

  --shell: 1240px;
  --gutter: 40px;

  /* Left/right bleed padding that lines a full-width panel up with the shell. */
  --bleed: max(var(--gutter), calc((100vw - var(--shell)) / 2));

  /* White band held under the dark consultation panel. The panel and the
     footer are the same green, so without it the two dark blocks run together
     into one shape. */
  --panel-inset: 32px;

  /* Motion. One easing pair for the whole page: --ease for anything that
     moves under its own steam, --ease-out for anything settling into place. */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 180ms;
  --dur-mid: 420ms;
  --dur-slow: 760ms;

  /* Photo treatment. See section 3b — these are the two dials worth turning
     once real client photography lands. */
  --photo-tint: 0.5;
  --photo-grain: 0.16;
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The hero/contact bleed padding is derived from 100vw, which includes the
     scrollbar on platforms that reserve space for it. `clip` absorbs the few
     stray pixels without creating a scroll container the way `hidden` does. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img {
  display: block;
  max-width: 100%;
}

a {
  color: var(--gold-ink);
  text-decoration: none;
}

a:hover {
  color: var(--ink);
}

::selection {
  background: var(--gold);
  color: var(--cream);
}

h1,
h2,
h3 {
  font-family: var(--serif);
  margin: 0;
  text-wrap: pretty;
}

p {
  margin: 0;
}

/* The UA gives blockquote a 40px side margin, which would strangle the review
   cards down to one word per line. */
blockquote,
figure {
  margin: 0;
}

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

/* Visible keyboard focus everywhere. */
:focus-visible {
  outline: 2px solid var(--gold-ink);
  outline-offset: 3px;
  border-radius: 1px;
}

/* On the dark panels the ink-gold ring disappears; use the light gold there. */
.hero :focus-visible,
.custom-band :focus-visible,
.contact__intro :focus-visible,
.reviews__panel :focus-visible,
.site-footer :focus-visible,
.compare :focus-visible {
  outline-color: var(--gold-cta-hover);
}

.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 100;
  background: var(--green-900);
  color: var(--cream);
  padding: 14px 20px;
  font-size: var(--fs-label);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  transition: top 160ms ease;
}

.skip-link:focus {
  top: 12px;
  color: var(--cream);
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   3. Shared pieces
   -------------------------------------------------------------------------- */
.shell {
  max-width: var(--shell);
  margin: 0 auto;
  padding-inline: var(--gutter);
}

.eyebrow {
  font-size: var(--fs-label);
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--gold-ink);
}

.eyebrow--on-dark {
  color: var(--gold-light);
}

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

/* Section numerals ----------------------------------------------------------
   01–05 were 11px gold labels: the most distinctive structural idea on the
   page, set as the smallest thing in the section. They are display numerals
   now, each trailing a hairline that fades into the column. At 44px+ the
   3.2:1 gold clears AA's large-text threshold. */
.step-number {
  display: flex;
  align-items: center;
  gap: 18px;
  font-family: var(--serif);
  font-size: clamp(44px, 5vw, 68px);
  font-weight: 300;
  line-height: 1;
  letter-spacing: 0.01em;
  color: var(--gold);
  font-feature-settings: "lnum" 1;
}

.step-number::after {
  content: "";
  flex: 1;
  height: 1px;
  background: linear-gradient(to right, var(--gold), rgba(169, 133, 69, 0));
}

/* Logo lockup ---------------------------------------------------------------
   The artwork is a stacked mark (tree over two lines of type), so its height
   drives the header height. Sizes below are the smallest at which the
   "RENOVATION AND DESIGN" line still reads. */
.brand {
  display: block;
  flex: none;
}

.brand img {
  display: block;
  height: 46px;
  width: auto;
}

.footer-logo {
  height: 53px;
  width: auto;
  flex: none;
  /* The lockup's rule sits above its cap height, so a flush-top box reads
     high. This centres the wordmark against the label-and-value block
     beside it rather than hanging off its top edge. */
  margin-top: 22px;
}

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 15px 34px;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  font-weight: 600;
  border-radius: 1px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color var(--dur-fast) ease, color var(--dur-fast) ease,
    border-color var(--dur-fast) ease, transform var(--dur-fast) var(--ease);
}

.btn--gold {
  background: var(--gold-cta);
  color: var(--green-900);
}

.btn--gold:hover {
  background: var(--gold-cta-hover);
  color: var(--green-900);
  transform: translateY(-1px);
}

.btn--gold:active {
  transform: translateY(0);
}

.btn--ghost {
  background: transparent;
  border-color: rgba(247, 243, 234, 0.4);
  color: var(--cream);
  font-weight: 500;
}

.btn--ghost:hover {
  border-color: var(--gold-light);
  color: var(--gold-light);
}

/* Underlined text link used under each service block. Was a 24.6px-tall tap
   target — the most-repeated conversion path on the page and the smallest
   thing on it. Padded to clear 44px without changing how it reads. */
.quote-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold-ink);
  box-shadow: inset 0 -1px 0 0 rgba(122, 93, 43, 0.45);
  transition: color var(--dur-fast) ease, box-shadow var(--dur-fast) ease;
}

.quote-link:hover {
  color: var(--ink);
  box-shadow: inset 0 -1px 0 0 var(--ink);
}

/* "Photo coming soon" frame. Unused on the page today — the gallery ships
   with real imagery — but kept for any slot that goes empty during content
   swaps. The label was 2.5:1; it is legible now. */
.photo-placeholder {
  background: var(--stone-light);
  border: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: center;
  padding: 24px;
}

.photo-placeholder::before {
  content: "";
  width: 26px;
  height: 1px;
  background: rgba(169, 133, 69, 0.7);
}

.photo-placeholder span {
  font-size: var(--fs-micro);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: #4a5c51;
}

/* --------------------------------------------------------------------------
   3b. Photo treatment system
   --------------------------------------------------------------------------
   The photography on this site will arrive from a contractor: phone shots,
   several devices, several times of day, mixed white balance — next to the
   occasional bright stock frame. Left alone they read as "someone uploaded
   some pictures". Three light passes make a mixed set read as one body of
   work, and they are the reason the warm brand palette and the cool interior
   shots stop fighting each other:

     1. a small saturation/contrast correction on the image itself
     2. a warm tint plus corner vignette in soft-light
     3. a fine grain in overlay

   Turn --photo-tint / --photo-grain down (or to 0) once real, colour-graded
   photography is in place. Wrap any new image in <div class="photo"> to opt
   it in. `isolation: isolate` keeps the blend modes inside the frame so they
   never pick up the page behind them.
   -------------------------------------------------------------------------- */
.photo {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--stone);
}

.photo > img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: saturate(0.94) contrast(1.03);
}

/* Warm tint + vignette. */
.photo::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: var(--photo-tint);
  mix-blend-mode: soft-light;
  background:
    radial-gradient(120% 120% at 50% 42%, rgba(247, 243, 234, 0.5) 0%, rgba(22, 40, 31, 0.55) 100%),
    linear-gradient(200deg, rgba(195, 160, 103, 0.55), rgba(22, 40, 31, 0.35));
}

/* Grain. feTurbulence rendered once into a data URI — no extra request. */
.photo::after {
  content: "";
  position: absolute;
  inset: -50%;
  z-index: 2;
  pointer-events: none;
  opacity: var(--photo-grain);
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.55'/%3E%3C/svg%3E");
}

/* --------------------------------------------------------------------------
   3c. Motion
   --------------------------------------------------------------------------
   Everything here is opt-in twice over: the hidden start state is scoped to
   `.has-js`, so the page renders complete if the script never runs, and the
   reduced-motion block in section 13 unwinds all of it.
   -------------------------------------------------------------------------- */
.has-js [data-reveal] {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity var(--dur-slow) var(--ease-out) var(--reveal-delay, 0ms),
    transform var(--dur-slow) var(--ease-out) var(--reveal-delay, 0ms);
}

.has-js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* A rule draws itself in rather than fading. */
.has-js [data-reveal="rule"] {
  opacity: 1;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform var(--dur-slow) var(--ease-out) var(--reveal-delay, 0ms);
}

.has-js [data-reveal="rule"].is-in {
  transform: scaleX(1);
}

/* Media settles out of a slow push-in. */
.has-js [data-reveal="media"] {
  opacity: 0;
  transform: none;
  transition: opacity var(--dur-slow) var(--ease-out) var(--reveal-delay, 0ms);
}

.has-js [data-reveal="media"].is-in {
  opacity: 1;
}

.has-js [data-reveal="media"] > img,
.has-js [data-reveal="media"] .photo > img {
  transform: scale(1.07);
  transition: transform 1500ms var(--ease-out) var(--reveal-delay, 0ms);
}

.has-js [data-reveal="media"].is-in > img,
.has-js [data-reveal="media"].is-in .photo > img {
  transform: scale(1);
}

/* The numeral's hairline draws after the numeral has arrived. */
.has-js [data-reveal] .step-number::after {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 900ms var(--ease-out) 220ms;
}

.has-js [data-reveal].is-in .step-number::after {
  transform: scaleX(1);
}

/* Hero — above the fold, so it plays on load rather than on scroll. */
.has-js .hero__copy > * {
  opacity: 0;
}

.has-js .hero__media > .photo > img {
  transform: scale(1.08);
}

html.is-ready .hero__copy > * {
  animation: np-rise 820ms var(--ease-out) forwards;
}

html.is-ready .hero__copy > .rule {
  animation-name: np-draw;
  transform-origin: left center;
}

html.is-ready .hero__copy > *:nth-child(1) { animation-delay: 80ms; }
html.is-ready .hero__copy > *:nth-child(2) { animation-delay: 180ms; }
html.is-ready .hero__copy > *:nth-child(3) { animation-delay: 330ms; }
html.is-ready .hero__copy > *:nth-child(4) { animation-delay: 410ms; }
html.is-ready .hero__copy > *:nth-child(5) { animation-delay: 500ms; }

html.is-ready .hero__media > .photo > img {
  transition: transform 1900ms var(--ease-out);
  transform: scale(1);
}

@keyframes np-rise {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}

@keyframes np-draw {
  from { opacity: 1; transform: scaleX(0); }
  to   { opacity: 1; transform: scaleX(1); }
}

/* --------------------------------------------------------------------------
   4. Header
   -------------------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--page);
  border-bottom: 2px solid var(--gold);
  transition: transform var(--dur-mid) var(--ease);
}

.site-header[data-hidden="true"] {
  transform: translateY(calc(-100% - 2px));
}

.site-header__inner {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 20px var(--gutter);
  display: flex;
  align-items: center;
  gap: 32px;
}

/* The pine badge closes the bar on the right. It is the last thing before
   the gutter, so it carries its own breathing room rather than sitting hard
   against the window edge. */
.header-badge {
  display: block;
  flex: none;
  width: 36px;
  height: 36px;
  margin-left: 4px;
  margin-right: 8px;
}

.site-nav {
  display: flex;
  gap: 32px;
  align-items: center;
  margin-left: auto;
}

.site-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  white-space: nowrap;
  font-size: var(--fs-sm);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  transition: color var(--dur-fast) ease;
}

.site-nav a:hover {
  color: var(--gold-ink);
}

.nav-item {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

/* The estimate CTA belongs to the mobile menu only — on desktop the hero and
   header already carry it. Section 13 turns it on at the nav breakpoint.
   The font-size and color are restated because `.site-nav a` out-specifies
   `.btn`/`.btn--gold` and would otherwise render this one button two pixels
   larger and in the wrong ink. */
.site-nav .nav-cta {
  display: none;
  font-size: var(--fs-label);
  color: var(--green-900);
}

.site-nav .nav-cta:hover {
  color: var(--green-900);
}

.tag {
  font-size: var(--fs-micro);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold-ink);
  border: 1px solid rgba(122, 93, 43, 0.5);
  padding: 2px 6px;
  white-space: nowrap;
}

.header-phone {
  padding-left: 32px;
  border-left: 1px solid var(--rule);
}

.header-phone__label {
  font-size: var(--fs-micro);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 2px;
}

.header-phone a {
  display: inline-flex;
  align-items: center;
  min-height: 28px;
  white-space: nowrap;
  font-size: var(--fs-md);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--ink);
  font-feature-settings: "tnum" 1;
}

.header-phone a:hover {
  color: var(--gold-ink);
}

/* Mobile nav toggle — hidden until the breakpoint. */
.nav-toggle {
  display: none;
  align-items: center;
  min-height: 44px;
  margin-left: auto;
  background: transparent;
  border: 1px solid var(--rule-strong);
  border-radius: 1px;
  padding: 11px 16px;
  font-size: var(--fs-micro);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink);
  cursor: pointer;
}

/* --------------------------------------------------------------------------
   5. Hero
   -------------------------------------------------------------------------- */
.hero {
  display: grid;
  grid-template-columns: minmax(360px, 0.86fr) 1.14fr;
  align-items: stretch;
  background: var(--green-800);
}

.hero__copy {
  min-width: 0;
  padding: 112px 72px 112px var(--bleed);
  display: flex;
  flex-direction: column;
  justify-content: center;
  color: var(--cream);
}

.hero__copy .eyebrow {
  margin-bottom: 34px;
}

.hero h1 {
  font-weight: 300;
  font-size: clamp(40px, 4.6vw, 66px);
  line-height: 1.08;
  letter-spacing: -0.005em;
}

.hero h1 em {
  font-style: italic;
  color: var(--gold-light);
  font-weight: 400;
}

.hero .rule {
  margin: 38px 0 26px;
}

.hero__sub {
  font-size: 16px;
  line-height: 1.7;
  color: rgba(247, 243, 234, 0.72);
  max-width: 34ch;
  font-weight: 300;
}

.hero__actions {
  display: flex;
  gap: 14px;
  margin-top: 46px;
  flex-wrap: wrap;
}

.hero__media {
  position: relative;
  min-width: 0;
  min-height: 600px;
  background: var(--stone);
}

.hero__media > .photo {
  position: absolute;
  inset: 0;
}

/* --------------------------------------------------------------------------
   6. Services
   -------------------------------------------------------------------------- */
.services-intro {
  padding-block: 60px 40px;
}

.services-intro > div {
  max-width: 52ch;
}

.services-intro .eyebrow {
  margin-bottom: 26px;
}

.services-intro h2 {
  font-weight: 300;
  font-size: clamp(34px, 3.4vw, 46px);
  line-height: 1.14;
}

.services-intro p {
  font-size: var(--fs-base);
  line-height: 1.8;
  color: var(--ink-muted);
  margin-top: 26px;
  max-width: 46ch;
  font-weight: 300;
}

.service {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 72px;
  align-items: center;
  padding-block: 96px;
  border-bottom: 1px solid var(--rule);
}

.service:first-of-type {
  padding-top: 0;
}

.service:last-of-type {
  border-bottom: 0;
}

/* Alternating rows put the image second in the DOM but first on screen, so
   reading order stays copy-first for screen readers. */
.service--image-left .service__media {
  order: -1;
}

/* Each row carries the aspect ratio of the photograph that sits in it, set
   per-section with --ratio. A single 4/3 frame for every row was cropping
   46% off the height of the portrait kitchen shot. The varied heights also
   give the alternating column some rhythm. */
.service__media {
  aspect-ratio: var(--ratio, 4 / 3);
  background: var(--stone);
  overflow: hidden;
  min-width: 0;
}

.service__media > .photo {
  width: 100%;
  height: 100%;
}

.service__body {
  min-width: 0;
}

.service__body .step-number {
  margin-bottom: 14px;
}

.service h3 {
  font-weight: 400;
  font-size: clamp(28px, 2.8vw, 38px);
  line-height: 1.16;
}

.service p {
  font-size: var(--fs-base);
  line-height: 1.8;
  color: var(--ink-muted);
  margin-top: 24px;
  max-width: 50ch;
  font-weight: 300;
}

.service .quote-link {
  margin-top: 22px;
}

/* --------------------------------------------------------------------------
   7. Custom projects band
   -------------------------------------------------------------------------- */
.custom-band {
  background: var(--green-800);
  color: var(--cream);
}

.custom-band__inner {
  padding-block: 104px;
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  gap: 80px;
  align-items: center;
}

.custom-band .step-number {
  color: var(--gold-light);
  margin-bottom: 14px;
}

.custom-band .step-number::after {
  background: linear-gradient(to right, var(--gold-light), rgba(195, 160, 103, 0));
}

.custom-band h3 {
  font-weight: 300;
  font-size: clamp(34px, 3.4vw, 46px);
  line-height: 1.12;
  max-width: 18ch;
}

.custom-band .rule {
  margin-top: 32px;
}

.custom-band p {
  font-size: var(--fs-md);
  line-height: 1.75;
  color: rgba(247, 243, 234, 0.86);
  max-width: 54ch;
  font-weight: 300;
}

.custom-band p span {
  color: rgba(247, 243, 234, 0.7);
  font-size: var(--fs-base);
}

.custom-band .btn {
  margin-top: 38px;
}

/* --------------------------------------------------------------------------
   8. Our Work
   -------------------------------------------------------------------------- */
.work {
  padding-block: 104px;
}

.work__head {
  max-width: 52ch;
  margin-bottom: 48px;
}

.work__head .eyebrow {
  margin-bottom: 26px;
}

.work h2 {
  font-weight: 300;
  font-size: clamp(34px, 3.4vw, 46px);
  line-height: 1.14;
}

.work__head p {
  font-size: var(--fs-base);
  line-height: 1.8;
  color: var(--ink-muted);
  margin-top: 26px;
  max-width: 50ch;
  font-weight: 300;
}

/* Editorial grid rather than four equal tiles: the before/after leads, a
   portrait sits beside it, and the second row inverts the weighting. Each
   tile's ratio matches its source file so nothing is cropped to fit. */
.work__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 22px;
}

/* The before/after owns a full row of its own. Capped in width because the
   pair is portrait — full-bleed would make it taller than the viewport and
   the handle would have nowhere useful to travel. */
.work__compare-row {
  margin-bottom: 22px;
}

.work__item--compare {
  max-width: 576px;
  margin-inline: auto;
}

.work__item {
  min-width: 0;
}

.work__item--tall,
.work__item--sq,
.work__item--wide    { grid-column: span 4; }

/* Ratios are chosen so the two tiles in each row finish at roughly the same
   height and their captions line up. Ragged caption baselines are the thing
   that makes a mixed-ratio gallery look accidental rather than composed. */
/* One ratio across all three so the captions land on a common baseline, and
   the same 4/3 box the service photography sits in. */
.work__item--tall .photo,
.work__item--sq .photo,
.work__item--wide .photo    { aspect-ratio: 4 / 3; }

.work__caption {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-top: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--rule);
}

.work__caption strong {
  font-family: var(--serif);
  font-size: 21px;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--ink);
}

.work__caption span {
  font-size: var(--fs-micro);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-faint);
  white-space: nowrap;
}

.work__more {
  margin-top: 44px;
  text-align: center;
}

/* `.services-intro p` and `.work__head p` are element-plus-class selectors,
   so they out-specify `.eyebrow` and were quietly rendering those two
   eyebrows at body size while every other eyebrow on the page sat at the
   label size. All four match now. */
.services-intro .eyebrow,
.work__head .eyebrow {
  font-size: var(--fs-label);
}

/* Before / after -----------------------------------------------------------
   The range input IS the control: it sits transparent over the frame, so a
   pointer drags it and arrow keys nudge it, and a screen reader announces a
   labelled slider rather than an unexplained pair of images. The handle is
   drawn separately and is inert to pointers. */
.compare {
  --pos: 50%;
  position: relative;
}

.compare__media {
  position: relative;
  /* Horizontal drags belong to the comparison, vertical ones to the page —
     without this a touch that starts on the photo can only scroll. */
  touch-action: pan-y;
  /* A mouse press on a photograph starts a native image drag by default,
     which pulls a ghost of the image away instead of moving the handle. */
  user-select: none;
  -webkit-user-select: none;
  isolation: isolate;
  overflow: hidden;
  /* 16/17 rather than 4/5: about 15% shorter at the same width. The pair is
     portrait, so the crop comes off the top and bottom. */
  aspect-ratio: 16 / 17;
  background: var(--stone);
  cursor: ew-resize;
}

.compare__layer {
  position: absolute;
  inset: 0;
}

.compare__layer .photo {
  width: 100%;
  height: 100%;
}

.compare__layer img {
  -webkit-user-drag: none;
  user-drag: none;
  pointer-events: none;
}

/* The "before" layer is clipped to the handle position. */
.compare__layer--before {
  clip-path: inset(0 calc(100% - var(--pos)) 0 0);
}

/* Set by scripts.js. The range stays in the DOM and in the tab order for
   keyboard and screen-reader users; pointer handling moves to the media so a
   drag can begin anywhere on the photograph rather than on the thumb alone. */
.compare--drag .compare__range {
  pointer-events: none;
}

.compare__media {
  cursor: ew-resize;
}

.compare__range {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  margin: 0;
  padding: 0;
  opacity: 0;
  cursor: ew-resize;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
}

.compare__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  z-index: 3;
  width: 2px;
  margin-left: -1px;
  background: rgba(247, 243, 234, 0.9);
  pointer-events: none;
}

.compare__grip {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 52px;
  height: 52px;
  margin: -26px 0 0 -26px;
  border-radius: 50%;
  background: var(--cream);
  box-shadow: 0 2px 18px rgba(22, 40, 31, 0.35);
  display: block;
}

/* Two chevrons, drawn from borders — no glyphs, no icon font. */
.compare__grip::before,
.compare__grip::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 8px;
  height: 8px;
  margin-top: -4px;
  border-left: 1.5px solid var(--gold-ink);
  border-bottom: 1.5px solid var(--gold-ink);
}

.compare__grip::before {
  left: 14px;
  transform: rotate(45deg);
}

.compare__grip::after {
  right: 14px;
  transform: rotate(-135deg);
}

.compare__range:focus-visible ~ .compare__handle .compare__grip {
  outline: 2px solid var(--gold-cta-hover);
  outline-offset: 4px;
}

.compare__tag {
  position: absolute;
  z-index: 3;
  top: 18px;
  font-size: var(--fs-micro);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--cream);
  background: rgba(22, 40, 31, 0.88);
  padding: 7px 12px;
  pointer-events: none;
}

.compare__tag--before { left: 18px; }
.compare__tag--after  { right: 18px; }

/* --------------------------------------------------------------------------
   9. Reviews
   -------------------------------------------------------------------------- */
.reviews {
  padding-block: 96px;
}

.reviews__panel {
  background: var(--green-900);
  color: var(--cream);
  padding: 72px 64px;
  display: grid;
  grid-template-columns: 0.82fr 1.18fr;
  gap: 64px;
  align-items: center;
  border-radius: 2px;
}

.reviews h2 {
  font-weight: 300;
  font-size: clamp(34px, 3.6vw, 48px);
  line-height: 1.1;
  max-width: 18ch;
}

.reviews .rule {
  margin: 34px 0 28px;
}

.reviews__note {
  font-size: var(--fs-micro);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(247, 243, 234, 0.62);
}

/* One column, not three. Three cards inside the right-hand panel gave each
   quote about 115px of measure — roughly eleven characters a line, with the
   longer names ("Pastor James H.") breaking across three. Stacked, each
   quote reads at a sensible width and the name/source row has room to sit
   on one line, and the panel ends up no taller than it was. */
.reviews__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

.review {
  background: var(--cream);
  color: var(--ink);
  padding: 28px 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.review__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}

.review__name {
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.02em;
}

.review__date {
  font-size: var(--fs-micro);
  color: var(--ink-faint);
  margin-top: 3px;
}

.review__source {
  font-size: var(--fs-micro);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold-ink);
}

.review__stars {
  color: var(--gold-ink);
  font-size: var(--fs-sm);
  letter-spacing: 0.28em;
}

.review p {
  font-size: var(--fs-sm);
  line-height: 1.7;
  color: var(--ink-muted);
  font-weight: 300;
}

/* --------------------------------------------------------------------------
   10. Contact + estimate wizard
   -------------------------------------------------------------------------- */
.contact {
  display: grid;
  grid-template-columns: 0.9fr 1.1fr;
  align-items: stretch;
  /* Explicit, because the page ground is what shows through the band under
     the dark column. */
  background: var(--page);
}

/* The panel is --green-800 and the footer is --green-900, and both resolve to
   the same #16281f, so the two dark blocks met with no boundary and read as one
   shape. Bottom margin only: the break is needed where the panel meets the
   footer, not on the sides. It keeps its full bleed to the page edge, which is
   what gives the copy its room. */
.contact__intro {
  min-width: 0;
  background: var(--green-800);
  color: var(--cream);
  padding: 64px 72px 64px var(--bleed);
  margin-bottom: var(--panel-inset);
}

.contact__intro .eyebrow {
  margin-bottom: 30px;
}

.contact__intro h2 {
  font-weight: 300;
  font-size: clamp(36px, 3.8vw, 52px);
  line-height: 1.1;
  max-width: 20ch;
}

.contact__intro .rule {
  margin: 38px 0 40px;
}

.contact__stat {
  border-top: 1px solid var(--rule-on-dark);
  border-bottom: 1px solid var(--rule-on-dark);
  padding: 24px 0;
}

.contact__stat strong {
  display: block;
  font-family: var(--serif);
  font-size: 38px;
  line-height: 1;
  color: var(--gold-light);
  font-weight: 400;
}

.contact__stat span {
  display: block;
  font-size: var(--fs-xs);
  line-height: 1.7;
  color: rgba(247, 243, 234, 0.75);
  margin-top: 10px;
  font-weight: 300;
  max-width: 30ch;
}

.contact__reach {
  margin: 40px 0 0;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.contact__reach dt {
  font-size: var(--fs-micro);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(247, 243, 234, 0.62);
  margin-bottom: 6px;
}

.contact__reach dd {
  margin: 0;
}

.contact__reach a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--cream);
  font-size: var(--fs-md);
  font-weight: 300;
  letter-spacing: 0.01em;
  box-shadow: inset 0 -1px 0 0 rgba(195, 160, 103, 0.5);
  word-break: break-word;
}

.contact__reach a:hover {
  color: var(--gold-light);
}

.contact__form {
  min-width: 0;
  background: var(--page);
  padding: 64px var(--bleed) 64px 72px;
}

.wizard {
  max-width: 540px;
}

.wizard__progress {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 44px;
}

.wizard__step-label {
  font-size: var(--fs-micro);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-faint);
  flex: none;
}

.wizard__track {
  flex: 1;
  height: 3px;
  background: rgba(27, 43, 35, 0.16);
  position: relative;
  display: block;
}

.wizard__fill {
  position: absolute;
  inset: 0 auto 0 0;
  height: 3px;
  background: var(--gold);
  width: 0;
  transition: width var(--dur-mid) var(--ease-out);
}

/* Steps vary in height — the choice list is ~450px, a single field is ~150px
   — so the whole section used to collapse the moment anyone answered the
   first question. Hold the tallest step's height. */
.wizard__panels {
  min-height: 430px;
}

.wizard__panel[hidden] {
  display: none;
}

/* Each step arrives rather than cutting. */
.has-js .wizard__panel:not([hidden]) {
  animation: np-step 380ms var(--ease-out) both;
}

@keyframes np-step {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

.wizard h3 {
  font-weight: 300;
  font-size: clamp(28px, 2.9vw, 38px);
  line-height: 1.16;
  margin-bottom: 34px;
  max-width: 24ch;
}

/* Choice list (step 1) */
.choices {
  display: flex;
  flex-direction: column;
  border-top: 1px solid rgba(27, 43, 35, 0.16);
}

.choice {
  border: 0;
  border-bottom: 1px solid rgba(27, 43, 35, 0.16);
  background: transparent;
  width: 100%;
  min-height: 56px;
  text-align: left;
  padding: 19px 4px;
  font-size: 16px;
  font-weight: 300;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  transition: color 160ms ease, padding-left 160ms ease, background-color 160ms ease;
}

.choice::after {
  content: "";
  width: 7px;
  height: 7px;
  flex: none;
  border-top: 1.5px solid var(--gold-ink);
  border-right: 1.5px solid var(--gold-ink);
  transform: rotate(45deg);
  transition: transform 160ms var(--ease);
}

.choice:hover {
  color: var(--gold-ink);
  padding-left: 10px;
  background-color: rgba(195, 160, 103, 0.07);
}

.choice:hover::after {
  transform: rotate(45deg) translate(2px, -2px);
}

/* Text fields */
.field {
  width: 100%;
  border: 0;
  border-bottom: 1px solid var(--rule-strong);
  background: transparent;
  padding: 12px 2px;
  font-size: 20px;
  color: var(--ink);
  font-weight: 300;
  border-radius: 0;
  transition: border-color var(--dur-fast) ease;
}

.field::placeholder {
  color: var(--ink-faint);
}

.field:focus {
  outline: none;
  border-bottom-color: var(--gold-ink);
}

.field:focus-visible {
  outline: 2px solid var(--gold-ink);
  outline-offset: 4px;
}

.field[aria-invalid="true"] {
  border-bottom-color: #8c2f21;
}

.wizard__actions {
  display: flex;
  align-items: center;
  gap: 28px;
  margin-top: 38px;
  flex-wrap: wrap;
}

.wizard__actions .btn--gold:hover {
  background: var(--gold-cta-hover);
}

.back-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  background: none;
  border: 0;
  padding: 0;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-faint);
  cursor: pointer;
  transition: color 160ms ease;
}

.back-link:hover {
  color: var(--ink);
}

.wizard__hint {
  font-size: var(--fs-xs);
  line-height: 1.7;
  color: var(--ink-muted);
  margin-top: 22px;
  max-width: 44ch;
  font-weight: 300;
}

/* Reserved so the Continue button does not jump down the moment an error
   appears — the old behaviour moved it ~30px mid-click. */
.wizard__error {
  font-size: var(--fs-xs);
  line-height: 1.6;
  color: #8c2f21;
  margin-top: 16px;
  min-height: 22px;
  font-weight: 400;
}

.wizard__error[hidden] {
  display: block;
  visibility: hidden;
}

.wizard__done p {
  font-size: var(--fs-base);
  line-height: 1.8;
  color: var(--ink-muted);
  margin-bottom: 34px;
  max-width: 46ch;
  font-weight: 300;
}

.wizard__done h3 {
  margin-bottom: 22px;
  max-width: 26ch;
}

.restart {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  background: none;
  border: 0;
  padding: 0;
  font-size: var(--fs-label);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--gold-ink);
  cursor: pointer;
  box-shadow: inset 0 -1px 0 0 rgba(122, 93, 43, 0.5);
}

.restart:hover {
  color: var(--ink);
}

.wizard__done-actions {
  display: flex;
  align-items: center;
  gap: 28px;
  flex-wrap: wrap;
  margin-bottom: 34px;
}

/* --------------------------------------------------------------------------
   11. Sticky mobile call bar
   --------------------------------------------------------------------------
   The page is roughly eleven screens tall on a phone and the header slides
   away on scroll down, taking the only phone number with it. This keeps both
   actions reachable at any depth. It hides itself over the contact section,
   where it would only duplicate what is already on screen.
   -------------------------------------------------------------------------- */
.callbar {
  position: fixed;
  z-index: 30;
  left: 0;
  right: 0;
  bottom: 0;
  display: none;
  gap: 10px;
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  background: rgba(22, 40, 31, 0.96);
  border-top: 1px solid var(--rule-on-dark);
  transform: translateY(110%);
  visibility: hidden;
  transition: transform var(--dur-mid) var(--ease), visibility 0s linear var(--dur-mid);
}

.callbar[data-visible="true"] {
  transform: none;
  visibility: visible;
  transition-delay: 0s, 0s;
}

.callbar .btn {
  flex: 1 1 0;
  min-height: 50px;
  padding-inline: 12px;
  font-size: var(--fs-micro);
  letter-spacing: 0.16em;
}

/* --------------------------------------------------------------------------
   12. Footer
   -------------------------------------------------------------------------- */
.site-footer {
  background: var(--green-900);
  color: rgba(247, 243, 234, 0.7);
}

.site-footer__inner {
  padding-block: 56px 12px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  column-gap: 48px;
  row-gap: 10px;
  flex-wrap: wrap;
}

.footer-details {
  display: flex;
  /* 48 rather than 56: at the shared size the three columns plus the lockup
     overran the shell by a few pixels, which dropped the details to a second
     row and undid the logo alignment. */
  gap: 48px;
  align-items: flex-start;
  flex-wrap: wrap;
}

.footer-details dt {
  font-size: var(--fs-micro);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: rgba(247, 243, 234, 0.62);
  margin-bottom: 6px;
}

/* One treatment across all three values. The phone set the tone, so the
   email and the service area now match it rather than each other. The 44px
   box is shared too: it used to sit on the two links only, which floated the
   plain Service Area text above its neighbours. */
.footer-details dd {
  display: flex;
  align-items: center;
  min-height: 44px;
  margin: 0;
  font-size: 18px;
  line-height: 1.45;
  color: var(--cream);
  font-weight: 400;
  letter-spacing: 0.01em;
}

.footer-details a {
  color: var(--cream);
}

.footer-details a:hover {
  color: var(--gold-light);
}

.footer-details .footer-phone {
  font-feature-settings: "tnum" 1;
}

.footer-details .footer-email {
  word-break: break-word;
}

/* Both values are links and neither is inside running text, so the shared
   underline is what marks them as clickable — colour alone would not.
   text-decoration rather than an inset shadow, because the shadow tracks the
   box and the box has to grow: the dd carried the 44px tap target while the
   anchor inside it was 23px tall, which is what a finger actually hits. */
.footer-details dd a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  text-decoration: underline;
  text-decoration-color: rgba(195, 160, 103, 0.5);
  text-decoration-thickness: 1px;
  text-underline-offset: 5px;
}

/* The pine takes a row of its own beneath the details. Centred on the
   details block rather than on the shell, which on desktop puts it under the
   email column; the shell runs wider than the content does. */
.footer-mark {
  flex-basis: 100%;
  display: flex;
  justify-content: center;
}

.footer-mark img {
  display: block;
  width: 36px;
  height: 36px;
}

.site-footer__legal {
  border-top: 1px solid rgba(247, 243, 234, 0.12);
  font-size: var(--fs-xs);
  color: rgba(247, 243, 234, 0.62);
  padding-block: 22px;
  font-weight: 300;
}

/* --------------------------------------------------------------------------
   13. Responsive
   -------------------------------------------------------------------------- */

/* Tablet / small laptop: collapse the desktop nav into a toggle. */
@media (max-width: 1080px) {
  /* One compact row: logo, phone, menu button. The nav unfolds beneath it.
     The header is sticky, so every pixel here is taken off the phone screen. */
  .site-header__inner {
    flex-wrap: wrap;
    gap: 16px;
    padding-block: 12px;
  }

  .brand img {
    height: 46px;
  }

  .nav-toggle {
    display: inline-flex;
    order: 3;
    margin-left: 0;
  }

  /* The compact bar is the lockup and the button. A second mark beside them
     would spend the height we just took back. */
  .header-badge {
    display: none;
  }

  /* The phone leaves the header row and becomes the last item in the menu,
     so the bar carries only the lockup and the button. It is still the
     first thing in the panel's tab order after the links. */
  .header-phone {
    display: none;
    order: 5;
    width: 100%;
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--rule);
    padding-top: 4px;
  }

  .site-header[data-nav-open="true"] .header-phone {
    display: block;
  }

  .nav-toggle {
    margin-left: auto;
  }

  .header-phone__label {
    display: block;
    padding-top: 12px;
  }

  .header-phone a {
    min-height: 44px;
    font-size: var(--fs-md);
  }

  .site-nav {
    display: none;
    order: 4;
    width: 100%;
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    margin-left: 0;
    border-top: 1px solid var(--rule);
    padding-top: 8px;
  }

  .site-nav[data-open="true"] {
    display: flex;
  }

  .site-nav > a,
  .site-nav .nav-item {
    width: 100%;
    padding: 16px 0;
    border-bottom: 1px solid var(--rule);
  }

  /* The menu had five links and no way to act from any of them. */
  .site-nav .nav-cta {
    display: inline-flex;
    width: 100%;
    margin: 16px 0 4px;
    padding-block: 15px;
    border-bottom: 0;
  }
}

/* Between the desktop bar and the toggle breakpoint the row carries the
   lockup, the switcher, five links, the phone and the badge. Tighten the
   spacing so nothing wraps. */
@media (max-width: 1240px) {
  .site-header__inner {
    gap: 20px;
  }

  .site-nav {
    gap: 20px;
  }

  .header-phone {
    padding-left: 20px;
  }

  .header-badge {
    margin-left: 0;
    margin-right: 4px;
  }
}

/* The gallery loses its 12-column composition before the split layouts do —
   below this the feature and the portrait would both be too narrow to read. */
@media (max-width: 1080px) {
  .work__item--tall,
  .work__item--sq,
  .work__item--wide {
    grid-column: span 6;
  }
}

/* Stack the split layouts. */
@media (max-width: 960px) {
  .hero {
    grid-template-columns: 1fr;
  }

  .hero__copy {
    padding: 72px var(--gutter) 64px;
  }

  /* min-height must go to 0 here: combined with aspect-ratio it would set a
     min *width* of height x 4/3 and push the whole page wider than the phone. */
  .hero__media {
    min-height: 0;
    aspect-ratio: 4 / 3;
  }

  .service,
  .custom-band__inner,
  .contact,
  .reviews__panel {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  .service {
    padding-block: 64px;
  }

  /* On one column the image should sit above the copy in every row. */
  .service .service__media {
    order: -1;
  }

  .custom-band__inner {
    padding-block: 72px;
  }

  .contact__intro,
  .contact__form {
    padding: 64px var(--gutter);
  }

  /* Stacked, the white form column is what sits above the footer, so the two
     greens never meet and the band has nothing to separate. The 40px grid gap
     already spaces the panel off the form. */
  .contact__intro {
    margin-bottom: 0;
  }

  .reviews__panel {
    padding: 48px 32px;
  }

  .work {
    padding-block: 72px;
  }

  .wizard__panels {
    min-height: 0;
  }
}

/* Phones */
@media (max-width: 620px) {
  :root {
    --gutter: 22px;
    --fs-base: 16px;
    --fs-sm: 15px;
  }

  /* Shrink the lockup so the logo, phone, and menu button share one row. */
  .brand img {
    height: 40px;
  }

  .header-phone a {
    font-size: var(--fs-sm);
  }

  .nav-toggle {
    padding: 9px 12px;
    font-size: var(--fs-micro);
  }

  .services-intro {
    padding-block: 40px 24px;
  }

  .service {
    padding-block: 48px;
    gap: 32px;
  }

  .hero__copy {
    padding-block: 56px 52px;
  }

  .hero__actions {
    gap: 12px;
  }

  .hero__actions .btn {
    flex: 1 1 100%;
  }

  .work,
  .reviews {
    padding-block: 64px;
  }

  .work__grid {
    gap: 16px;
  }

  /* A 53px lockup in a one-column footer dwarfs everything under it. */
  .footer-logo {
    height: 34px;
    margin-top: 0;
  }

  /* 16px is the largest size the email still fits on one line at 375px.
     Above it the address breaks mid-word, which looks like a typo. All
     three values move together so they stay a set. */
  .footer-details dd {
    font-size: 16px;
  }

  .work__item--tall,
  .work__item--sq,
  .work__item--wide {
    grid-column: span 12;
  }

  .compare__grip {
    width: 44px;
    height: 44px;
    margin: -22px 0 0 -22px;
  }

  .compare__tag {
    top: 12px;
  }

  .compare__tag--before { left: 12px; }
  .compare__tag--after  { right: 12px; }

  .work__caption strong {
    font-size: 19px;
  }

  .contact__intro,
  .contact__form {
    padding-block: 52px;
  }

  .footer-details {
    gap: 32px;
  }

  .wizard__actions .btn {
    width: 100%;
  }
}


/* The call bar owns the bottom of the screen below this width, so the last
   line of the footer needs to clear it. */
@media (max-width: 860px) {
  .callbar {
    display: flex;
  }

  .site-footer__legal {
    padding-bottom: calc(22px + 72px + env(safe-area-inset-bottom));
  }
}

/* --------------------------------------------------------------------------
   14. Motion preferences + print
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }

  /* Belt and braces: whatever the script does or fails to do, nothing that
     carries content is left hidden or displaced. */
  .has-js [data-reveal],
  .has-js [data-reveal].is-in,
  .has-js .hero__copy > * {
    opacity: 1 !important;
    transform: none !important;
  }

  .has-js [data-reveal="media"] > img,
  .has-js [data-reveal="media"] .photo > img,
  .has-js .hero__media > .photo > img {
    transform: none !important;
  }

  /* Never slide the header out from under a reduced-motion user. */
  .site-header {
    position: static;
  }

  .site-header[data-hidden="true"] {
    transform: none;
  }
}

@media print {
  .site-header,
  .nav-toggle,
  .callbar,
  .wizard,
  .compare__range,
  .compare__handle {
    display: none;
  }

  body {
    background: #fff;
  }

  /* Filters and blend modes cost ink and gain nothing on paper. */
  .photo::before,
  .photo::after {
    display: none;
  }

  .photo > img {
    filter: none;
  }

  .has-js [data-reveal],
  .has-js .hero__copy > * {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* --------------------------------------------------------------------------
   12. Lightbox

   Click a gallery photo and it opens over a blurred page, matted in white so
   it reads as its own viewing window. Arrows step through the set; Escape or
   a click on the scrim closes it. The whole thing is inert until scripts.js
   removes [hidden], so a blocked script costs the gallery nothing.
   -------------------------------------------------------------------------- */
.lightbox[hidden] {
  display: none;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: clamp(16px, 5vw, 56px);
}

.lightbox__scrim {
  position: absolute;
  inset: 0;
  background: rgba(22, 40, 31, 0.55);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.lightbox__dialog {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  max-width: min(1100px, 100%);
  max-height: 100%;
}

/* The 10px mat. box-sizing keeps it outside the picture rather than eating
   into it. */
.lightbox__frame {
  margin: 0;
  border: 10px solid #fff;
  background: #fff;
  box-shadow: 0 24px 70px rgba(10, 20, 15, 0.45);
  max-height: calc(100vh - 150px);
  display: flex;
}

.lightbox__img {
  display: block;
  max-width: 100%;
  max-height: calc(100vh - 170px);
  width: auto;
  height: auto;
  object-fit: contain;
}

.lightbox__caption {
  margin: 0;
  color: var(--cream);
  font-size: var(--fs-label);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-align: center;
}

.lightbox__btn {
  position: absolute;
  top: 50%;
  width: 52px;
  height: 52px;
  margin-top: -26px;
  border: 0;
  border-radius: 50%;
  background: var(--cream);
  box-shadow: 0 2px 18px rgba(22, 40, 31, 0.35);
  cursor: pointer;
}

.lightbox__btn--prev { left: -26px; }
.lightbox__btn--next { right: -26px; }

/* Chevrons drawn from borders — same construction as the compare grip, no
   glyphs and no icon font. */
.lightbox__btn::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 10px;
  height: 10px;
  border-left: 1.5px solid var(--gold-ink);
  border-bottom: 1.5px solid var(--gold-ink);
}

.lightbox__btn--prev::before {
  margin: -5px 0 0 -3px;
  transform: rotate(45deg);
}

.lightbox__btn--next::before {
  margin: -5px 0 0 -8px;
  transform: rotate(-135deg);
}

.lightbox__btn:hover {
  background: #fff;
}

.lightbox__close {
  position: absolute;
  top: -42px;
  right: 0;
  border: 0;
  background: transparent;
  color: var(--cream);
  font-size: var(--fs-micro);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 8px 4px;
}

.lightbox :focus-visible {
  outline: 2px solid var(--gold-cta-hover);
  outline-offset: 3px;
}

/* The gallery photo is a button now; strip the button chrome so it looks
   exactly like the framed photo it replaced. */
.photo--zoom {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: zoom-in;
}

@media (max-width: 700px) {
  .lightbox__btn--prev { left: 4px; }
  .lightbox__btn--next { right: 4px; }

  .lightbox__frame {
    border-width: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .lightbox__scrim {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    background: rgba(22, 40, 31, 0.9);
  }
}
