@import url('tokens.css?v=430d6322');
@import url('../assets/fonts/fonts.css?v=491636cf');

/* ============================================================
   1. BASE
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--plaster);
  color: var(--text);
  font-family: var(--f-body);
  font-size: var(--t-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  font-family: var(--f-display);
  font-weight: 800;
  line-height: .98;
  letter-spacing: -.025em;
  margin: 0;
  text-wrap: balance;
}
h1 { font-size: var(--t-hero); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); font-weight: 700; line-height: 1.15; letter-spacing: -.015em; }
p  { margin: 0 0 var(--s2); max-width: var(--maxw-text); text-wrap: pretty; }
a  { color: inherit; }
img, svg, video { display: block; max-width: 100%; height: auto; }
ul, ol { margin: 0; padding: 0; list-style: none; }

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

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--ink); color: var(--plaster); padding: var(--s2) var(--s3);
}
.skip:focus { left: 0; }

.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gutter); }
.wrap--narrow { max-width: 920px; }

.eyebrow {
  font-family: var(--f-display);
  font-weight: 500;
  font-size: var(--t-eyebrow);
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold-3);
  margin: 0 0 var(--s2);
  display: flex; align-items: center; gap: var(--s2);
}
.eyebrow::before {
  content: ''; width: 28px; height: 1px; background: currentColor; flex: none;
}
/* Centred, a single leading rule reads as a stray dash floating beside the label.
   Mirror it so the label sits inside a pair of rules instead. */
/* `justify-content` centres the flex LINE inside the box, but the box itself was
   still a full-width block starting at the left gutter -- which is why the label
   looked off-centre against the heading below it. It needs to shrink to its
   content and centre as a block. */
.eyebrow--center {
  justify-content: center; margin-bottom: var(--s1);
  width: fit-content; margin-inline: auto;
}
.eyebrow--center::after {
  content: ''; width: 28px; height: 1px; background: currentColor; flex: none;
}
/* GRADIENT ON DARK, SOLID ON LIGHT -- see section 1b. The eyebrow inherits its
   colour into the ::before/::after rules via currentColor, so on dark we cannot
   simply background-clip the <p> (that would erase the rules too). The text gets
   its own span-less treatment: clip the gradient to the text only, and repaint
   the hairlines with a solid gold. */
.on-dark .eyebrow, .sec--dark .eyebrow, .foot h4 {
  background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.on-dark .eyebrow::before, .sec--dark .eyebrow::before,
.on-dark .eyebrow::after,  .sec--dark .eyebrow::after { background: var(--gold-2); }
@media (forced-colors: active) {
  .on-dark .eyebrow, .sec--dark .eyebrow, .foot h4 { background: none; color: CanvasText; }
}

.lead { font-size: var(--t-lead); line-height: 1.55; color: var(--text-soft); }
.sec--dark .lead { color: var(--text-invert-soft); }

/* ---- curved section overlaps -------------------------------------------
   Every band after the hero pulls itself up over the one before it with a
   negative top margin and a large top radius, so section changes read as
   smooth curved overlaps instead of flat cutoffs. Sections paint in DOM
   order, so each one naturally covers the bottom edge of its predecessor.
   Same idea as the portfolio's SectionShell.

   Each band MUST declare its own background -- without one the curve reveals
   whatever is behind the page rather than the previous section. That is why
   plain `.sec` now sets `--plaster` explicitly; it used to inherit from body. */
.sec, .award, .trust, .proof, .marquee, .foot, .phead + .sec {
  position: relative;
  border-top-left-radius:  var(--radius-section);
  border-top-right-radius: var(--radius-section);
}
.sec + .sec, .award, .trust, .proof, .marquee, .foot,
.sec--dark, .sec--tint, .trust + .sec, .phead + .sec {
  margin-top: calc(var(--section-lift) * -1);
}
/* anchors must not land under the fixed nav */
.sec, .award, .trust, .proof { scroll-margin-top: calc(var(--nav-h) + var(--s2)); }

/* Top and bottom padding are the derived --section-pt / --section-pb, never a
   raw --section-y. The bottom one carries the lift the NEXT band is about to
   take out of it, which is the only reason the rhythm reads as even. */
.sec { padding-block: var(--section-pt) var(--section-pb); background: var(--plaster); }
.sec--dark { background: var(--ink); color: var(--text-invert); }
.sec--tint { background: var(--plaster-2); }

/* The hero is full-bleed and pinned; it is the one band that is never lifted
   and never rounded. The section AFTER it does the curving, over the top. */
.hero { border-radius: 0; margin-top: 0; }

/* grain */
.grain {
  position: fixed; inset: 0; z-index: 900; pointer-events: none; opacity: .34;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.45'/%3E%3C/svg%3E");
}

/* scroll progress hairline */
.progress {
  position: fixed; top: 0; left: 0; height: 2px; width: 100%;
  transform: scaleX(0); transform-origin: 0 50%;
  background: var(--gold-2); z-index: 950; pointer-events: none;
}

/* ============================================================
   1b. GOLD SYSTEM
   Ported from the Cleverstack portfolio. Two hard rules:

   1. GRADIENT ON DARK, SOLID ON LIGHT. .gold-text only ever goes on ink;
      on plaster use solid var(--gold-3). A gradient clipped to text on a
      light ground goes muddy and drops below contrast.
   2. NEVER ANIMATE box-shadow. A glow that pulses lives on its own
      absolutely-positioned layer animated on OPACITY, which the compositor
      can handle. Animating box-shadow repaints every frame, forever --
      the portfolio's CSS records this as a real source of jank.
   ============================================================ */
.gold-text {
  background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
/* Windows High Contrast drops backgrounds, and this class paints its glyphs
   THROUGH one -- so `color: transparent` would leave the text invisible. */
@media (forced-colors: active) {
  .gold-text { background: none; color: CanvasText; }
}

/* --- media corners -------------------------------------------------------
   Every photograph on the site is rounded to --radius-card, so the images and
   the curved section overlaps read as one radius language. Two deliberate
   exceptions: the hero (its plate and cut-out layers share one coordinate
   space and must stay full-bleed edge to edge) and the award medallion (an
   alpha cut-out -- there is no rectangle there to round). ---------------- */
.proof__media,
.ba__frame,
.gal__item,
.video__frame,
.svc-detail__media,
.about-grid__media img,
.contact-grid aside picture img,
.lb img { border-radius: var(--radius-card); }
/* Safari has never reliably clipped an iframe to an ancestor's radius, so the
   frame's radius is restated on the iframe itself rather than trusting the
   parent's overflow:hidden. This is what rounds the Vimeo player. */
.video__frame iframe,
.video__poster { border-radius: inherit; }
.drop__thumb { border-radius: calc(var(--radius-card) * .4); }

/* Hairline gold gradient border, via the padding-box/border-box trick. */
.gold-ring {
  position: relative;
  background:
    linear-gradient(var(--ring-fill, var(--ink)), var(--ring-fill, var(--ink))) padding-box,
    linear-gradient(120deg, rgba(245,231,193,.9), rgba(212,175,55,.6) 50%, rgba(245,231,193,.9)) border-box;
  border: 1px solid transparent;
}
/* On light surfaces pale champagne reads as nothing, so the ring goes deep and
   picks up a soft drop shadow to lift it off the plaster. */
.gold-ring-dark {
  background:
    linear-gradient(var(--ring-fill, var(--plaster)), var(--ring-fill, var(--plaster))) padding-box,
    linear-gradient(120deg, rgba(212,175,55,.95), rgba(122,96,26,.85) 50%, rgba(212,175,55,.95)) border-box;
  border: 1.5px solid transparent;
  box-shadow: 0 4px 18px -4px rgba(122,96,26,.35);
}

/* The pulsing glow. Decorative and pointer-events:none so it can never swallow
   a click on the control underneath it. */
.gold-halo {
  pointer-events: none;
  box-shadow: 0 0 10px 1px rgba(212,175,55,.4), 0 0 26px 4px rgba(212,175,55,.25);
  animation: halo-pulse 2.8s ease-in-out infinite;
  will-change: opacity;
}
@keyframes halo-pulse {
  0%, 100% { opacity: .4; }
  50%      { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .gold-halo { animation: none; opacity: .55; }
}

/* ============================================================
   2. BUTTONS
   ============================================================ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .6em;
  font-family: var(--f-display); font-weight: 700; font-size: .95rem;
  letter-spacing: .01em;
  padding: 1.05em 1.9em;
  border: 1px solid transparent; border-radius: 999px;
  text-decoration: none; cursor: pointer;
  transition: background var(--dur) var(--ease-out), color var(--dur) var(--ease-out),
              border-color var(--dur) var(--ease-out), transform .25s var(--ease-out);
  will-change: transform;
}
/* --- brass/primary: gold gradient fill, with a pulsing halo on dark ------- */
.btn--brass {
  background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
  color: var(--ink);
  position: relative; isolation: isolate;
}
.btn--brass:hover { transform: translateY(-2px); }
.btn--brass:active { transform: translateY(0); }

/* --- ghost: gold ring outline that FILLS FROM THE BOTTOM on hover and drains
   again on leave. The fill is a child layer scaled on Y, so only transform
   animates. ------------------------------------------------------------- */
.btn--ghost {
  border-color: var(--rule); color: var(--text);
  position: relative; overflow: hidden; isolation: isolate;
}
.btn--ghost::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--ink);
  transform: scaleY(0); transform-origin: 50% 100%;
  transition: transform .45s var(--ease-snap);
}
.btn--ghost:hover { border-color: var(--ink); color: var(--plaster); }
.btn--ghost:hover::before { transform: scaleY(1); }

/* On ink the ghost becomes the portfolio's gold-ring pill: gradient hairline
   border, gold gradient filling up from the bottom, text flipping to ink. */
.on-dark .btn--ghost, .sec--dark .btn--ghost, .foot .btn--ghost {
  border: 1px solid transparent;
  background:
    linear-gradient(var(--ink), var(--ink)) padding-box,
    linear-gradient(120deg, rgba(245,231,193,.9), rgba(212,175,55,.6) 50%, rgba(245,231,193,.9)) border-box;
  color: var(--gold-1);
}
.on-dark .btn--ghost::before, .sec--dark .btn--ghost::before, .foot .btn--ghost::before {
  background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
}
.on-dark .btn--ghost:hover, .sec--dark .btn--ghost:hover, .foot .btn--ghost:hover {
  color: var(--ink);
}

/* The halo is a SIBLING layer, not a box-shadow transition -- see the note in
   section 1b. Markup: <a class="btn btn--brass"><span class="btn__halo"></span>…
   It is added by JS so a no-JS render is a plain button. */
.btn__halo {
  position: absolute; inset: 0; border-radius: inherit; z-index: -1;
  pointer-events: none;
  box-shadow: 0 0 10px 1px rgba(212,175,55,.4), 0 0 26px 4px rgba(212,175,55,.25);
  animation: halo-pulse 2.8s ease-in-out infinite;
  will-change: opacity;
}
@media (prefers-reduced-motion: reduce) {
  .btn__halo { animation: none; opacity: .55; }
  .btn--brass:hover { transform: none; }
  .btn--ghost::before { transition: none; }
}

.btn__ico { width: 1em; height: 1em; }

/* --- button rows ---------------------------------------------------------
   This had NO base rule, which caused two visible bugs at once. The buttons
   are inline-flex, so a row of them was held apart by nothing but one
   collapsed text space -- they looked glued together. And several rows are
   marked up as <p style="justify-content:center">, which does nothing at all
   on a non-flex box; worse, the base `p` rule caps them at --maxw-text, so a
   "centred" row was really centred inside a 68ch column sitting on the left.
   Making the row a real flex container fixes both. --------------------- */
.btn-row {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--s2);
  max-width: none; margin-bottom: 0;
}
.btn-row > .btn { flex: 0 0 auto; }
/* Below 480px a two-button row of full-width pills reads better stacked than
   squeezed, and 44px touch targets must not end up shoulder to shoulder. */
@media (max-width: 479px) {
  .btn-row { flex-direction: column; align-items: stretch; gap: var(--s2); }
  .btn-row > .btn { width: 100%; }
}

/* ============================================================
   3. NAV — hidden over the hero, slides in when the hero releases
   ============================================================ */
/* Dark glass on every page, matching the portfolio. Was light plaster and went
   dark only over the hero; Palmer wanted the darker treatment throughout. */
.nav {
  position: fixed; inset-inline: 0; top: 0; z-index: 800;
  height: var(--nav-h);
  display: flex; align-items: center;
  background: rgba(10,10,12,.72);
  backdrop-filter: saturate(1.4) blur(16px);
  -webkit-backdrop-filter: saturate(1.4) blur(16px);
  border-bottom: 1px solid rgba(212,175,55,.16);
  color: var(--plaster);
  transform: translateY(-100%);
}
.nav a, .nav .brand { color: var(--plaster); }
.nav__links a { color: rgba(245,242,237,.66); transition: color .3s var(--ease-out); }
.nav__links a:hover, .nav__links a[aria-current="page"] { color: var(--gold-1); }
.nav__tel { color: var(--plaster); }
.nav__tel:hover { color: var(--gold-1); }
.nav.is-visible { transform: translateY(0); }
.nav__inner {
  width: 100%; max-width: var(--maxw); margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex; align-items: center; gap: var(--s3);
}
.brand {
  font-family: var(--f-display); font-weight: 800; font-size: 1.32rem;
  letter-spacing: -.02em; text-decoration: none; line-height: 1;
  display: flex; align-items: baseline; gap: .5rem; margin-right: auto;
}
.brand__mk { letter-spacing: -.04em; }
.brand__dot {
  background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
@media (forced-colors: active) { .brand__dot { background: none; color: CanvasText; } }
.brand__sub {
  font-family: var(--f-body); font-weight: 500; font-size: .68rem;
  letter-spacing: .16em; text-transform: uppercase; color: var(--text-soft);
}
.nav__links { display: flex; gap: var(--s3); align-items: center; }
.nav__links a {
  font-family: var(--f-display); font-weight: 500; font-size: .93rem;
  text-decoration: none; padding: .4rem 0; position: relative;
}
/* "Tubelight": the underline is a gold bar with a soft bloom above it, the same
   idea as the portfolio's active tab lamp reduced to a single hairline. */
.nav__links a::after {
  content: ''; position: absolute; left: 0; right: 100%; bottom: 0; height: 2px;
  border-radius: 2px 2px 0 0;
  background: linear-gradient(90deg, var(--gold-2), var(--gold-1), var(--gold-2));
  box-shadow: 0 -4px 12px rgba(212,175,55,.55), 0 -1px 4px rgba(245,231,193,.7);
  transition: right .35s var(--ease-out);
}
.nav__links a:hover::after, .nav__links a[aria-current="page"]::after { right: 0; }
.nav__tel {
  font-family: var(--f-display); font-weight: 700; text-decoration: none;
  white-space: nowrap;
}
.nav__cta {
  padding: .7em 1.3em; font-size: .88rem;
  position: relative; overflow: hidden; isolation: isolate;
  border: 1px solid transparent;
  background:
    linear-gradient(#111009, #111009) padding-box,
    linear-gradient(120deg, rgba(245,231,193,.9), rgba(212,175,55,.6) 50%, rgba(245,231,193,.9)) border-box;
  color: var(--gold-1) !important;
}
.nav__cta::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
  transform: scaleY(0); transform-origin: 50% 100%;
  transition: transform .35s var(--ease-snap);
}
.nav__cta:hover { color: var(--ink) !important; }
.nav__cta:hover::before { transform: scaleY(1); }
@media (prefers-reduced-motion: reduce) { .nav__cta::before { transition: none; } }

.nav__burger { display: none; }

/* mobile menu uses <details> so it works with JS off */
.menu { display: none; }

@media (max-width: 900px) {
  .nav__links, .nav__tel, .brand__sub { display: none; }
  .menu { display: block; margin-left: auto; }
  .menu > summary {
    list-style: none; cursor: pointer; padding: .6rem; margin: -.6rem;
    display: flex; align-items: center; gap: .5rem;
    font-family: var(--f-display); font-weight: 700; font-size: .9rem;
  }
  .menu > summary::-webkit-details-marker { display: none; }
  .menu__bars { width: 22px; height: 12px; position: relative; }
  .menu__bars::before, .menu__bars::after {
    content: ''; position: absolute; left: 0; right: 0; height: 1.5px; background: currentColor;
    transition: transform .3s var(--ease-out);
  }
  .menu__bars::before { top: 0; } .menu__bars::after { bottom: 0; }
  .menu[open] .menu__bars::before { transform: translateY(5px) rotate(45deg); }
  .menu[open] .menu__bars::after  { transform: translateY(-5px) rotate(-45deg); }
  /* .nav has a transform and a backdrop-filter, both of which make it the
     containing block for fixed children — so position the panel against it. */
  .menu__panel {
    position: absolute; top: 100%; left: 0; right: 0;
    height: calc(100svh - var(--nav-h)); background: var(--ink);
    padding: var(--s4) var(--gutter) var(--s6);
    display: flex; flex-direction: column; gap: var(--s1);
    overflow-y: auto;
  }
  /* Gradient lettering on ink -- the sanctioned direction (gradient on dark,
     solid on light). The border-bottom is unaffected: background-clip:text
     clips the BACKGROUND to the glyphs, it does not clip borders. */
  .menu__panel a {
    font-family: var(--f-display); font-weight: 700;
    font-size: clamp(1.6rem, 7vw, 2.2rem); text-decoration: none;
    padding: .45em 0; border-bottom: 1px solid var(--rule-invert);
    background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;
  }
  /* Hover must NOT set a solid `color` -- that would paint over the clipped
     gradient and flip the link from gradient to flat mid-interaction. Shift the
     whole gradient's brightness instead. */
  .menu__panel a:hover { filter: brightness(1.18); }
  .menu__panel .btn { margin-top: var(--s3); }
  /* `.menu__panel a` (0,1,1) outranks `.btn--brass` (0,1,0), so the call pill
     inherited the panel's link colour and rendered near-WHITE text on the gold
     gradient. This wins at (0,2,0) and restores black-on-gold. It also has to
     undo the clip, or the pill's own gradient fill would be clipped to its text. */
  .menu__panel .btn--brass {
    color: var(--ink);
    -webkit-background-clip: border-box;
            background-clip: border-box;
  }
  .menu__panel .btn--brass:hover { filter: none; }
  @media (forced-colors: active) {
    .menu__panel a { background: none; color: CanvasText; }
  }
}

/* Narrow phones: the sticky call bar carries the CTA, so the nav keeps only
   the wordmark and the menu. */
@media (max-width: 520px) {
  .nav__cta { display: none; }
  .brand { font-size: 1.2rem; }
}

/* ============================================================
   4. HERO — full-bleed camera plate
   One plate holds the master photograph AND every cut-out in a
   single coordinate space, so the layers can never drift off the
   image. The plate is the ONLY transformed element: it carries the
   camera dolly, and every layer inherits it for free.

   Two masters, switched on ASPECT RATIO (not width): 16:9 for
   landscape viewports, 3:4 for portrait. Cover behaviour is a
   function of aspect ratio alone; copy layout is a function of
   width alone. Keeping those axes separate is what stops iPad
   portrait and landscape phones from becoming special cases.

   Layer positions are generated from the measured quads — run
   brand/sync_hero_css.py, never hand-edit the block below.
   ============================================================ */

/* HERO:VARS:BEGIN — generated by brand/sync_hero_css.py, do not hand-edit */
.hero {
  --ar-w: 16; --ar-h: 9;
  --cam-x: 50%; --cam-y: 39.925%; --cam-start: 1.40;
  --gl-x: 11.994%; --gl-y: 1.986%; --gl-w: 77.989%;
  --br-x: 40.579%; --br-y: 31.803%; --br-w: 19.227%;
  --tv-x: 34.151%; --tv-y: 23.307%; --tv-w: 31.734%;
  --sb-x: 38.253%; --sb-y: 63.574%; --sb-w: 27.925%;
  --pr-x: 23.494%; --pr-y: 50.977%; --pr-w: 54.001%;
}
@media (max-aspect-ratio: 9/10) {
  .hero {
    --ar-w: 3; --ar-h: 4;
    --cam-x: 50%; --cam-y: 44.675%; --cam-start: 1.22;
    --gl-x: 1.981%; --gl-y: 9.981%; --gl-w: 96.010%;
    --br-x: 34.459%; --br-y: 40.134%; --br-w: 35.575%;
    --tv-x: 23.940%; --tv-y: 33.145%; --tv-w: 52.232%;
    --sb-x: 40.904%; --sb-y: 63.967%; --sb-w: 25.781%;
    --pr-x: 6.975%; --pr-y: 54.488%; --pr-w: 87.500%;
  }
}
/* HERO:VARS:END */

/* The plate is sized against the LARGE viewport so that when the iOS URL bar
   collapses and the visual viewport grows, the plate is already big enough to
   cover it — no letterbox, no reflow. */
:root { --hero-vh: 100vh; }
@supports (height: 100lvh) { :root { --hero-vh: 100lvh; } }

.hero {
  position: relative;
  isolation: isolate;
  height: 100svh;              /* layout height = SMALL viewport, so copy always fits */
  overflow: hidden;
  background: var(--ink);
  color: var(--text-invert);
  display: grid;
  align-items: center;
}

/* --- the plate: one coordinate space for the photograph and every cut-out --- */
/* A centring frame that is NEVER transformed. Grid centring rather than a
   translate matters: it leaves the plate's transform entirely to GSAP, so the
   camera scale can't compound with a centring translate. */
.hero__stage {
  position: absolute; inset: 0; z-index: 0;
  display: grid; place-items: center;
  overflow: hidden;
}
.hero__plate {
  position: relative;
  /* Cover, without object-fit. Width resolves to max(viewport, height x ratio),
     and aspect-ratio then makes the height >= the viewport in both branches. */
  width: max(100%, calc(var(--hero-vh) * var(--ar-w) / var(--ar-h)));
  aspect-ratio: var(--ar-w) / var(--ar-h);
  height: auto;
  transform-origin: var(--cam-x) var(--cam-y);
  backface-visibility: hidden;
  /* no transform at rest — the resting state IS the final frame */
}
/* Only with JS do we start zoomed in, so a no-JS render is never mid-animation. */
.js .hero__plate { transform: scale(var(--cam-start)); }

/* The box already carries the master's ratio, so the image fills it 1:1.
   `fill` (not `cover`) means a one-pixel export error degrades to a sub-pixel
   stretch instead of a crop — registration survives a rounding mistake. */
.hero__base {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: fill; z-index: 1;
}

/* cut-outs, positioned in % of the plate */
.hero__layer { position: absolute; height: auto; }
/* Stacking order matters more than it looks. Nothing here physically overlaps
   — the books sit left of the soundbar, the vases right of it, and none of them
   reach the TV. But a difference matte always carries faint drift, so whichever
   layer sits on top paints its ghosting onto the ones below. Putting the props
   UNDER the TV and the soundbar hides that ghosting behind solid objects, which
   is why no part of the props matte has to be cut away. */
.hero__glow     { left: var(--gl-x); top: var(--gl-y); width: var(--gl-w); z-index: 2; }
.hero__bracket  { left: var(--br-x); top: var(--br-y); width: var(--br-w); z-index: 3; }
.hero__props    { left: var(--pr-x); top: var(--pr-y); width: var(--pr-w); z-index: 5; }
.hero__tv       { left: var(--tv-x); top: var(--tv-y); width: var(--tv-w); z-index: 6; }
.hero__soundbar { left: var(--sb-x); top: var(--sb-y); width: var(--sb-w); z-index: 7; }

/* structural x-ray + the cable, drawn in the master's own pixel space */
.hero__gfx {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 4; overflow: visible; pointer-events: none;
}
.hero__gfx--top { z-index: 8; }
/* one x-ray per master; only the active orientation's pair is in play */
.hero__gfx--p { display: none; }
@media (max-aspect-ratio: 9/10) {
  .hero__gfx--l { display: none; }
  .hero__gfx--p { display: block; }
}

/* --- the scrim: a SIBLING of the plate, so it never moves with the camera.
   As the dolly pulls back and different marble slides under the headline, the
   guaranteed contrast floor stays exactly where it is. --- */
.hero__scrim {
  position: absolute; inset: 0; z-index: 9; pointer-events: none;
  background:
    linear-gradient(100deg,
      rgba(8,8,10,.92)  0%,
      rgba(8,8,10,.80) 26%,
      rgba(8,8,10,.36) 52%,
      rgba(8,8,10,0)   76%),
    linear-gradient(to bottom, rgba(8,8,10,.55) 0%, rgba(8,8,10,0) 18%),
    linear-gradient(to top,    rgba(8,8,10,.55) 0%, rgba(8,8,10,0) 22%);
}

/* --- copy --- */
.hero__inner {
  position: relative; z-index: 10;
  width: 100%; max-width: var(--maxw); margin-inline: auto;
  padding: var(--s6) var(--gutter) var(--s5);
}
.hero__copy { max-width: 46ch; }
.hero h1 { color: var(--plaster); margin-bottom: var(--s3);
           text-shadow: 0 1px 22px rgba(0,0,0,.55); }
.hero h1 em { font-style: normal; color: var(--gold-1); display: block; }
.hero__lead { color: var(--text-invert-soft); font-size: var(--t-lead);
              margin-bottom: var(--s3); max-width: 40ch;
              text-shadow: 0 1px 22px rgba(0,0,0,.55); }
.hero .btn-row { margin-bottom: var(--s4); }
.hero__meta {
  display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3);
  font-size: var(--t-small); color: var(--text-invert-soft);
  border-top: 1px solid var(--rule-invert); padding-top: var(--s3);
  max-width: 46ch;
}
.hero__meta strong { color: var(--plaster); font-weight: 600; }

/* Scroll cue. Persists for the whole pinned hero (JS dims it once the headline
   goes), so it has to stay legible over BOTH the near-black marble and the bright
   gold veining -- hence the text-shadow rather than a flat colour. */
.hero__cue {
  position: absolute; left: 50%; bottom: 1.4rem; transform: translateX(-50%);
  z-index: 10; display: flex; flex-direction: column; align-items: center; gap: .35rem;
  font-family: var(--f-display); font-weight: 700;
  font-size: .68rem; letter-spacing: .3em; text-transform: uppercase;
  color: rgba(245,242,237,.86);
  text-shadow: 0 1px 10px rgba(0,0,0,.85), 0 0 26px rgba(0,0,0,.6);
  text-decoration: none;
}
.hero__cue:hover { color: var(--gold-1); }
/* Progress fill under the cue label. Desktop never shows it -- the desktop hero
   was signed off as is and its cue is not covered by anything. */
.hero__cue-bar {
  display: none; width: 104px; height: 2px; border-radius: 2px;
  background: rgba(245,242,237,.22); overflow: hidden;
}
.hero__cue-bar i {
  display: block; width: 100%; height: 100%; transform-origin: 0 50%;
  transform: scaleX(0);
  background: linear-gradient(90deg, var(--gold-2), var(--gold-1));
}
.hero__cue svg {
  width: 18px; height: 18px; display: block;
  filter: drop-shadow(0 1px 8px rgba(0,0,0,.9));
  animation: cue-bob 1.8s ease-in-out infinite;
}
@keyframes cue-bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(6px); }
}
@media (prefers-reduced-motion: reduce) { .hero__cue svg { animation: none; } }

/* The grain overlay is fixed, full-viewport and mix-blend-mode — exactly the
   kind of layer that stutters over a scrubbing full-screen image. Keep it off
   the hero entirely, and off phones. */
.hero-live .grain { opacity: 0; }
@media (max-width: 767px) { .grain { display: none; } }

/* The nav now reveals DURING the pin, over the photograph. A full-width
   backdrop-filter over an actively scrubbing image is one of the most
   expensive things you can ask a mid-range phone to do — go opaque instead.
   `.hero-live` is set on <html> by the hero ScrollTrigger's onToggle. */
/* The nav is dark everywhere now, so this override is no longer about colour --
   it exists ONLY to drop the backdrop-filter while the hero is scrubbing. A
   full-width blur over a 4K image being scrubbed is one of the most expensive
   things you can ask a mid-range phone to do. Do not delete it just because the
   two states now look almost identical. */
.hero-live .nav {
  background: rgba(10,10,12,.96);
  backdrop-filter: none; -webkit-backdrop-filter: none;
}

/* ---- short viewports: the hero is pinned, so nothing below the fold during
   the pin is reachable. These keep the whole copy block inside 100svh. ---- */
@media (min-width: 768px) and (max-height: 900px) {
  .hero__inner { padding-block: var(--s5) var(--s4); }
  .hero h1 { margin-bottom: var(--s2); }
  .hero__lead { font-size: 1.02rem; margin-bottom: var(--s3); }
  .hero .btn-row { margin-bottom: var(--s3); }
  .hero__meta { padding-top: var(--s2); }
}
@media (min-width: 768px) and (max-height: 740px) {
  .hero__inner { padding-block: var(--s4) var(--s3); }
  .hero h1 { font-size: clamp(1.9rem, 3.1vw, 2.5rem); }
  .hero__meta { display: none; }
  .hero .btn { padding: .9em 1.5em; font-size: .9rem; }
}

/* ---- tablet ---- */
@media (max-width: 1023px) {
  .hero__copy { max-width: 38ch; }
}

/* ---- portrait viewports: copy sits at the bottom, scrim flips to match ---- */
@media (max-aspect-ratio: 9/10) {
  .hero { align-items: end; }
  /* Stops are measured from the BOTTOM. On a 390x844 phone the headline copy
     occupies 0-48% and the bracket/TV sit at 42-68%, so this gradient was doing
     two jobs at once: holding contrast under the text AND dimming the hardware
     by up to 62% black. A matte-black bracket on near-black marble under 62%
     dimming is simply invisible, which is why the animation read as "nothing
     happened" on a phone.
     Everything from 0-42% is UNCHANGED, so headline contrast is untouched
     (re-measured, not assumed). Only the ramp above the copy is steepened, which
     roughly halves the dimming over the TV: ~0.42 -> ~0.19 at 55%. */
  .hero__scrim {
    background:
      linear-gradient(to top,
        rgba(8,8,10,.95)  0%,
        rgba(8,8,10,.90) 24%,
        rgba(8,8,10,.62) 42%,
        rgba(8,8,10,.30) 50%,
        rgba(8,8,10,.08) 60%,
        rgba(8,8,10,0)   72%),
      linear-gradient(to bottom, rgba(8,8,10,.55) 0%, rgba(8,8,10,0) 16%);
  }
}
@media (max-width: 767px) {
  /* The bottom padding has to clear the scroll cue, which is now 48px tall
     (label + chevron + progress bar) sitting 18px off the bottom -- a 66px
     no-go zone. --s6 alone left the button stack 2px INTO it at 414x896.
     Note the axis: the copy's height varies with WIDTH, not height, because it
     is the headline and lead re-wrapping. So this is unconditional on phones
     rather than gated behind a max-height. */
  .hero__inner { padding: var(--s4) var(--gutter) calc(var(--s6) + var(--s2)); }
  .hero__copy { max-width: none; }
  .hero h1 { font-size: clamp(2rem, 8.6vw, 2.6rem); margin-bottom: var(--s2); }
  .hero__lead { font-size: 1rem; margin-bottom: var(--s3); }
  .hero .btn-row { gap: var(--s2); margin-bottom: 0; }
  .hero .btn { flex: 1 1 auto; padding: .95em 1.2em; font-size: .88rem; }
  .hero__meta { display: none; }
  /* the cue stays on phones -- it is the whole point of the pinned hero */
  /* The cue was 55x40px at 9.9px type and the sticky call bar covered it from
     45% of the pin onward -- so the one affordance telling a phone user to keep
     scrolling was both unreadable and hidden. It is legible now, sits clear of
     the call bar, and carries a progress fill so the FIRST pixel of scroll
     produces visible feedback. That is the real fix for "the page looks broken":
     the hero always responds, even before the bracket has faded in. */
  .hero__cue { bottom: 1.15rem; font-size: .68rem; letter-spacing: .2em; gap: .3rem; }
  .hero__cue .hero__cue-bar { display: block; }

}

/* reduced motion: no pin, no dolly — the finished frame, everything visible */
@media (prefers-reduced-motion: reduce) {
  .js .hero__plate { transform: none; }
  .hero__layer, .hero__gfx { opacity: 1 !important; transform: none !important; }
  .hero__gfx { opacity: 0 !important; }   /* x-ray is a motion beat, not a resting state */
  .hero__copy { opacity: 1 !important; visibility: visible !important; }
}

/* ============================================================
   5. REVEALS
   ============================================================ */
.js .rv { opacity: 0; transform: translateY(14px); }
.is-ready .rv { will-change: opacity, transform; }
@media (prefers-reduced-motion: reduce) { .rv { opacity: 1 !important; transform: none !important; } }

/* ============================================================
   6. PROOF BAND — Wil hanging off a mount he installed
   ============================================================ */
.proof { position: relative; background: var(--ink); color: var(--text-invert); overflow: hidden; }
/* The grid, not the copy column, owns the section padding now. It used to sit
   on .proof__body alone, which left the photograph bleeding into all four
   edges of the band -- so its bottom sat hard against the section below it,
   and there was no rectangle inset from the edge to round. */
.proof__grid {
  display: grid; grid-template-columns: 1.05fr .95fr; align-items: center;
  gap: var(--s5) var(--s6);
  max-width: var(--maxw); margin-inline: auto;
  padding: var(--section-pt) var(--gutter) var(--section-pb);
}
.proof__media { position: relative; aspect-ratio: 4 / 3.4; overflow: hidden; }
.proof__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%; }
.proof__media picture { display: block; width: 100%; height: 100%; }
.proof__body { padding: 0; }
.proof__body h2 { color: var(--plaster); margin-bottom: var(--s3); }
.proof__quote {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.05rem, 1.5vw, 1.3rem); line-height: 1.45;
  color: var(--plaster); border-left: 2px solid var(--gold-2);
  padding-left: var(--s3); margin: var(--s4) 0 0; max-width: 40ch;
}
@media (max-width: 900px) {
  .proof__grid { grid-template-columns: 1fr; gap: var(--s4); }
  .proof__media { aspect-ratio: 4 / 3; }
  .proof__body { padding: 0; }
}

/* ============================================================
   7. TRUST BAR
   ============================================================ */
/* The bar's tiles carry their own padding, so it does not take the full
   --section-pt/pb. It still owes the lift back at the bottom, because the
   section after it is now pulled up over this edge like every other junction. */
.trust { background: var(--plaster-2); border-block: 1px solid var(--rule);
         padding-bottom: var(--section-lift); }
/* FIVE tiles, which is an awkward number to wrap. Dividers come from a 1px grid
   gap letting the rule-coloured background show through -- the same trick
   .svc-grid uses -- because the old `border-left` + `:first-child` reset only
   works for a single unwrapped row and draws in the wrong places otherwise.
   Widths are chosen so no row is ever left with an orphan tile. */
.trust__grid {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(2, 1fr);
  max-width: var(--maxw); margin-inline: auto;
}
.trust__item {
  background: var(--plaster-2);
  padding: var(--s4) var(--s2); text-align: center;
  transition: background .45s var(--ease-out);
}
/* phone: 2 + 2 + 1, the last tile carrying the full width */
.trust__item:nth-child(5) { grid-column: span 2; }
.trust__item:hover { background: var(--plaster); }

/* tablet / laptop: a SIX column track, because 6 divides by both 3 and 2 --
   three tiles of 2 then two tiles of 3, so both rows come out flush */
@media (min-width: 700px) {
  .trust__grid { grid-template-columns: repeat(6, 1fr); }
  .trust__item { padding: var(--s5) var(--s3); }
  .trust__item:nth-child(-n+3) { grid-column: span 2; }
  .trust__item:nth-child(n+4)  { grid-column: span 3; }
}
/* desktop: all five across. Type and padding step down a notch so "Insured"
   and the award label do not wrap awkwardly inside a ~260px column. */
@media (min-width: 1160px) {
  .trust__grid { grid-template-columns: repeat(5, 1fr); }
  .trust__item:nth-child(-n+3),
  .trust__item:nth-child(n+4) { grid-column: auto; }
  .trust__item { padding: var(--s5) var(--s2); }
  .trust__n { font-size: clamp(1.9rem, 2.6vw, 2.5rem); }
}
.trust__n {
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(2rem, 3.6vw, 3rem); line-height: 1;
  letter-spacing: -.03em; color: var(--ink); display: block;
  /* the digits are being counted up -- proportional figures make the whole row
     jitter sideways on every frame */
  font-variant-numeric: tabular-nums;
  transition: transform .45s var(--ease-snap);
}
.trust__item:hover .trust__n { transform: translateY(-2px); }
.trust__n .u { color: var(--gold-3); }
/* "Free" is the one non-numeric tile, so it gets the reveal the counters cannot have:
   letters wipe up out of a mask, then a brass rule draws under the word. Both the
   mask and the rule are inert until JS adds .is-split / animates them, so a no-JS
   render is just the word. */
.trust__n .u { position: relative; display: inline-block; }
.trust__n .u .split-line { display: inline-block; overflow: hidden; vertical-align: bottom; }
/* Absolutely positioned so it does NOT take part in the flow: as a block element
   it added ~8px under the two word tiles and their labels sat lower than the
   three number tiles, which read as a misaligned row. */
.trust__rule {
  position: absolute; left: 0; right: 0; bottom: -.28rem; height: 2px;
  background: linear-gradient(90deg, var(--gold-3), var(--gold-2));
  transform: scaleX(0); transform-origin: 0 50%;
}
/* "Insured" and "Free" share the letter wipe and the brass rule; they are only
   separated in time. An earlier version gave Insured a drawn tick as well, but it
   was the one tile with an extra element in the flow, so its label sat lower than
   the other four and the whole row looked misaligned. */
.trust__l {
  display: block; margin-top: .6rem; font-size: .82rem; line-height: 1.4;
  color: var(--text-soft); letter-spacing: .02em;
}

/* ============================================================
   7b. AWARD BAND — the Consumer Choice medallion
   Light, not dark, for two reasons worth writing down because
   "award = dark background" is the reflex: the hero and the proof
   band on either side are both ink, so a dark band here would make
   three dark sections in a row; and the medallion's deep red goes
   muddy against #0E0E10 while it stays rich against plaster. Gold
   and red on warm plaster reads as a wax seal on letterhead.
   ============================================================ */
.award { background: var(--plaster-2); border-bottom: 1px solid var(--rule);
         padding-block: var(--section-pt) var(--section-pb); }
.award__grid {
  display: grid; gap: var(--s3) var(--s5);
  grid-template-columns: auto 1fr; align-items: center;
}
/* Wide screens get a third column so the band carries the full page width
   instead of stranding the copy on the left -- seal, then the claim, then the
   explanation of why the claim is worth anything. */
@media (min-width: 1080px) {
  .award__grid { grid-template-columns: auto minmax(0, 1fr) minmax(0, .8fr);
                 column-gap: var(--s6); align-items: center; }
  .award__note { border-left-width: 2px; align-self: center; }
}
.award__seal { position: relative; width: clamp(112px, 16vw, 190px); flex: none; }
/* Never upscaled: the source cut-out is 370px wide, so 190px keeps it crisp at
   2x DPR — and a seal beside a headline wants to be this size anyway. */
.award__seal img { width: 100%; height: auto; display: block;
                   filter: drop-shadow(0 10px 24px rgba(14,14,16,.22)); }
.award__body h2 { margin-bottom: var(--s2); }
.award__body .lead { max-width: 52ch; margin-bottom: var(--s2); }
.award__note {
  font-size: var(--t-small); color: var(--text-soft); max-width: 52ch;
  border-left: 2px solid var(--gold-3); padding-left: var(--s2); margin: 0;
}
.award__note strong { color: var(--ink); font-weight: 600; }

/* Shine sweep. The band is masked BY the medallion itself, so the highlight
   only ever appears on the metal — a plain overflow:hidden box would show a
   rectangle crossing the transparent corners. Guarded by @supports so an engine
   without mask support simply gets no shine rather than a white slab. */
.award__shine { display: none; }
@supports ((-webkit-mask-image: url(#m)) or (mask-image: url(#m))) {
  .award__shine {
    display: block; position: absolute; inset: 0; overflow: hidden;
    pointer-events: none;
    -webkit-mask: url("/assets/img/cca-medallion-370.webp") center/contain no-repeat;
            mask: url("/assets/img/cca-medallion-370.webp") center/contain no-repeat;
  }
}
.award__shine i {
  position: absolute; top: -25%; bottom: -25%; left: 0; width: 42%;
  background: linear-gradient(105deg, rgba(255,255,255,0) 0%,
              rgba(255,255,255,.72) 50%, rgba(255,255,255,0) 100%);
  transform: translateX(-160%);
}
/* below the 3-column breakpoint the note simply follows the body in the second
   column; on a phone everything stacks AND centres */
@media (max-width: 1079px) {
  .award__note { grid-column: 2; margin-top: var(--s1); }
}
@media (max-width: 720px) {
  .award__grid { grid-template-columns: 1fr; justify-items: center; text-align: center; }
  .award__note { grid-column: 1; }
  .award__seal { margin-inline: auto; }
  .award__body .lead { margin-inline: auto; }
  .award__body .eyebrow { justify-content: center; }
  /* the note keeps its gold rule, so it stays left-READ but centres as a block */
  .award__note { text-align: left; margin-inline: auto; max-width: 40ch; }
}
@media (prefers-reduced-motion: reduce) { .award__shine { display: none; } }

/* ============================================================
   8. SECTION HEADERS
   ============================================================ */
.sec__head { max-width: 62ch; margin-bottom: var(--s5); }
.sec__head h2 { margin-bottom: var(--s2); }

/* --- split head -------------------------------------------------------------
   Mobile-first on purpose: below 1080px this modifier does nothing at all, so
   phones and tablets keep the plain stacked head. Above it, the eyebrow and the
   headline hold the left column while the supporting sentence sits bottom-aligned
   in the right one, and a hairline carries the block the full width of the page.
   Heads with no .lead degrade to a single column and keep only the rule. */
@media (min-width: 1080px) {
  .sec__head--split {
    max-width: none;
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    column-gap: var(--s6);
    align-items: end;
    padding-bottom: var(--s4);
    border-bottom: 1px solid var(--rule);
  }
  .sec__head--split .eyebrow { grid-column: 1; grid-row: 1; }
  .sec__head--split h2       { grid-column: 1; grid-row: 2; margin-bottom: 0; }
  .sec__head--split .lead,
  .sec__head--split .sec__aside {
    grid-column: 2; grid-row: 1 / span 2;
    align-self: end; margin-bottom: 0; max-width: 46ch;
  }
  .sec__head--split .sec__aside { max-width: none; }
}
.sec--dark .sec__head--split { border-bottom-color: var(--rule-invert); }

/* ---- the About / Meet-the-owner split ----
   This used to be an INLINE style on the element with no CSS rule at all, so no
   media query could ever collapse it -- inline wins -- and on a phone the copy
   was trapped in a narrow left column beside a postage-stamp photo. */
.about-grid {
  display: grid; gap: var(--s5);
  grid-template-columns: 1.1fr .9fr; align-items: start;
}
.about-grid__media img { width: 100%; height: auto; }
@media (max-width: 860px) {
  .about-grid { grid-template-columns: 1fr; gap: var(--s4); }
  /* photo first, then the copy at the full width of the column */
  .about-grid__media { order: -1; }
  .about-grid__media img { max-height: 62vh; object-fit: cover; }
}

/* ============================================================
   9. BEFORE / AFTER SLIDERS
   ============================================================ */
.ba-grid { display: grid; gap: var(--s4); grid-template-columns: repeat(2, 1fr); }
@media (max-width: 820px) { .ba-grid { grid-template-columns: 1fr; } }

.ba { position: relative; }
.ba__frame {
  position: relative; overflow: hidden; aspect-ratio: 4 / 5;
  background: var(--ink-2); cursor: ew-resize; touch-action: pan-y;
}
/* Photographs are uncovered rather than faded in -- it matches what the section
   is about. Gated behind .js so a no-JS render is never clipped to nothing. */
.js .rv-wipe { clip-path: inset(0 0 100% 0); }
@media (prefers-reduced-motion: reduce) { .rv-wipe { clip-path: none !important; } }
.ba__img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.ba__after { z-index: 1; }
/* The before layer is full size and revealed with clip-path, so both images
   always render at identical scale no matter how wide the frame is. */
.ba__beforeWrap {
  position: absolute; inset: 0; z-index: 2;
  clip-path: inset(0 50% 0 0);
}
.ba__beforeWrap::after {
  content: ''; position: absolute; top: 0; bottom: 0; right: 0; width: 1px;
  background: rgba(245,242,237,.7);
}
.ba__handle {
  position: absolute; top: 0; bottom: 0; left: 50%; z-index: 3;
  width: 44px; transform: translateX(-50%);
  display: grid; place-items: center; pointer-events: none;
}
.ba__knob {
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--plaster); color: var(--ink);
  display: grid; place-items: center;
  box-shadow: 0 4px 18px rgba(0,0,0,.35);
  font-size: .8rem; font-family: var(--f-display); font-weight: 800;
  transition: transform .35s var(--ease-snap), background .35s var(--ease-out);
}
.ba__frame:hover .ba__knob { transform: scale(1.12); background: var(--gold-2); }
@media (prefers-reduced-motion: reduce) { .ba__frame:hover .ba__knob { transform: none; } }
.ba__tag {
  position: absolute; z-index: 4; top: var(--s2);
  font-family: var(--f-display); font-weight: 700; font-size: .68rem;
  letter-spacing: .16em; text-transform: uppercase;
  padding: .35em .7em; background: rgba(14,14,16,.72); color: var(--plaster);
  backdrop-filter: blur(6px);
}
.ba__tag--b { left: var(--s2); }
.ba__tag--a { right: var(--s2); background: var(--gold-2); color: var(--ink); }
.ba__cap { margin-top: var(--s2); font-size: var(--t-small); color: var(--text-soft);
            max-width: 46ch; }
.ba input[type="range"] {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; margin: 0; cursor: ew-resize; z-index: 5;
}

/* ============================================================
   10. SERVICES
   ============================================================ */
.svc-grid { display: grid; gap: 1px; background: var(--rule);
            grid-template-columns: repeat(3, 1fr); border: 1px solid var(--rule); }
.svc {
  background: var(--plaster); padding: var(--s4);
  display: flex; flex-direction: column; gap: var(--s2);
  text-decoration: none; transition: background .4s var(--ease-out);
  position: relative;
}
.svc:hover { background: var(--plaster-2); }
/* a brass edge that draws in from the left, so the whole grid does not shift */
.svc::after {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: var(--gold-3); transform: scaleY(0); transform-origin: 50% 0;
  transition: transform .4s var(--ease-snap);
}
.svc:hover::after { transform: scaleY(1); }
.svc__ico { width: 30px; height: 30px; color: var(--gold-3);
            transition: transform .4s var(--ease-snap); }
.svc:hover .svc__ico { transform: translateY(-3px); }
.svc h3 { font-size: 1.12rem; }
.svc p { font-size: var(--t-small); color: var(--text-soft); margin: 0; }
.svc__more { margin-top: auto; font-family: var(--f-display); font-weight: 700;
             font-size: .82rem; color: var(--gold-3);
             display: inline-flex; align-items: center; gap: .4em; }
.svc__more::after { content: '\2192'; transition: transform .4s var(--ease-snap); }
.svc:hover .svc__more::after { transform: translateX(5px); }
@media (prefers-reduced-motion: reduce) {
  .svc:hover .svc__ico, .svc:hover .svc__more::after { transform: none; }
}
@media (max-width: 940px) { .svc-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .svc-grid { grid-template-columns: 1fr; } }

/* ============================================================
   11. VIDEO
   ============================================================ */
.video__frame {
  position: relative; aspect-ratio: 16 / 9; overflow: hidden;
  background: var(--ink-2); border: 1px solid var(--rule-invert);
  max-width: 1060px; margin-inline: auto;
}
.video__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.video__poster {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  filter: brightness(.62) saturate(.9);
}
/* The disc is centred on the FRAME, not on a stack containing the label -- it
   used to be one grid column with the label under it, so the pair was centred
   and the disc alone sat visibly high. The label is now out of flow. */
.video__play {
  position: absolute; inset: 0; z-index: 2;
  border: 0; background: none; cursor: pointer; color: var(--plaster);
  font-family: var(--f-display); font-weight: 700;
  display: grid; place-items: center;
}
.video__disc {
  position: relative;
  width: clamp(64px, 8vw, 92px); aspect-ratio: 1; border-radius: 50%;
  background: linear-gradient(140deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
  color: var(--ink);
  display: grid; place-items: center;
  transition: transform .45s var(--ease-snap);
}
/* Pulsing glow on its own layer, animated on OPACITY only -- see section 1b. */
.video__disc::after {
  content: ''; position: absolute; inset: -6px; border-radius: 50%; z-index: -1;
  box-shadow: 0 0 18px 4px rgba(212,175,55,.55), 0 0 48px 12px rgba(212,175,55,.3);
  animation: halo-pulse 2.6s ease-in-out infinite;
  will-change: opacity;
}
.video__play:hover .video__disc,
.video__play:focus-visible .video__disc { transform: scale(1.12); }
.video__play:hover .video__disc::after { animation-duration: 1.3s; }
.video__play:active .video__disc { transform: scale(1.04); }

.video__label {
  position: absolute; left: 50%; top: calc(50% + clamp(58px, 6vw, 78px));
  transform: translateX(-50%);
  font-size: .82rem; letter-spacing: .16em; text-transform: uppercase;
  white-space: nowrap;
  animation: label-breathe 3.4s ease-in-out infinite;
}
@keyframes label-breathe {
  0%, 100% { opacity: .72; letter-spacing: .16em; }
  50%      { opacity: 1;   letter-spacing: .22em; }
}
.video__play:hover .video__label { animation-play-state: paused; opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .video__disc::after { animation: none; opacity: .6; }
  .video__label { animation: none; opacity: 1; }
  .video__play:hover .video__disc { transform: none; }
}

/* ============================================================
   12. PROCESS
   ============================================================ */
.step-grid { display: grid; gap: var(--s4); grid-template-columns: repeat(4, 1fr); }
.step { border-top: 1px solid var(--rule); padding-top: var(--s3); }
.sec--dark .step { border-color: var(--rule-invert); }
.step__n {
  font-family: var(--f-display); font-weight: 800; font-size: .8rem;
  letter-spacing: .14em; color: var(--gold-3); display: block; margin-bottom: var(--s2);
}
.sec--dark .step__n { color: var(--gold-1); }
.step h3 { font-size: 1.05rem; margin-bottom: .5rem; }
.step p { font-size: var(--t-small); color: var(--text-soft); margin: 0; }
.sec--dark .step p { color: var(--text-invert-soft); }
@media (max-width: 900px) { .step-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .step-grid { grid-template-columns: 1fr; } }

/* Keep the whole closing block on one centred measure. The step grid inside it
   is a full-width 4-column track by default, which pulled the section's visual
   weight to the left even though the heading above it was centred. */
.cta-block { max-width: 1040px; margin-inline: auto; }
.cta-block .step-grid { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 760px) { .cta-block .step-grid { grid-template-columns: 1fr; } }

/* the expectation-setting line under the homepage CTA steps */
.cta__expect {
  max-width: 58ch; margin: var(--s4) auto 0; font-size: var(--t-small);
  color: var(--text-invert-soft); text-align: center;
}

/* ============================================================
   13. REVIEWS
   ============================================================ */
.rev-grid { display: grid; gap: var(--s3); grid-template-columns: repeat(3, 1fr); }
@media (max-width: 900px) { .rev-grid { grid-template-columns: 1fr; } }
.rev {
  background: var(--plaster); border: 1px solid var(--rule);
  padding: var(--s4); display: flex; flex-direction: column; gap: var(--s2);
  transition: border-color .4s var(--ease-out), transform .4s var(--ease-snap);
}
.rev:hover { border-color: var(--gold-2); transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .rev:hover { transform: none; } }
.sec--dark .rev { background: var(--ink-2); border-color: var(--rule-invert); }
/* Core gold reads well on ink. On light surfaces the stars are decorative
   (aria-hidden, with a text rating beside them) but still want more weight. */
.stars { display: flex; gap: 2px; color: var(--gold-3); }
.sec--dark .stars, .on-dark .stars { color: var(--gold-2); }
.stars svg { width: 15px; height: 15px; }
.rev p { margin: 0; font-size: var(--t-small); }
.rev__who { margin-top: auto; font-family: var(--f-display); font-weight: 700; font-size: .88rem; }
.rev__when { font-family: var(--f-body); font-weight: 400; color: var(--text-soft); font-size: .8rem; }

/* The homepage shows a single featured quote, so it is set as a pull-quote that
   owns the section width rather than a 60ch card stranded on the left. */
/* margin:0 matters -- <figure> carries a 40px UA margin on every side, which
   pushed the quote 40px inboard of the "Read the reviews" button below it and
   made the whole block look accidentally indented. */
.rev--feature { border: 0; background: none !important; padding: 0; margin: 0;
                display: grid; grid-template-columns: 1fr; gap: var(--s3); }
.rev--feature blockquote p {
  font-family: var(--f-display); font-weight: 500;
  font-size: clamp(1.25rem, 2.2vw, 1.9rem); line-height: 1.32;
  letter-spacing: -.015em; color: var(--plaster); max-width: 24ch;
}
.sec:not(.sec--dark) .rev--feature blockquote p { color: var(--ink); }
.rev--feature:hover { transform: none; }
/* Single column at every width: stars, quote, then the attribution UNDER the
   quote, all sharing one left edge with the button below. An earlier version put
   the name in a second column, which left it floating in the middle of the band
   with nothing to align to. Applies to every review added later, not just the
   one currently on the page. */
.rev--feature .rev__who { margin-top: var(--s1); }
@media (min-width: 1080px) {
  .rev--feature blockquote p { max-width: 26ch; }
}

.rating-hero { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.rating-hero__n { font-family: var(--f-display); font-weight: 800;
                  font-size: clamp(2.6rem, 5vw, 3.8rem); line-height: 1; letter-spacing: -.03em; }

/* ============================================================
   14. FAQ  (details/summary — readable with JS off)
   ============================================================ */
/* Two columns from 1024px: the heading stays put while the questions scroll past
   it, and the accordion gets the whole remaining width instead of being capped at
   900px inside a 1320px section. Below 1024px it is a plain stacked block and the
   sticky is dropped, because pinning anything on a phone eats the viewport. */
.faq-layout { display: grid; gap: var(--s4); }
.faq-layout .sec__head { margin-bottom: 0; }
@media (min-width: 1024px) {
  .faq-layout {
    grid-template-columns: minmax(0, 320px) minmax(0, 1fr);
    column-gap: var(--s6);
    align-items: start;
  }
  .faq-layout .sec__head {
    position: sticky; top: calc(var(--nav-h) + var(--s4));
    max-width: none;
  }
}
.faq__aside { margin-top: var(--s3); font-size: var(--t-small); color: var(--text-soft); }
.faq__aside a { font-family: var(--f-display); font-weight: 700; color: var(--gold-3);
                text-decoration: none; white-space: nowrap; }
.faq__aside a:hover { text-decoration: underline; }

.faq { border-top: 1px solid var(--rule); max-width: 900px; }
.faq-layout .faq { max-width: none; }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary {
  list-style: none; cursor: pointer; padding: var(--s3) 2.5rem var(--s3) 0;
  position: relative; font-family: var(--f-display); font-weight: 700;
  font-size: clamp(1rem, 1.4vw, 1.15rem); line-height: 1.35;
  transition: color .3s var(--ease-out), padding-left .35s var(--ease-snap);
}
.faq summary:hover { color: var(--gold-3); padding-left: 6px; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ''; position: absolute; right: .5rem; top: 50%; width: 13px; height: 13px;
  margin-top: -6px;
  background:
    linear-gradient(var(--gold-3), var(--gold-3)) center/100% 1.5px no-repeat,
    linear-gradient(var(--gold-3), var(--gold-3)) center/1.5px 100% no-repeat;
  transition: transform .35s var(--ease-out);
}
.faq summary:hover::after { transform: rotate(90deg); }
.faq details[open] summary::after { transform: rotate(90deg); background-size: 100% 1.5px, 0 0; }
.faq details[open] summary:hover::after { transform: rotate(90deg); }
.faq__a { padding: 0 2.5rem var(--s3) 0; }
.faq__a p { font-size: var(--t-small); color: var(--text-soft); max-width: 74ch; }
.faq__a p:last-child { margin-bottom: 0; }
@media (prefers-reduced-motion: reduce) {
  .faq summary:hover { padding-left: 0; }
  .faq summary:hover::after { transform: none; }
}

/* ============================================================
   15. GALLERY
   ============================================================ */
.gal { columns: 3; column-gap: var(--s2); }
@media (max-width: 900px) { .gal { columns: 2; } }
@media (max-width: 520px) { .gal { columns: 1; } }
.gal__item {
  break-inside: avoid; margin-bottom: var(--s2); position: relative;
  display: block; width: 100%; padding: 0; border: 0; background: none; cursor: zoom-in;
  overflow: hidden;   /* so the hover scale is a crop, not an overflow */
}
.gal__item img { width: 100%; height: auto;
                 transition: transform .6s var(--ease-snap); }
.gal__item:hover img { transform: scale(1.045); }
.gal__item::after {
  content: ''; position: absolute; inset: 0; background: var(--ink); opacity: 0;
  transition: opacity .4s var(--ease-out); pointer-events: none;
}
.gal__item:hover::after { opacity: .12; }
@media (prefers-reduced-motion: reduce) { .gal__item:hover img { transform: none; } }

.lb[hidden] { display: none; }
.lb {
  position: fixed; inset: 0; z-index: 990; background: rgba(10,10,12,.94);
  display: grid; place-items: center; padding: var(--gutter);
}
.lb img { max-width: 100%; max-height: 84vh; width: auto; }
.lb__cap {
  position: absolute; left: 0; right: 0; bottom: var(--s3); text-align: center;
  color: var(--text-invert-soft); font-size: var(--t-small); padding-inline: var(--gutter);
}
.lb__btn {
  position: absolute; background: none; border: 1px solid var(--rule-invert);
  color: var(--plaster); width: 46px; height: 46px; border-radius: 50%;
  cursor: pointer; display: grid; place-items: center; font-size: 1.1rem;
}
.lb__close { top: var(--s3); right: var(--s3); }
.lb__prev { left: var(--s3); top: 50%; transform: translateY(-50%); }
.lb__next { right: var(--s3); top: 50%; transform: translateY(-50%); }

/* ============================================================
   16. MARQUEE — service areas
   ============================================================ */
/* The marquee is a thin band with a lifted section on BOTH sides of it: it
   pulls up over the band above, and the reviews band pulls up over it. At
   --s3 of padding the lift below was taller than the band itself, so the dark
   section simply covered the names. It pays both lifts back and keeps --s4 of
   clear air on each side of the text. */
/* The band's own top border used to draw the section's curved corners as a
   visible hairline arc -- the only place on the site where a rule bent. The
   radius is dropped here and the rule is redrawn as a straight ::before inset
   to the container, so it matches the hairlines above it (.sec__head--split,
   .step) instead of curling into the gutters. The bottom border went with it:
   the reviews band overlaps this edge, so it was never visible anyway. */
.marquee { overflow: hidden; border: 0;
           border-top-left-radius: 0; border-top-right-radius: 0;
           padding-block: calc(var(--s4) + var(--section-lift));
           background: var(--plaster); }
.marquee::before {
  content: ''; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: min(100% - var(--gutter) * 2, var(--maxw) - var(--gutter) * 2);
  height: 1px; background: var(--rule);
}
.sec--dark .marquee { background: var(--ink); }
.sec--dark .marquee::before { background: var(--rule-invert); }
/* No flex `gap` here on purpose. The track is cloned to a whole number of
   segments and wrapped by exactly one segment width; a gap between the segments
   would make the wrap point land half a gap short and show a seam. Spacing is
   carried by the span's own padding instead, so every repeat is identical. */
.marquee__track { display: flex; width: max-content; will-change: transform; }
.marquee__track span {
  font-family: var(--f-display); font-weight: 800;
  font-size: clamp(1.1rem, 2.2vw, 1.7rem); letter-spacing: -.02em;
  color: var(--text-soft); display: flex; align-items: center; gap: var(--s4);
  white-space: nowrap; padding-right: var(--s4);
}
.marquee__track span::after { content: ''; width: 6px; height: 6px; border-radius: 50%;
                              background: var(--gold-2); flex: none; }

/* ============================================================
   17. FOOTER
   ============================================================ */
.foot { background: var(--ink); color: var(--text-invert); padding-block: var(--s6) var(--s4); }
.foot__grid {
  display: grid; gap: var(--s5); grid-template-columns: 1.4fr 1fr 1fr 1.1fr;
  padding-bottom: var(--s5); border-bottom: 1px solid var(--rule-invert);
}
.foot h4 {
  font-size: .74rem; letter-spacing: .18em; text-transform: uppercase;
  color: var(--gold-1); font-weight: 700; margin-bottom: var(--s2);
}
.foot a { color: var(--text-invert-soft); text-decoration: none; }
.foot a:hover { color: var(--plaster); }
.foot li { margin-bottom: .45rem; font-size: var(--t-small); }
.foot__brand { font-family: var(--f-display); font-weight: 800; font-size: 1.6rem;
               letter-spacing: -.03em; margin-bottom: var(--s2); }
.foot__tel { font-family: var(--f-display); font-weight: 800;
             font-size: 1.5rem; letter-spacing: -.02em; color: var(--plaster) !important;
             text-decoration: none; display: inline-block; margin-bottom: .3rem; }
.foot__social { display: flex; gap: var(--s2); margin-top: var(--s3); }
.foot__social a {
  width: 42px; height: 42px; border: 1px solid var(--rule-invert); border-radius: 50%;
  display: grid; place-items: center; transition: border-color .3s, background .3s;
}
.foot__social a:hover { border-color: var(--gold-2); background: rgba(212,175,55,.14); }
.foot__social svg { width: 18px; height: 18px; }
.foot__legal {
  display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); justify-content: space-between;
  padding-top: var(--s3); font-size: .8rem; color: var(--text-invert-soft);
}
.foot__hours { display: grid; grid-template-columns: auto auto; gap: .3rem var(--s3);
               font-size: var(--t-small); }
.foot__hours dt { color: var(--text-invert-soft); }
.foot__hours dd { margin: 0; color: var(--plaster); }
@media (max-width: 900px) { .foot__grid { grid-template-columns: repeat(2, 1fr); } }

/* PHONES: keep TWO columns rather than collapsing to one.
   Stacked full-width, the two link lists were 350px-wide blocks holding ~110px
   of text -- 187px + 219px of height with the right half of each one empty, and
   that empty half is most of why the mobile footer ran to 1219px (1.44 screens).
   Side by side they cost one column's height instead of two.

   The towns stay one per line on purpose. Flowing them inline only pays off in
   a full-width column; inside a half-width one each name is atomic and wraps to
   its own line anyway, so it would buy nothing and split the column ragged. */
@media (max-width: 540px) {
  .foot__grid { grid-template-columns: repeat(2, 1fr); gap: var(--s4) var(--s3); }
  .foot__col--brand, .foot__col--touch { grid-column: 1 / -1; }
}

/* sticky mobile call bar */
.callbar { display: none; }
@media (max-width: 767px) {
  .callbar {
    position: fixed; inset: auto 0 0 0; z-index: 850;
    display: grid; grid-template-columns: 1fr 1fr;
    background: var(--ink); border-top: 1px solid var(--rule-invert);
    transform: translateY(100%); transition: transform .4s var(--ease-out);
    padding-bottom: env(safe-area-inset-bottom);
  }
  .callbar.is-visible { transform: translateY(0); }
  /* The bar is fixed, so it floats over whatever the page ends with -- and the
     footer's last line ("Consumer Choice Award 2024") was sitting under it.
     The padding goes on .foot, NOT on body: body is --plaster, so padding there
     would paint a light strip below the ink footer. On .foot the ink simply
     extends behind the bar, which is what is wanted. */
  .foot { padding-bottom: calc(var(--s4) + var(--callbar-h) + env(safe-area-inset-bottom)); }
  .callbar a {
    padding: 1rem; text-align: center; text-decoration: none;
    font-family: var(--f-display); font-weight: 700; font-size: .92rem;
    color: var(--plaster);
  }
  /* Both halves now carry the site's gold, in the two sanctioned forms: gradient
     LETTERING on the ink half, gradient FILL on the solid half. The fill used to
     be flat --gold-2, which was the only place on the site where the gold was a
     single colour rather than the .btn--brass gradient. */
  .callbar a:first-child {
    background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
    -webkit-background-clip: text;
            background-clip: text;
    color: transparent;
  }
  .callbar a + a {
    background: linear-gradient(100deg, var(--gold-1) 0%, var(--gold-2) 55%, var(--gold-1) 100%);
    color: var(--ink);
  }
  body { padding-bottom: 0; }
  /* Windows High Contrast drops backgrounds, and the first half paints its
     glyphs THROUGH one -- without this it renders as invisible text. */
  @media (forced-colors: active) {
    .callbar a:first-child { background: none; color: CanvasText; }
  }
}

/* ============================================================
   18. FORMS
   ============================================================ */
.form { display: grid; gap: var(--s3); max-width: 720px; }
.form__row { display: grid; gap: var(--s3); grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .form__row { grid-template-columns: 1fr; } }

.field { position: relative; display: block; }
.field > span {
  display: block; font-family: var(--f-display); font-weight: 500;
  font-size: .82rem; letter-spacing: .02em; margin-bottom: .45rem;
}
.field .req { color: var(--gold-3); }
.field input, .field select, .field textarea {
  width: 100%; font-family: var(--f-body); font-size: 1rem; color: var(--text);
  background: var(--plaster); border: 1px solid var(--rule); border-radius: 2px;
  padding: .85rem 1rem; transition: border-color .3s var(--ease-out);
}
.field textarea { min-height: 110px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--gold-3); outline: none;
}
.field__hint { display: block; margin-top: .35rem; font-size: .8rem; color: var(--text-soft); }

/* photo upload */
.drop {
  border: 1px dashed var(--rule); border-radius: 2px; background: var(--plaster);
  padding: var(--s4) var(--s3); text-align: center; cursor: pointer;
  transition: border-color .3s var(--ease-out), background .3s var(--ease-out);
  display: block;
}
.drop:hover, .drop.is-over { border-color: var(--gold-3); background: var(--plaster-2); }
.drop input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; }
.drop__ico { width: 26px; height: 26px; color: var(--gold-3); margin: 0 auto .6rem; }
.drop__t { font-family: var(--f-display); font-weight: 700; font-size: .95rem; }
.drop__s { font-size: .82rem; color: var(--text-soft); margin-top: .25rem; }
.drop__preview { display: none; align-items: center; gap: var(--s2); text-align: left; }
.drop.has-file .drop__prompt { display: none; }
.drop.has-file .drop__preview { display: flex; }
.drop__thumb { width: 74px; height: 74px; object-fit: cover; flex: none; }
.drop__meta { font-size: .85rem; min-width: 0; }
.drop__name { font-family: var(--f-display); font-weight: 700; word-break: break-all; }
.drop__remove {
  margin-left: auto; flex: none; border: 1px solid var(--rule); background: none;
  border-radius: 999px; padding: .4rem .9rem; cursor: pointer;
  font-family: var(--f-display); font-weight: 700; font-size: .78rem;
}
.drop__remove:hover { border-color: var(--ink); }

.form__note { font-size: .82rem; color: var(--text-soft); }
.toast {
  margin-top: var(--s2); padding: var(--s3); border-left: 2px solid var(--gold-3);
  background: var(--plaster-2); font-size: var(--t-small);
}
.toast[hidden] { display: none; }
.toast--err { border-color: #B4402E; }

/* honeypot */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* contact split */
.contact-grid { display: grid; gap: var(--s6); grid-template-columns: 1.25fr .75fr; align-items: start; }
@media (max-width: 900px) { .contact-grid { grid-template-columns: 1fr; gap: var(--s5); } }
.contact-card { border: 1px solid var(--rule); padding: var(--s4);
                transition: border-color .4s var(--ease-out); }
.contact-card:hover { border-color: var(--gold-3); }
.contact-card h3 { font-size: 1.05rem; margin-bottom: var(--s2); }
.contact-card dl { display: grid; grid-template-columns: auto 1fr; gap: .4rem var(--s3);
                   font-size: var(--t-small); margin: 0; }
.contact-card dt { color: var(--text-soft); }
.contact-card dd { margin: 0; }

/* page header (inner pages) */
.phead { background: var(--ink); color: var(--text-invert);
         padding-block: calc(var(--nav-h) + var(--s6)) calc(var(--s6) + var(--section-lift)); }
.phead h1 { color: var(--plaster); margin-bottom: var(--s2); }
.phead p { color: var(--text-invert-soft); font-size: var(--t-lead); }
.crumbs { font-size: .8rem; color: var(--text-invert-soft); margin-bottom: var(--s3); }
.crumbs a { text-decoration: none; }
.crumbs a:hover { color: var(--plaster); }

/* inner pages show the nav immediately */
.nav--static { transform: translateY(0); }

/* service blocks */
.svc-detail { display: grid; gap: var(--s5); grid-template-columns: 1fr 1fr;
              align-items: center; padding-block: var(--section-y);
              border-top: 1px solid var(--rule); }
.svc-detail:first-of-type { border-top: 0; }
.svc-detail--flip .svc-detail__media { order: -1; }
@media (max-width: 860px) {
  .svc-detail { grid-template-columns: 1fr; gap: var(--s4); }
  .svc-detail--flip .svc-detail__media { order: 0; }
}
.svc-detail ul { margin-top: var(--s2); }
.svc-detail li { position: relative; padding-left: 1.4rem; margin-bottom: .5rem;
                 font-size: var(--t-small); color: var(--text-soft); }
.svc-detail li::before { content: ''; position: absolute; left: 0; top: .62em;
                         width: 7px; height: 1.5px; background: var(--gold-3); }
.svc-detail__media { overflow: hidden; }
.svc-detail__media img { transition: transform .7s var(--ease-snap); }
.svc-detail__media:hover img { transform: scale(1.03); }
@media (prefers-reduced-motion: reduce) { .svc-detail__media:hover img { transform: none; } }

/* filter pills */
.filters { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: var(--s4); }
.filters button {
  font-family: var(--f-display); font-weight: 700; font-size: .82rem;
  padding: .55em 1.1em; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--rule); background: none; color: var(--text);
  transition: background .3s, border-color .3s, color .3s;
}
.filters button:hover { border-color: var(--gold-3); color: var(--gold-3); }
.filters button[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: var(--plaster); }
