/* =========================================================================
   ZABE Media — zabemedia.com
   Tokens, base, layout, components. No build step, no dependencies.
   ========================================================================= */

/* ---------- Font fallbacks ------------------------------------------------
   Inter and Outfit load async, so the first paint uses a local fallback.
   Plain Arial is wider or narrower than the web fonts, which made hero text
   and button rows re-wrap on the swap (CLS 0.33 on the tour pages on mobile).
   These faces scale Arial to each web font's measured advance width, so
   lines break in the same places before and after the swap. Ratios were
   measured in Chromium against a mixed sample string, per weight band.
   ------------------------------------------------------------------------ */
@font-face{font-family:'Inter Fallback';src:local('Arial');font-weight:100 500;size-adjust:106.6%}
@font-face{font-family:'Inter Fallback';src:local('Arial Bold'),local('Arial-BoldMT');font-weight:600 900;size-adjust:101.5%}
@font-face{font-family:'Outfit Fallback';src:local('Arial');font-weight:100 500;size-adjust:98.4%}
@font-face{font-family:'Outfit Fallback';src:local('Arial Bold'),local('Arial-BoldMT');font-weight:600 900;size-adjust:94.2%}

/* ---------- Design tokens ------------------------------------------------
   Palette is navy-core and monochrome: every hue on this page sits on the
   brand navy's own 219deg axis. Ground is deliberately COOL, not the warm
   cream this page used to run, which matched neither the client's brand nor
   their live site. All ratios below are measured, not estimated.
   ------------------------------------------------------------------------ */
:root{
  /* Brand navy, sampled exactly from the client logo. hsl(219, 54%, 24%). */
  --navy:#1C335E;          /* white on it 12.47:1 */
  --navy-deep:#101F3C;     /* white on it 16.36:1 */
  --navy-soft:#2A4B84;

  /* Cool grounds. Never pure #fff, never warm. */
  --paper:#FBFCFD;
  --paper-2:#EFF3F8;

  /* Accent: the same navy hue lifted to L50. Works BOTH as text on paper and
     as a button fill under white text, which is why it is a single token. */
  --accent:#3068CF;        /* 5.10:1 on paper, white on it 5.24:1 */
  --accent-deep:#2957AE;   /* pressed / hover state */
  --accent-lite:#88A6DD;   /* accent as text on navy: 5.07:1 */
  --accent-line:rgba(48,104,207,.34);   /* decorative rules only */

  --ink:#17202E;          /* 15.94:1 on paper */
  --ink-soft:#5A6373;     /* 5.90:1 on paper  */
  /* Google review gold. Decorative star glyphs only, never text. */
  --gold:#FBBC04;
  --gold-deep:#C8890B;

  --ink-faint:#656D7B;    /* 5.08:1 on paper, 4.68:1 on paper-2 */

  --rule:rgba(28,51,94,.13);
  --rule-strong:rgba(28,51,94,.24);

  --display:'Outfit','Outfit Fallback',ui-sans-serif,system-ui,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  --sans:'Inter','Inter Fallback',system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;

  /* Shadows tinted to the navy ground, never neutral black. */
  --shadow-sm:0 1px 2px rgba(16,31,60,.06),0 2px 8px rgba(16,31,60,.05);
  --shadow-md:0 4px 12px rgba(16,31,60,.07),0 14px 34px rgba(16,31,60,.09);
  --shadow-lg:0 8px 20px rgba(16,31,60,.09),0 30px 64px rgba(16,31,60,.14);

  /* Shape lock: one radius scale. Cards 14px, small chrome 8px, pills full. */
  --r-sm:8px; --r-md:14px; --r-lg:14px; --r-pill:100px;
  --pad:clamp(76px,8.5vw,132px);
  --gut:clamp(20px,4vw,40px);
  --ease:cubic-bezier(.22,.61,.36,1);
}

/* ---------- Reset / base ------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
html:focus-within{scroll-behavior:smooth}
body{
  margin:0;background:var(--paper);color:var(--ink);
  font-family:var(--sans);font-size:17px;line-height:1.65;
  -webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img,svg,video{max-width:100%;display:block}
a{color:inherit}
button{font:inherit;color:inherit}
:focus-visible{outline:3px solid var(--accent);outline-offset:3px;border-radius:3px}

h1,h2,h3,h4{
  font-family:var(--display);font-weight:600;line-height:1.08;
  letter-spacing:-.015em;margin:0;color:var(--navy);
}
h1{font-size:clamp(2.5rem,6.4vw,4.75rem)}
h2{font-size:clamp(2rem,4.1vw,3.15rem)}
h3{font-size:clamp(1.2rem,1.9vw,1.5rem);line-height:1.22}
p{margin:0 0 1.1em}
p:last-child{margin-bottom:0}

/* ---------- Layout ------------------------------------------------------- */
.wrap{width:min(1200px,100% - var(--gut)*2);margin-inline:auto}
.wrap-wide{width:min(1400px,100% - var(--gut)*2);margin-inline:auto}
.sect{padding-block:var(--pad)}
body.has-hero [id]{scroll-margin-top:124px}
.sect-tight{padding-block:clamp(52px,6vw,84px)}
.center{text-align:center}
.skip{position:absolute;left:-9999px;top:0;background:var(--navy);color:#fff;padding:12px 20px;z-index:200;border-radius:0 0 var(--r-sm) 0}
.skip:focus{left:0}

/* ---------- Shared type helpers ------------------------------------------ */
.eyebrow{
  display:inline-flex;align-items:center;gap:.7em;
  font-size:.72rem;font-weight:600;letter-spacing:.18em;text-transform:uppercase;
  color:var(--accent);margin:0 0 1.1rem;
}
.eyebrow::before{content:"";width:26px;height:2px;background:var(--accent);flex:none}
.eyebrow.on-dark{color:var(--accent-lite)}
.eyebrow.on-dark::before{background:var(--accent-lite)}
.center .eyebrow{justify-content:center}
.lede{font-size:clamp(1.05rem,1.5vw,1.22rem);color:var(--ink-soft);line-height:1.68;max-width:62ch}
.center .lede{margin-inline:auto}
.sect-head{max-width:56ch;margin-bottom:clamp(38px,4vw,60px)}
.sect-head h2{text-wrap:balance}
.sect-head .lede{margin-top:1.1rem}
.center .sect-head,.sect-head.center{margin-inline:auto}

/* Visually hidden but read by screen readers. Used on the mobile submenu
   toggles, whose only visible content is a chevron. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ---------- Buttons ------------------------------------------------------ */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.6em;
  padding:.92em 1.6em;border-radius:var(--r-sm);border:1.5px solid transparent;
  font-size:.94rem;font-weight:600;letter-spacing:.01em;text-decoration:none;
  cursor:pointer;transition:transform .25s var(--ease),background .25s,color .25s,border-color .25s,box-shadow .25s;
}
.btn:hover{transform:translateY(-2px)}
.btn svg{width:1em;height:1em;flex:none;transition:transform .3s var(--ease)}
.btn:hover svg{transform:translateX(3px)}
.btn-primary{background:var(--navy);color:#fff;box-shadow:var(--shadow-sm)}
.btn-primary:hover{background:var(--navy-soft);box-shadow:var(--shadow-md)}
.btn-accent{background:var(--accent);color:#fff;box-shadow:var(--shadow-sm)}
.btn-accent:hover{background:var(--accent-deep);box-shadow:var(--shadow-md)}
.btn-ghost{background:transparent;color:var(--navy);border-color:var(--rule-strong)}
.pkg .btn-ghost:hover{border-color:var(--accent);color:var(--accent);background:rgba(48,104,207,.05)}
.btn-ghost:hover{border-color:var(--navy);background:rgba(28,51,94,.04)}
.btn-light{background:#fff;color:var(--navy)}
.btn-light:hover{background:var(--paper)}
.btn-outline-light{background:transparent;color:#fff;border-color:rgba(255,255,255,.42)}
.btn-outline-light:hover{border-color:#fff;background:rgba(255,255,255,.08)}
/* A single light pass across the filled buttons on hover. */
.btn-primary,.btn-accent{position:relative;overflow:hidden}
.btn-primary::after,.btn-accent::after{
  content:"";position:absolute;top:0;left:-130%;width:55%;height:100%;pointer-events:none;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.26),transparent);
  transform:skewX(-18deg);transition:left .75s var(--ease);
}
.btn-primary:hover::after,.btn-accent:hover::after{left:160%}
.btn-row{display:flex;flex-wrap:wrap;gap:14px}
.center .btn-row{justify-content:center}

/* ---------- Utility bar -------------------------------------------------- */
.util{background:var(--navy-deep);color:rgba(255,255,255,.82);font-size:.8rem;
  overflow:hidden;max-height:64px;
  transition:max-height .38s var(--ease),opacity .28s var(--ease)}
.util .wrap-wide{display:flex;align-items:center;justify-content:space-between;gap:18px;min-height:40px;flex-wrap:wrap}
.util a{text-decoration:none}
.util a:hover{color:#fff}
.util-l,.util-r{display:flex;align-items:center;gap:20px;flex-wrap:wrap}
.util-item{display:inline-flex;align-items:center;gap:.5em;white-space:nowrap}
.util svg{width:14px;height:14px;flex:none;opacity:.85}
.stars{color:var(--gold);letter-spacing:.06em}
@media(max-width:820px){.util .hide-sm{display:none}}
@media(max-width:560px){
  .util{font-size:.7rem}
  .util .wrap-wide{gap:10px;flex-wrap:nowrap}
  .util-l,.util-r{gap:12px}
}

/* ---------- Header / nav ------------------------------------------------- */
/* One shell holds the utility bar and the header so they flip together.
   With a hero it is fixed, letting the photography run to the top of the
   viewport under a transparent bar; without one it behaves as a normal
   sticky header and keeps its place in the flow. */
.site-top{position:sticky;top:0;z-index:120}
body.has-hero .site-top{position:fixed;left:0;right:0}

.hdr{position:relative;background:rgba(251,252,253,.9);backdrop-filter:blur(14px);
  border-bottom:1px solid transparent;
  transition:box-shadow .3s,border-color .3s,background .35s var(--ease),backdrop-filter .35s}
.hdr.stuck{border-bottom-color:var(--rule);box-shadow:0 2px 20px rgba(19,37,70,.07)}
/* Read-progress hairline. Purely CSS scroll-driven; browsers without
   animation-timeline just never paint it (it stays at scaleX(0)). */
.hdr::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:2px;z-index:1;
  background:linear-gradient(90deg,var(--accent),var(--accent-lite));
  transform:scaleX(0);transform-origin:0 50%;opacity:0;transition:opacity .3s}
.hdr.stuck::after{opacity:1}
@supports (animation-timeline:scroll()){
  .hdr::after{animation-name:readProgress;animation-timing-function:linear;animation-fill-mode:both;
    animation-timeline:scroll(root block)}
}
@keyframes readProgress{from{transform:scaleX(0)}to{transform:scaleX(1)}}
/* Loading part-way down the page (browser scroll restoration, or an anchor)
   is the one case where site.js still has to correct the bar. .is-ready lands
   two frames after its initial scroll read, so that correction is instant
   rather than a fade. */
.site-top:not(.is-ready),
.site-top:not(.is-ready) *,
.site-top:not(.is-ready)::before{transition:none !important}

/* The transparent bar is the DEFAULT on a hero page, not a state JS switches
   into. site.js is deferred, so anything it applies is painted after the
   browser has already shown the solid bar, which reads as a flash on load.
   Inverting it means first paint is correct and JS only adds .is-scrolled.
   html.js keeps no-JS visitors on the solid header. :not(.menu-open) matters
   because the mobile drawer paints solid paper, and white on it would vanish. */
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .util{max-height:0;opacity:0;pointer-events:none}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .hdr{background:transparent;backdrop-filter:none;
  border-bottom-color:transparent;box-shadow:none}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .brand{color:#fff}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .nav-link{color:#fff}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .nav-link:hover,
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .has-panel:hover>.nav-link,
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .has-panel:focus-within>.nav-link{color:#fff;background:rgba(255,255,255,.15)}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .nav-link[aria-current="page"]{color:#fff}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .nav-link .chev,
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .nav-toggle{color:#fff}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .nav-link .chev{opacity:.8}
/* Solid navy would sink into the photo, so the CTA becomes a light outline. */
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .hdr-cta{background:rgba(255,255,255,.12);color:#fff;
  border-color:rgba(255,255,255,.5);box-shadow:none;backdrop-filter:blur(6px)}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .hdr-cta:hover{background:rgba(255,255,255,.22);border-color:#fff}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .burger{border-color:rgba(255,255,255,.55)}
html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .burger span{background:#fff}
/* A soft scrim keeps white type legible over a bright hero frame. */
body.has-hero .site-top::before{content:"";position:absolute;inset:0;z-index:-1;
  pointer-events:none;opacity:0;transition:opacity .35s var(--ease);
  background:linear-gradient(180deg,rgba(11,22,42,.62) 0%,rgba(11,22,42,.5) 58%,rgba(11,22,42,0) 100%)}
body.has-hero html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open)::before{opacity:1}

.hdr .wrap-wide{display:flex;align-items:center;gap:22px;min-height:78px;transition:min-height .3s var(--ease)}
.hdr.stuck .wrap-wide{min-height:66px}
.brand{display:flex;align-items:center;text-decoration:none;color:var(--navy);flex:none}
/* Logo is one cached SVG recolored via mask, so header and footer share the file. */
.brand-mark{display:block;background-color:currentColor;
  -webkit-mask:url(images/zabe-media-logo.svg) no-repeat center/contain;
          mask:url(images/zabe-media-logo.svg) no-repeat center/contain}
.brand .brand-mark{width:174px;height:36px;transition:width .3s var(--ease),height .3s var(--ease)}
.hdr.stuck .brand .brand-mark{width:155px;height:32px}

.nav{margin-left:auto;display:flex;align-items:center}
.nav-list{display:flex;align-items:center;gap:2px;margin:0;padding:0;list-style:none}
.nav-list>li{position:relative}
.nav-link{
  display:inline-flex;align-items:center;gap:.4em;padding:.6em .78em;border-radius:var(--r-sm);
  font-size:.925rem;font-weight:500;color:var(--ink);text-decoration:none;background:none;border:0;cursor:pointer;
  transition:color .2s,background .2s;
}
.nav-link:hover,.has-panel:hover>.nav-link,.has-panel:focus-within>.nav-link{color:var(--navy);background:rgba(28,51,94,.06)}
/* Current page and current section. The exact page carries the accent bar and
   a tint; its parent carries the bar alone, so the section still reads as
   active while its panel is shut. */
.nav-link[aria-current="page"],.nav-link.is-section{color:var(--navy);font-weight:600;
  box-shadow:inset 0 -2px 0 var(--accent)}
.nav-link[aria-current="page"]{background:rgba(28,51,94,.06)}
.nav-link .chev{width:11px;height:11px;transition:transform .3s var(--ease);opacity:.6}
.has-panel:hover>.nav-link .chev,.has-panel:focus-within>.nav-link .chev{transform:rotate(180deg)}

/* A top-level item that owns a dropdown is a real link to its hub page, not a
   button. The panel opens on hover and on keyboard focus; the separate
   .nav-toggle button exists only for the mobile drawer, where tapping the
   label has to navigate rather than expand. */
.has-panel{display:flex;align-items:center}
.nav-toggle{display:none;background:none;border:0;padding:0;cursor:pointer;color:var(--ink)}
.nav-toggle .chev{width:14px;height:14px;transition:transform .3s var(--ease);opacity:.6}
.nav-toggle[aria-expanded="true"] .chev{transform:rotate(180deg)}
.hdr-cta{margin-left:12px}

/* Dropdown panels */
.panel{
  position:absolute;top:calc(100% + 12px);left:50%;transform:translate(-50%,-8px);
  background:#fff;border:1px solid var(--rule);border-radius:var(--r-lg);
  box-shadow:var(--shadow-lg);padding:20px;margin:0;list-style:none;
  opacity:0;visibility:hidden;
  transition:opacity .22s var(--ease),transform .22s var(--ease),visibility .22s;
  z-index:50;
}
.panel::before{content:"";position:absolute;top:-14px;left:0;right:0;height:14px}
.nav-list>li:hover>.panel,.nav-list>li:focus-within>.panel,.panel.open{opacity:1;visibility:visible;transform:translate(-50%,0)}
.panel-svc{width:min(680px,88vw);display:grid;grid-template-columns:1fr 1fr;gap:4px}
.panel-ind{width:min(440px,88vw);display:grid;grid-template-columns:1fr;gap:2px}
.panel-area{width:min(560px,88vw);display:grid;grid-template-columns:1fr 1fr 1fr;gap:2px}
/* About carries the pages that had no route from the nav at all: reviews,
   the FAQ, and the guides hub with the networking calendar under it. */
.panel-about{width:min(340px,88vw);display:grid;grid-template-columns:1fr;gap:2px}
.panel a{
  display:block;padding:9px 12px;border-radius:var(--r-sm);text-decoration:none;
  font-size:.9rem;color:var(--ink);line-height:1.35;transition:background .18s,color .18s;
}
.panel a:hover{background:var(--paper-2);color:var(--navy)}
.panel a[aria-current="page"]{background:var(--paper-2);color:var(--navy);
  box-shadow:inset 3px 0 0 var(--accent)}
.panel a[aria-current="page"] strong{color:var(--navy)}
/* A guide detail page has no entry of its own, so the hub it sits under is
   marked instead, one step down from the exact-page treatment. */
.panel a.is-section{color:var(--navy);box-shadow:inset 3px 0 0 var(--accent-line)}
.panel a small{display:block;font-size:.76rem;color:var(--ink-faint);margin-top:1px}
.panel-foot{grid-column:1/-1;margin-top:10px;padding-top:12px;border-top:1px solid var(--rule)}
.panel-foot a{font-weight:600;color:var(--navy);display:inline-flex;align-items:center;gap:.5em}

/* Mobile menu button */
.burger{display:none;margin-left:auto;width:44px;height:44px;border:1px solid var(--rule-strong);
  background:none;border-radius:var(--r-sm);cursor:pointer;position:relative}
.burger span{position:absolute;left:12px;right:12px;height:1.5px;background:var(--navy);transition:transform .3s var(--ease),opacity .2s}
.burger span:nth-child(1){top:15px}
.burger span:nth-child(2){top:21px}
.burger span:nth-child(3){top:27px}
.burger[aria-expanded="true"] span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}

@media(max-width:1120px){
  .burger{display:block;z-index:2}
  .hdr-cta{display:none}
  .hdr{backdrop-filter:none;background:var(--paper)}
  html.js body.has-hero .site-top:not(.is-scrolled):not(.menu-open) .hdr{background:transparent}
  .brand{position:relative;z-index:2}
  .nav{
    position:fixed;inset:0;z-index:1;margin:0;display:block;overflow-y:auto;
    background:var(--paper);padding:86px var(--gut) 48px;
    opacity:0;visibility:hidden;transform:translateY(-10px);
    transition:opacity .25s var(--ease),transform .25s var(--ease),visibility .25s;
  }
  .nav.open{opacity:1;visibility:visible;transform:none}
  .nav-list{display:block}
  .nav-list>li{border-bottom:1px solid var(--rule)}
  .nav-link{width:100%;justify-content:space-between;padding:16px 4px;font-size:1.05rem;border-radius:0}
  /* In the drawer the label and the chevron are two separate targets: the label
     navigates to the hub page, the chevron expands the submenu in place. */
  .has-panel{flex-wrap:wrap}
  .has-panel>.nav-link{width:auto;flex:1;min-width:0}
  .has-panel>.nav-link .chev{display:none}
  /* The drawer rows are hairline separated, so a highlight that stops short of
     the chevron reads as a misaligned box rather than a hover state. */
  .has-panel:hover>.nav-link,.has-panel:focus-within>.nav-link{background:none}
  .nav-toggle{display:flex;align-items:center;justify-content:center;flex:none;
    width:52px;align-self:stretch;margin-right:-8px}
  .has-panel>.panel{flex-basis:100%}
  .panel{position:static;transform:none;opacity:1;visibility:visible;box-shadow:none;
    border:0;border-radius:0;padding:0 0 14px;width:auto;display:none;background:transparent}
  /* .panel.open carries the desktop centring transform and outranks bare .panel,
     so it has to be reset explicitly at this breakpoint. */
  .nav-list>li:hover>.panel,.nav-list>li:focus-within>.panel,.panel.open{transform:none}
  .panel.open{display:grid}
  .panel-svc,.panel-area{grid-template-columns:1fr 1fr}
  .m-cta{display:block;padding-top:24px}
  .m-cta .btn{width:100%}
  /* While the drawer is open the bar pins to the top at a fixed height, so the
     drawer's top padding clears it whether or not the page was scrolled. */
  .hdr.menu-open{position:fixed;top:0;left:0;right:0;background:var(--paper)}
  .hdr.menu-open .wrap-wide{min-height:78px}
  .hdr.menu-open .brand .brand-mark{width:174px;height:36px}
  /* The at-top state must not survive into the open drawer. */
  .site-top.menu-open .hdr{background:var(--paper)}
  .site-top.menu-open .brand{color:var(--navy)}
  .site-top.menu-open .burger span{background:var(--navy)}
  .site-top.menu-open .burger{border-color:var(--rule-strong)}
}
@media(min-width:1121px){.m-cta{display:none}}
@media(max-width:520px){.panel-svc,.panel-area{grid-template-columns:1fr}}

/* ---------- Hero --------------------------------------------------------- */
/* min-h uses dvh so the iOS address bar cannot shorten the hero mid-scroll. */
.hero{position:relative;isolation:isolate;color:#fff;overflow:hidden;
  min-height:min(760px,86dvh);display:flex;align-items:center;
  padding-block:clamp(64px,7vw,96px)}
/* The fixed bar sits over the top ~78px, so add that back as hero top padding
   or the centred copy drifts up underneath it. */
body.has-hero .hero{padding-top:calc(clamp(64px,7vw,96px) + 78px)}
/* Solid ground behind the stack: two slides at 50% during a crossfade only cover
   ~75%, and this keeps what shows through navy instead of the warm page paper.
   It also stands in for the hero image before it decodes. */
.hero-bg{position:absolute;inset:0;z-index:-2;background:var(--navy-deep)}
.hero-slide{position:absolute;inset:0;opacity:0}
.hero-slide img{width:100%;height:100%;object-fit:cover;transform:scale(1.03)}

/* Without JS (or with reduced motion) only the first slide is ever painted, so
   the hero degrades to exactly the single still it was before. */
.hero-slide:first-child{opacity:1}
.hero-slide:first-child img{animation:kb 28s var(--ease) infinite alternate}
@keyframes kb{from{transform:scale(1.02)}to{transform:scale(1.13)}}

/* .rotating is added by site.js once slides 2-4 have their src. Four slides
   share one 28s cycle: 7s hold each, 1.7s crossfade, offset 7s apart. The
   first slide starts at -1.7s so it is already opaque on the first frame. */
.hero-bg.rotating{--hero-cycle:28s}
.hero-bg.rotating .hero-slide{opacity:0;animation:heroFade var(--hero-cycle) linear infinite}
.hero-bg.rotating .hero-slide img{animation:heroKb var(--hero-cycle) var(--ease) infinite}
.hero-bg.rotating .hero-slide:nth-child(1),
.hero-bg.rotating .hero-slide:nth-child(1) img{animation-delay:-1.7s}
.hero-bg.rotating .hero-slide:nth-child(2),
.hero-bg.rotating .hero-slide:nth-child(2) img{animation-delay:5.3s}
.hero-bg.rotating .hero-slide:nth-child(3),
.hero-bg.rotating .hero-slide:nth-child(3) img{animation-delay:12.3s}
.hero-bg.rotating .hero-slide:nth-child(4),
.hero-bg.rotating .hero-slide:nth-child(4) img{animation-delay:19.3s}
/* Scrolled past the hero there is nothing to see, so stop compositing it. */
.hero-bg.paused .hero-slide,.hero-bg.paused .hero-slide img{animation-play-state:paused}
@keyframes heroFade{0%{opacity:0}6%{opacity:1}25%{opacity:1}31%{opacity:0}100%{opacity:0}}
/* Holds at the zoomed-in end and snaps back at 0%, which lands while opacity is 0. */
@keyframes heroKb{0%{transform:scale(1.03)}31%,100%{transform:scale(1.13)}}
.hero-bg::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,rgba(19,37,70,.94) 0%,rgba(19,37,70,.8) 42%,rgba(19,37,70,.36) 72%,rgba(19,37,70,.46) 100%);
}
.hero-inner{max-width:760px}
.hero h1{color:#fff;text-wrap:balance}
.hero h1 em{color:var(--accent-lite);font-style:normal;font-weight:700}
.hero-sub{font-size:clamp(1.06rem,1.55vw,1.25rem);color:rgba(255,255,255,.9);
  line-height:1.6;max-width:48ch;margin:1.3rem 0 2.1rem}
.hero .btn-row{margin-bottom:0}
/* Credential strip. Sits directly under the hero rather than inside it, so the
   hero stays a single moment: eyebrow, headline, subtext, CTAs. */
.creds-bar{background:var(--paper);border-bottom:1px solid var(--rule)}
.creds-bar .wrap-wide{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:center;gap:14px clamp(22px,3.4vw,52px);padding-block:16px}
.chip{display:inline-flex;align-items:center;gap:.6em;font-size:.86rem;
  font-weight:500;color:var(--ink-soft);white-space:nowrap}
.chip svg{width:16px;height:16px;color:var(--accent);flex:none}
@media(max-width:700px){
  .creds-bar .wrap-wide{display:grid;grid-template-columns:1fr 1fr;
    gap:12px 18px;padding-block:14px}
  .chip{white-space:normal;align-items:flex-start;font-size:.78rem;line-height:1.35}
  .chip svg{margin-top:.15em}
}
@media(max-width:400px){
  .creds-bar .wrap-wide{gap:10px 14px}
  .chip{font-size:.75rem}
}

/* ---------- Stat bar ----------------------------------------------------- */
/* Deliberately NOT four equal boxed cells. Columns are sized to their own copy
   and the numerals sit straight on the navy with no card containers. */
.stats{background:var(--navy);color:#fff;position:relative}
.stats::after{content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,transparent,var(--accent-lite),transparent)}
.stat-grid{display:grid;grid-template-columns:repeat(4,1fr);
  gap:clamp(24px,3vw,46px);padding-block:clamp(40px,4.6vw,62px)}
.stat-ic{display:block;width:30px;height:30px;color:var(--accent-lite);margin-bottom:.85rem}
.stat-ic svg{width:100%;height:100%}
.stat b{display:block;font-family:var(--display);font-weight:700;
  font-size:clamp(2.3rem,4.4vw,3.4rem);color:var(--accent-lite);line-height:.95;
  letter-spacing:-.03em}
.stat .stat-l{display:block;font-size:1rem;font-weight:600;color:#fff;margin-top:.55rem}
.stat small{display:block;font-size:.78rem;color:rgba(255,255,255,.6);margin-top:.28rem}
.stat small a{color:inherit;text-decoration:underline;text-decoration-color:rgba(255,255,255,.35);text-underline-offset:3px}
.stat small a:hover{color:#fff}
@media(max-width:820px){.stat-grid{grid-template-columns:1fr 1fr;gap:30px}}
@media(max-width:359px){.stat-grid{grid-template-columns:1fr}}

/* ---------- Intro / authority -------------------------------------------- */
.intro-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(38px,5vw,84px);align-items:center}
.intro-copy p{color:var(--ink-soft);font-size:1.03rem}
.intro-copy strong{color:var(--navy);font-weight:600}
.intro-media{position:relative}
.intro-media .shot{border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow-lg)}
.intro-media .shot img{width:100%;height:auto;aspect-ratio:4/3;object-fit:cover}
.intro-media .badge{
  position:absolute;right:-14px;bottom:-24px;background:#fff;border:1px solid var(--rule);
  border-radius:var(--r-md);box-shadow:var(--shadow-md);padding:16px 20px;text-align:center;max-width:200px;
}
.intro-media .badge b{display:block;font-family:var(--display);font-size:2rem;color:var(--navy);line-height:1}
.intro-media .badge span{font-size:.78rem;color:var(--ink-soft);display:block;margin-top:.3rem;line-height:1.4}
@media(max-width:900px){.intro-grid{grid-template-columns:1fr}.intro-media .badge{right:8px}}

/* ---------- Services ----------------------------------------------------- */
/* A bento, not four equal cards. Every cell uses the SAME treatment (photo on
   top, copy below) so no single service is visually privileged; only the cell
   footprint varies. Wide, upright, upright, wide. */
.svc-grid{display:grid;grid-template-columns:repeat(4,1fr);
  gap:clamp(14px,1.6vw,20px)}
/* Client requested 2026-08-31: the big four are equal boxes, not a bento. */

.svc{position:relative;display:flex;flex-direction:column;background:#fff;
  border:1px solid var(--rule);border-radius:var(--r-md);overflow:hidden;
  text-decoration:none;color:inherit;
  transition:transform .38s var(--ease),box-shadow .38s var(--ease),border-color .38s}
.svc::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;z-index:3;
  background:linear-gradient(90deg,var(--accent),var(--accent-lite));
  transform:scaleX(0);transform-origin:left;transition:transform .45s var(--ease)}
.svc:hover::before,.svc:focus-visible::before{transform:scaleX(1)}
.svc:hover{transform:translateY(-6px);box-shadow:var(--shadow-lg);border-color:transparent}
.svc-img{aspect-ratio:16/10;overflow:hidden;background:var(--paper-2)}
.svc-img img{width:100%;height:100%;object-fit:cover;transition:transform .7s var(--ease)}
.svc:hover .svc-img img{transform:scale(1.07)}
.svc-body{padding:20px 22px 24px;display:flex;flex-direction:column;flex:1}
.svc h3{margin-bottom:.45rem;transition:color .25s}
.svc:hover h3{color:var(--accent)}
.svc p{font-size:.92rem;color:var(--ink-soft);line-height:1.6;flex:1}
.svc .go{display:inline-flex;align-items:center;gap:.5em;margin-top:1rem;
  font-size:.85rem;font-weight:600;color:var(--accent)}
.svc .go svg{width:14px;height:14px;transition:transform .3s var(--ease)}
.svc:hover .go svg{transform:translateX(4px)}
/* Wide cells get a shallower photo so the two rows stay balanced. */


@media(max-width:900px){
  .svc-grid{grid-template-columns:1fr 1fr}
}
@media(max-width:600px){
  .svc-grid{grid-template-columns:1fr}
}

/* The remaining six services: compact photo cards, so all ten are shown with a
   real visual rather than six of them being icon-only list rows. */
.mini-grid{display:grid;grid-template-columns:repeat(5,1fr);
  gap:clamp(14px,1.6vw,20px);margin-top:clamp(16px,1.8vw,22px)}
.svc-mini{position:relative;display:flex;flex-direction:column;background:#fff;
  border:1px solid var(--rule);border-radius:var(--r-md);overflow:hidden;
  text-decoration:none;color:inherit;
  transition:transform .32s var(--ease),box-shadow .32s var(--ease),border-color .32s}
.svc-mini::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;z-index:3;
  background:linear-gradient(90deg,var(--accent),var(--accent-lite));
  transform:scaleX(0);transform-origin:left;transition:transform .45s var(--ease)}
.svc-mini:hover::before,.svc-mini:focus-visible::before{transform:scaleX(1)}
.svc-mini:hover{transform:translateY(-5px);box-shadow:var(--shadow-md);border-color:transparent}
.svc-mini-img{position:relative;aspect-ratio:16/9;overflow:hidden;background:var(--paper-2);
  border-bottom:1px solid var(--rule)}
/* The floor plan schematic is a white document. Without a tinted ground it
   dissolves into the white card, unlike the photographic tiles. */
.svc-mini-img.is-doc{background:var(--paper-2);padding:10px}
.svc-mini-img.is-doc img{object-fit:contain;mix-blend-mode:multiply}
.svc-mini-img img{width:100%;height:100%;object-fit:cover;transition:transform .6s var(--ease)}
.svc-mini:hover .svc-mini-img img{transform:scale(1.06)}
.svc-mini-body{padding:16px 18px 20px}
.svc-mini h3{font-size:1rem;margin-bottom:.3rem;transition:color .25s}
.svc-mini:hover h3{color:var(--accent)}
.svc-mini p{font-size:.85rem;color:var(--ink-soft);line-height:1.55;margin:0}
@media(max-width:1100px){.mini-grid{grid-template-columns:repeat(3,1fr)}}
@media(max-width:760px){.mini-grid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.mini-grid{grid-template-columns:1fr}}

/* ---------- Portfolio ---------------------------------------------------- */
.gal-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(10px,1.2vw,16px)}
.gal-grid .ph{position:relative;overflow:hidden;border-radius:var(--r-md);cursor:zoom-in;
  background:var(--paper-2);border:0;padding:0;display:block;aspect-ratio:3/2;margin:0;width:100%}
.gal-grid .ph.tall{grid-row:span 2;aspect-ratio:auto;align-self:stretch}
.gal-grid .ph img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease)}
.gal-grid .ph:hover img{transform:scale(1.06)}
.gal-grid .ph figcaption{
  position:absolute;left:0;right:0;bottom:0;padding:34px 16px 14px;color:#fff;font-size:.82rem;font-weight:500;
  background:linear-gradient(transparent,rgba(19,37,70,.88));opacity:0;transform:translateY(6px);
  transition:opacity .3s,transform .3s var(--ease);text-align:left;
}
.gal-grid .ph:hover figcaption,.gal-grid .ph:focus-within figcaption{opacity:1;transform:none}
@media(max-width:900px){
  /* Two even columns, four rows, no feature cell and no orphan. */
  .gal-grid{grid-template-columns:1fr 1fr}
  .gal-grid .ph.tall{grid-row:auto;aspect-ratio:3/2}
}

/* ---------- Industries --------------------------------------------------- */
/* Two-column hairline list, now with a small square photo per row so every
   property type is actually shown. One border direction only, no card boxes. */
.ind-grid{display:grid;grid-template-columns:1fr 1fr;
  column-gap:clamp(28px,4vw,64px);border-top:1px solid var(--rule)}
.ind{position:relative;display:flex;align-items:center;gap:18px;
  padding:18px 4px 18px 0;border-bottom:1px solid var(--rule);
  text-decoration:none;color:inherit}
.ind-thumb,.ind-txt{transition:transform .34s var(--ease)}
.ind:hover .ind-thumb,.ind:hover .ind-txt,
.ind:focus-visible .ind-thumb,.ind:focus-visible .ind-txt{transform:translateX(11px)}
.ind-thumb{flex:none;width:clamp(84px,9vw,124px);aspect-ratio:1;border-radius:var(--r-sm);
  overflow:hidden;background:var(--paper-2);display:block}
.ind-thumb img{width:100%;height:100%;object-fit:cover;transition:transform .55s var(--ease)}
.ind:hover .ind-thumb img{transform:scale(1.09)}
.ind-txt{display:block;min-width:0}
.ind b{display:block;font-family:var(--display);font-weight:600;font-size:1.06rem;
  color:var(--navy);margin-bottom:.1rem;transition:color .25s}
.ind:hover b{color:var(--accent)}
.ind-txt>span{display:block;font-size:.85rem;color:var(--ink-soft);line-height:1.45}
.ind::after{content:"";position:absolute;left:0;top:18px;bottom:18px;width:2px;
  background:var(--accent);transform:scaleY(0);transform-origin:top;
  transition:transform .35s var(--ease)}
.ind:hover::after{transform:scaleY(1)}
@media(max-width:700px){.ind-grid{grid-template-columns:1fr}}

/* ---------- Process ------------------------------------------------------ */
/* Two-up ladder. Numbered because it is a sequence, but the verb still leads
   the heading so the number is an index, not a "Stage 1" label. */
.steps{display:grid;grid-template-columns:1fr 1fr;
  gap:clamp(26px,3.2vw,46px) clamp(34px,5vw,76px);counter-reset:step}
.step{position:relative;padding-left:clamp(56px,5.4vw,74px);counter-increment:step}
.step::before{content:counter(step,decimal-leading-zero);position:absolute;left:0;top:-.14em;
  font-family:var(--display);font-weight:700;font-size:clamp(1.7rem,2.4vw,2.15rem);
  line-height:1;color:var(--accent-lite);letter-spacing:-.03em}
.step::after{content:"";position:absolute;left:2px;top:clamp(2.1rem,3vw,2.7rem);bottom:.3rem;
  width:2px;background:linear-gradient(var(--accent-lite),transparent)}
.step h3{color:#fff;font-size:clamp(1.12rem,1.7vw,1.32rem);margin-bottom:.5rem}
.step p{font-size:.94rem;color:rgba(255,255,255,.76);line-height:1.65;max-width:44ch}
@media(max-width:720px){.steps{grid-template-columns:1fr}}

/* ---------- Dark section ------------------------------------------------- */
/* A dark section can take a photographic ground. The gradient is heavy enough
   that white body copy and the form card keep their contrast; measured, not
   eyeballed. Sits under .dark::before so the radial glows still read. */
.dark.has-photo{isolation:isolate}
.dark>.sect-photo{position:absolute;inset:0;z-index:0;overflow:hidden}
.sect-photo img{width:100%;height:100%;object-fit:cover;object-position:center 62%}
.sect-photo::after{content:"";position:absolute;inset:0;
  background:linear-gradient(105deg,rgba(16,31,60,.96) 0%,rgba(16,31,60,.9) 46%,rgba(16,31,60,.72) 100%)}
.dark.has-photo>.wrap,.dark.has-photo>.wrap-wide{position:relative;z-index:2}
.dark{background:var(--navy-deep);color:#fff;position:relative;overflow:hidden}
.dark h2,.dark h3{color:#fff}
.dark .lede{color:rgba(255,255,255,.78)}
.dark::before{
  content:"";position:absolute;inset:0;opacity:.55;pointer-events:none;
  background:radial-gradient(760px 420px at 82% 8%,rgba(48,104,207,.16),transparent 62%),
             radial-gradient(660px 400px at 6% 96%,rgba(42,75,132,.55),transparent 60%);
  animation:glowDrift 38s ease-in-out infinite alternate;
}
/* Barely perceptible per second, but it keeps the dark bands from reading flat. */
@keyframes glowDrift{from{transform:translate3d(0,0,0) scale(1)}to{transform:translate3d(-2.4%,1.6%,0) scale(1.09)}}
.dark>*{position:relative}

/* ---------- Packages ----------------------------------------------------- */
/* Three plans, but not three equal cards: the recommended plan is scaled up and
   filled navy so the eye lands on it first. */
.pkg-grid{display:grid;grid-template-columns:1fr 1.14fr 1fr;
  gap:clamp(14px,1.8vw,22px);align-items:stretch}
/* stretch + a column flex inside means all three cards share one height and the
   buttons sit on a common baseline, whatever each plan's feature count is. */
.pkg{position:relative;display:flex;flex-direction:column;background:#fff;
  border:1px solid var(--rule);border-radius:var(--r-md);padding:30px 26px;
  transition:transform .35s var(--ease),box-shadow .35s var(--ease)}
.pkg:hover{transform:translateY(-5px);box-shadow:var(--shadow-lg)}
.pkg ul{flex:1}
.pkg .btn{margin-top:auto}

.pkg.feat{background:var(--navy);border-color:var(--navy);color:#fff;
  padding:40px 30px 30px;box-shadow:var(--shadow-lg);z-index:2}
.pkg.feat h3{color:rgba(255,255,255,.72)}
.pkg.feat .price{color:#fff}
.pkg.feat .from{color:rgba(255,255,255,.6)}
.pkg.feat ul{border-top-color:rgba(255,255,255,.2)}
.pkg.feat li{color:rgba(255,255,255,.86)}
.pkg.feat li svg{color:var(--accent-lite)}

.pkg-tag{position:absolute;top:-12px;left:30px;background:var(--accent);color:#fff;
  font-size:.7rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  padding:.42em .8em;border-radius:var(--r-pill)}
.pkg h3{font-size:.9rem;letter-spacing:.14em;text-transform:uppercase;
  font-family:var(--sans);font-weight:700;color:var(--ink-soft)}
.pkg .price{font-family:var(--display);font-weight:700;
  font-size:clamp(2.5rem,3.8vw,3.1rem);color:var(--navy);line-height:1;
  margin:.5rem 0 .1rem;letter-spacing:-.04em}
.pkg.feat .price{font-size:clamp(2.9rem,4.6vw,3.8rem)}
.pkg .price sup{font-size:.42em;vertical-align:.9em;margin-right:.06em;font-weight:500}
.pkg .from{font-size:.79rem;color:var(--ink-faint)}
.pkg ul{list-style:none;margin:1.3rem 0;padding:1.15rem 0 0;border-top:1px solid var(--rule)}
.pkg li{display:flex;gap:.7em;font-size:.89rem;color:var(--ink-soft);padding:.34em 0;line-height:1.5}
.pkg li svg{width:15px;height:15px;flex:none;color:var(--accent);margin-top:.28em}
.pkg .btn{width:100%}
@media(max-width:900px){
  .pkg-grid{grid-template-columns:1fr;align-items:start}
  .pkg.feat{padding:32px 26px}
  .pkg ul{flex:0}
}

/* ---------- Single service price list (pricing page) --------------------- */
/* One card per service family, each a plain name / price ledger, so an agent
   can find a line and its cost without reading a paragraph. */
.svc-prices{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.8vw,22px);align-items:start}
.svc-group{background:#fff;border:1px solid var(--rule);border-radius:var(--r-md);padding:clamp(20px,2.2vw,26px)}
.svc-group h3{font-size:1.14rem;color:var(--navy)}
.svc-group h3 a{color:inherit;text-decoration:none}
.svc-group h3 a:hover{color:var(--accent)}
.svc-group > p{font-size:.84rem;color:var(--ink-faint);margin-top:.3rem;line-height:1.5}
.svc-list{list-style:none;margin:1rem 0 0;padding:0;border-top:1px solid var(--rule)}
.svc-list li{display:flex;justify-content:space-between;align-items:baseline;gap:1rem;
  padding:.72rem 0;border-bottom:1px solid var(--rule);font-size:.92rem;color:var(--ink);line-height:1.4}
.svc-list li:last-child{border-bottom:0;padding-bottom:0}
.svc-list small{display:block;font-size:.78rem;color:var(--ink-faint);margin-top:.15rem}
.svc-list b{font-family:var(--display);font-weight:700;font-size:1.08rem;color:var(--navy);white-space:nowrap}
.svc-list b small{display:inline;font-family:var(--sans);font-weight:500;font-size:.74rem;color:var(--ink-faint);margin:0 0 0 .15em}
.svc-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:14px 24px;
  margin-top:clamp(22px,2.6vw,32px)}
.svc-foot p{font-size:.88rem;color:var(--ink-soft);max-width:70ch;margin:0}
@media(max-width:1000px){.svc-prices{grid-template-columns:1fr 1fr}}
@media(max-width:640px){.svc-prices{grid-template-columns:1fr}}

/* ---------- Reviews ------------------------------------------------------ */
.score{display:flex;align-items:center;justify-content:center;
  gap:clamp(16px,2.6vw,38px);flex-wrap:wrap;background:#fff;
  border:1px solid var(--rule);border-radius:var(--r-md);
  padding:clamp(20px,2.4vw,28px) clamp(22px,3vw,38px);
  box-shadow:var(--shadow-sm);margin-bottom:clamp(30px,3.4vw,46px);
  border-top:3px solid var(--gold)}
.score-main{display:flex;flex-direction:column;align-items:center;gap:.3rem}
.score-n{font-family:var(--display);font-size:clamp(2.6rem,4vw,3.4rem);font-weight:700;
  color:var(--navy);line-height:1;letter-spacing:-.04em}
.score-stars{color:var(--gold);letter-spacing:.16em;font-size:1.15rem;line-height:1}
.score-m{font-size:.9rem;color:var(--ink-soft);line-height:1.5;margin:0}
.score-m b{color:var(--navy);font-size:1rem}
.score-div{width:1px;align-self:stretch;background:var(--rule)}
.score-cta{display:inline-flex;align-items:center;gap:.55em;flex-direction:row-reverse;
  font-size:.88rem;font-weight:600;color:var(--accent);text-decoration:none;
  padding:.6em 1.05em;border:1px solid var(--rule-strong);border-radius:var(--r-pill);
  transition:background .25s,border-color .25s,color .25s}
.score-cta svg{width:14px;height:14px;transition:transform .3s var(--ease)}
.score-cta:hover{background:var(--accent);border-color:var(--accent);color:#fff}
.score-cta:hover svg{transform:translateX(3px)}
@media(max-width:760px){.score-div{display:none}.score{gap:14px}}

/* One review at a time. The track is a single-column grid with every slide
   stacked in the same cell, so the slider is exactly as tall as its tallest
   quote and never jumps between slides. */
.rev-slider{max-width:820px;margin-inline:auto}
.rev-track{display:grid}
.rev{grid-area:1/1;background:none;border:0;padding:0;margin:0;
  display:flex;flex-direction:column;align-items:center;text-align:center;
  opacity:0;visibility:hidden;transform:translateY(10px);
  transition:opacity .55s var(--ease),transform .55s var(--ease),visibility .55s}
.rev.is-on{opacity:1;visibility:visible;transform:none}
.rev:hover{transform:none;box-shadow:none}
.rev .rstars{color:var(--gold-deep);letter-spacing:.18em;font-size:1.05rem;margin-bottom:1rem}
.rev>figure{margin:0}
.rev blockquote{margin:0;font-family:var(--display);font-weight:500;
  font-size:clamp(1.15rem,2vw,1.6rem);line-height:1.4;color:var(--navy);
  letter-spacing:-.015em;max-width:44ch}
.rev figcaption{margin-top:1.3rem;padding-top:1rem;border-top:1px solid var(--rule);
  font-size:.86rem;min-width:180px}
.rev figcaption b{color:var(--navy);display:block;font-weight:600}
.rev figcaption span{color:var(--ink-faint);font-size:.8rem}

.rev-nav{display:flex;align-items:center;justify-content:center;gap:clamp(14px,2vw,22px);
  margin-top:clamp(22px,2.6vw,32px)}
.rev-arrow{width:40px;height:40px;flex:none;border-radius:50%;cursor:pointer;
  border:1px solid var(--rule-strong);background:#fff;color:var(--navy);
  display:grid;place-items:center;
  transition:background .25s,border-color .25s,color .25s,transform .25s var(--ease)}
.rev-arrow svg{width:17px;height:17px}
.rev-next svg{transform:scaleX(-1)}
.rev-arrow:hover{background:var(--accent);border-color:var(--accent);color:#fff}
.rev-arrow:active{transform:scale(.94)}

.rev-dots{display:flex;align-items:center;gap:9px}
.rev-dot{width:9px;height:9px;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:var(--rule-strong);transition:background .3s,transform .3s var(--ease)}
.rev-dot[aria-current="true"]{background:var(--accent);transform:scale(1.35)}
.rev-dot:hover{background:var(--accent)}

/* ---------- Trust marquee + credentials ---------------------------------- */
.trust-lead{text-align:center;font-family:var(--display);font-weight:500;
  font-size:clamp(.98rem,1.5vw,1.14rem);color:var(--ink-soft);margin:0}
.marquee{overflow:hidden;position:relative;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent);
          mask-image:linear-gradient(90deg,transparent,#000 7%,#000 93%,transparent)}
.marquee-track{display:flex;align-items:center;width:max-content;animation:slide 64s linear infinite}
.marquee:hover .marquee-track{animation-play-state:paused}
@keyframes slide{to{transform:translateX(-50%)}}
/* Real partner marks, each pre-composited onto a uniform 2:1 tile so wildly
   different source aspect ratios and backgrounds share one footprint. */
.plogo{flex:none;display:block;width:clamp(190px,17vw,250px);
  margin-inline:clamp(16px,2vw,30px);border:1px solid var(--rule);
  border-radius:var(--r-sm);overflow:hidden;background:#fff;
  transition:border-color .3s,box-shadow .3s,transform .3s var(--ease)}
.plogo img{width:100%;height:auto;display:block}
.plogo:hover{border-color:var(--accent);box-shadow:var(--shadow-sm);transform:translateY(-3px)}
/* Credentials that are not brokerages (ABoR, Supra) sit under the marquee
   rather than in it, per the 2026-09-18 client call. */
.trust-creds{list-style:none;margin:clamp(26px,3vw,40px) auto 0;padding:0;display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,2vw,28px);max-width:980px}
.trust-creds li{text-align:center;display:grid;gap:.3rem}
.trust-creds b{font-family:var(--display);font-weight:600;font-size:1.02rem;color:var(--ink)}
.trust-creds span{font-size:.86rem;color:var(--ink-soft);line-height:1.5}
@media(max-width:700px){.trust-creds{grid-template-columns:1fr;gap:16px}}

.creds{display:grid;grid-template-columns:repeat(2,1fr);
  gap:clamp(16px,2vw,28px) clamp(26px,3.4vw,54px);
  margin-top:clamp(28px,3.2vw,42px);padding-top:clamp(24px,2.8vw,36px);
  border-top:1px solid var(--rule)}
@media(min-width:1000px){.creds{grid-template-columns:repeat(4,1fr)}}
@media(max-width:520px){.creds{grid-template-columns:1fr}}
.cred{display:flex;align-items:flex-start;gap:12px;background:none;padding:0}
.cred svg{width:20px;height:20px;color:var(--accent);flex:none;margin-top:.15em}
.cred b{display:block;font-size:.89rem;color:var(--navy);font-weight:600;line-height:1.35}
.cred span{font-size:.79rem;color:var(--ink-soft)}

/* ---------- Service areas ------------------------------------------------ */
/* Now a light section, so the city pills are outlined rather than knocked out. */
/* Copy and pills share the left column, the map fills the right. On phones
   the map sits between them, directly above the pills it is linked to. */
.area-grid{display:grid;grid-template-columns:1fr 1.05fr;
  grid-template-areas:"copy map" "links map";
  column-gap:clamp(34px,4.6vw,72px);row-gap:clamp(26px,2.8vw,36px);align-items:center}
.area-copy{grid-area:copy;align-self:end}
.area-links{grid-area:links;align-self:start}
.area-grid>.area-map{grid-area:map}
html:not(.js) .area-grid,.area-grid.no-map{grid-template-areas:"copy links"}
.areas{display:flex;flex-wrap:wrap;gap:10px}
.area{display:inline-flex;align-items:center;gap:.55em;padding:.62em 1.05em;
  border-radius:var(--r-pill);background:#fff;border:1px solid var(--rule-strong);
  color:var(--navy);text-decoration:none;font-size:.89rem;font-weight:500;
  transition:background .25s,border-color .25s,color .25s,transform .25s var(--ease)}
.area:hover{background:var(--accent);border-color:var(--accent);color:#fff;
  transform:translateY(-2px)}
.area svg{width:13px;height:13px;color:var(--accent);flex:none;transition:color .25s}
.area:hover svg{color:#fff}
.area.lead{background:var(--navy);border-color:var(--navy);color:#fff;font-weight:600}
.area.lead svg{color:var(--accent-lite)}
.area.lead:hover{background:var(--accent);border-color:var(--accent)}
@media(max-width:900px){
  .area-grid{grid-template-columns:1fr;grid-template-areas:"copy" "map" "links"}
  html:not(.js) .area-grid,.area-grid.no-map{grid-template-areas:"copy" "links"}
}

/* ---------- About -------------------------------------------------------- */
.about-grid{display:grid;grid-template-columns:.85fr 1fr;gap:clamp(36px,5vw,76px);align-items:center}
.about-photo{border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--shadow-lg)}
/* height:auto matters — without it the img's height attribute is used as a
   presentational hint and aspect-ratio is ignored, stretching the photo. */
.about-photo img{width:100%;height:auto;aspect-ratio:4/5;object-fit:cover}
.sig{font-family:var(--display);font-size:1.02rem;font-weight:600;color:var(--navy);margin-top:1.4rem;
  letter-spacing:.01em}
@media(max-width:900px){.about-grid{grid-template-columns:1fr}}

/* ---------- FAQ ---------------------------------------------------------- */
.faq{max-width:880px;margin-inline:auto;border-top:1px solid var(--rule)}
.faq details{border-bottom:1px solid var(--rule)}
.faq summary{
  list-style:none;cursor:pointer;padding:22px 48px 22px 0;position:relative;
  font-family:var(--display);font-weight:600;font-size:clamp(1.02rem,1.5vw,1.2rem);color:var(--navy);line-height:1.35;transition:color .2s;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--accent)}
.faq summary::after,.faq summary::before{content:"";position:absolute;right:8px;top:50%;background:var(--accent);
  transition:transform .3s var(--ease),opacity .3s}
.faq summary::after{width:14px;height:1.5px;margin-top:-.75px}
.faq summary::before{width:1.5px;height:14px;margin-top:-7px;right:14px}
.faq details[open] summary::before{transform:rotate(90deg);opacity:0}
.faq-a{padding:0 48px 24px 0;color:var(--ink-soft);font-size:.98rem;line-height:1.7}
.faq details[open] .faq-a{animation:fadein .35s var(--ease)}
@keyframes fadein{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.faq-a a{color:var(--accent);text-decoration-thickness:1px;text-underline-offset:2px}

/* ---------- Contact / CTA ------------------------------------------------ */
.cta-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(36px,4.6vw,72px);align-items:start}
@media(max-width:900px){.cta-grid{grid-template-columns:1fr}}
.form-card{background:#fff;border-radius:var(--r-lg);padding:clamp(24px,3vw,36px);box-shadow:var(--shadow-lg)}
/* Pre-load height floor only; form_embed.js sets the real height. Don't raise it. */
.qf-embed iframe{display:block;width:100%;min-height:320px;border:0;background:transparent}
.field{margin-bottom:16px}
.field label{display:block;font-size:.8rem;font-weight:600;color:var(--navy);margin-bottom:.42rem;letter-spacing:.02em}
.field input,.field select,.field textarea{
  width:100%;padding:.82em .95em;border:1px solid var(--rule-strong);border-radius:var(--r-sm);
  font:inherit;font-size:.94rem;color:var(--ink);background:var(--paper);
  transition:border-color .2s,box-shadow .2s,background .2s;
}
.field input:focus,.field select:focus,.field textarea:focus{
  outline:none;border-color:var(--navy);background:#fff;box-shadow:0 0 0 3px rgba(28,51,94,.1)}
.field textarea{resize:vertical;min-height:106px}
.field-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
@media(max-width:560px){.field-row{grid-template-columns:1fr}}
.form-note{font-size:.78rem;color:var(--ink-faint);margin-top:.9rem;text-align:center}

.contact-list{list-style:none;margin:2rem 0 0;padding:0;display:grid;gap:18px}
.contact-list li{display:flex;gap:14px;align-items:flex-start}
.contact-list .ic{width:40px;height:40px;flex:none;border-radius:10px;background:rgba(255,255,255,.1);
  border:1px solid rgba(255,255,255,.22);display:grid;place-items:center;color:var(--accent-lite)}
.contact-list .ic svg{width:17px;height:17px}
.contact-list b{display:block;font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.62);
  font-weight:600;margin-bottom:.15rem}
.contact-list a,.contact-list p{color:#fff;text-decoration:none;font-size:1.02rem;margin:0;line-height:1.5}
.contact-list a:hover{color:var(--accent-lite)}
.socials{display:flex;gap:10px;margin-top:1.8rem}
.socials a{width:40px;height:40px;border-radius:10px;border:1px solid rgba(255,255,255,.22);display:grid;place-items:center;
  color:#fff;transition:background .25s,border-color .25s,transform .25s var(--ease)}
.socials a:hover{background:var(--accent);border-color:var(--accent);transform:translateY(-3px)}
.socials svg{width:17px;height:17px}

/* ---------- Footer ------------------------------------------------------- */
.ftr{background:var(--navy-deep);color:rgba(255,255,255,.7);font-size:.88rem}
.ftr-grid{display:grid;grid-template-columns:1.7fr 1fr 1fr 1fr 1fr;gap:clamp(24px,3vw,44px);padding-block:clamp(52px,6vw,76px)}
.ftr h3{font-family:var(--sans);font-size:.74rem;font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:#fff;margin-bottom:1.05rem}
.ftr ul{list-style:none;margin:0;padding:0;display:grid;gap:.55rem}
.ftr a{text-decoration:none;transition:color .2s}
.ftr a:hover{color:var(--accent-lite)}
.ftr-brand .brand-mark{width:169px;height:35px;color:#fff;margin-bottom:1.2rem}
.ftr-brand p{font-size:.88rem;line-height:1.65;max-width:36ch}
.ftr-nap{margin-top:1.3rem;display:grid;gap:.4rem;font-size:.86rem;font-style:normal}
.ftr-nap a{color:#fff}
.ftr-bot{border-top:1px solid rgba(255,255,255,.12);padding-block:22px;display:flex;justify-content:space-between;
  gap:16px;flex-wrap:wrap;font-size:.8rem;color:rgba(255,255,255,.55)}
.ftr-bot ul{display:flex;gap:20px;list-style:none;margin:0;padding:0}
/* The office address sits in the small print on purpose: it corroborates the
   Google Business Profile for NAP matching without inviting walk ins. */
.ftr-office{display:block;margin-top:.35rem;font-size:.74rem}
.ftr-office a{color:inherit;text-decoration:underline;text-underline-offset:2px}
@media(max-width:1060px){.ftr-grid{grid-template-columns:1fr 1fr 1fr}.ftr-brand{grid-column:1/-1}}
@media(max-width:620px){.ftr-grid{grid-template-columns:1fr 1fr}}

/* ---------- Lightbox ----------------------------------------------------- */
.lb{position:fixed;inset:0;z-index:200;background:rgba(11,22,42,.94);
  display:grid;place-items:center;padding:24px;
  opacity:0;visibility:hidden;transition:opacity .3s,visibility .3s;backdrop-filter:blur(4px)}
.lb.open{opacity:1;visibility:visible}
/* The figure is the click target for closing; the image itself is not, so a
   click anywhere on the backdrop dismisses but a click on the photo does not. */
.lb img{max-width:min(1180px,90vw);max-height:82vh;width:auto;
  border-radius:var(--r-md);box-shadow:var(--shadow-lg);
  transition:opacity .22s var(--ease)}
.lb.is-swapping img{opacity:0}
.lb-close{position:absolute;top:18px;right:18px;width:44px;height:44px;border-radius:50%;
  border:1px solid rgba(255,255,255,.32);background:rgba(255,255,255,.08);color:#fff;
  cursor:pointer;display:grid;place-items:center;transition:background .25s}
.lb-close:hover{background:rgba(255,255,255,.2)}
.lb-close svg{width:18px;height:18px}

.lb-nav{position:absolute;top:50%;transform:translateY(-50%);
  width:52px;height:52px;border-radius:50%;border:1px solid rgba(255,255,255,.3);
  background:rgba(255,255,255,.09);color:#fff;cursor:pointer;
  display:grid;place-items:center;transition:background .25s,border-color .25s}
.lb-nav:hover{background:rgba(255,255,255,.22);border-color:rgba(255,255,255,.55)}
.lb-nav svg{width:22px;height:22px}
.lb-prev{left:clamp(10px,3vw,34px)}
.lb-next{right:clamp(10px,3vw,34px)}

.lb-cap{position:absolute;bottom:44px;left:0;right:0;text-align:center;
  color:rgba(255,255,255,.82);font-size:.88rem;padding-inline:80px;margin:0}
.lb-count{position:absolute;bottom:20px;left:0;right:0;text-align:center;
  color:rgba(255,255,255,.5);font-size:.76rem;letter-spacing:.1em;margin:0}
@media(max-width:640px){
  .lb-nav{width:42px;height:42px}
  .lb-cap{padding-inline:16px;bottom:48px;font-size:.8rem}
}
/* Horizontal swipes go to the script (photo to photo); vertical and pinch stay native. */
.lb{touch-action:pan-y pinch-zoom}
@media(max-width:700px){.lb-close{transition:background .25s,top .2s var(--ease)}}

/* ---------- Scroll reveal ------------------------------------------------ */
/* Default is a short rise. data-reveal="left|right" lets the two halves of a
   split section come in from their own side; "wipe" is for framed photos. */
[data-reveal]{opacity:0;transform:translate3d(0,22px,0);transition:opacity .7s var(--ease),transform .7s var(--ease)}
[data-reveal].in{opacity:1;transform:none}
[data-reveal="left"]{transform:translate3d(-32px,0,0)}
[data-reveal="right"]{transform:translate3d(32px,0,0)}
@media(max-width:900px){
  [data-reveal="left"],[data-reveal="right"]{transform:translate3d(0,22px,0)}
}

/* The wrapper stays put so its shadow is never clipped; the photo inside is
   uncovered top to bottom and settles out of a slight overscale. */
[data-reveal="wipe"]{opacity:1;transform:none}
[data-reveal="wipe"] img{clip-path:inset(0 0 101% 0);transform:scale(1.06);
  transition:clip-path 1.1s var(--ease),transform 1.5s var(--ease)}
[data-reveal="wipe"].in img{clip-path:inset(0 0 0 0);transform:none}

/* The little accent rule on an eyebrow draws itself in with the block. */
[data-reveal] .eyebrow::before,.eyebrow[data-reveal]::before,
[data-stagger] .eyebrow::before{
  transform:scaleX(0);transform-origin:left;transition:transform .8s var(--ease) .18s}
[data-reveal].in .eyebrow::before,.eyebrow[data-reveal].in::before,
[data-stagger].in .eyebrow::before{transform:scaleX(1)}
[data-stagger]>*{opacity:0;transform:translateY(20px);transition:opacity .65s var(--ease),transform .65s var(--ease)}
[data-stagger].in>*{opacity:1;transform:none}
[data-stagger].in>*:nth-child(1){transition-delay:.04s}
[data-stagger].in>*:nth-child(2){transition-delay:.1s}
[data-stagger].in>*:nth-child(3){transition-delay:.16s}
[data-stagger].in>*:nth-child(4){transition-delay:.22s}
[data-stagger].in>*:nth-child(5){transition-delay:.28s}
[data-stagger].in>*:nth-child(6){transition-delay:.34s}
[data-stagger].in>*:nth-child(7){transition-delay:.4s}
[data-stagger].in>*:nth-child(8){transition-delay:.46s}
[data-stagger].in>*:nth-child(9){transition-delay:.52s}
[data-stagger].in>*:nth-child(10){transition-delay:.58s}

@media(prefers-reduced-motion:reduce){
  html:focus-within{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms !important;animation-iteration-count:1 !important;
    transition-duration:.001ms !important;scroll-behavior:auto !important}
  [data-reveal],[data-stagger]>*{opacity:1 !important;transform:none !important}
  [data-reveal="wipe"] img{clip-path:none !important;transform:none !important}
  [data-reveal] .eyebrow::before,.eyebrow[data-reveal]::before,
  [data-stagger] .eyebrow::before{transform:none !important}
  .hero-inner>*{animation:none !important;opacity:1 !important;transform:none !important}
  .hdr::after{display:none}
  .rev{transition:none !important}
  .lb img{transition:none !important}
}

/* =========================================================================
   INTERIOR PAGES
   Everything below is used by service, industry, service-area, guide and
   core pages. The home page does not use any of it. Same tokens, same
   motion rules and the same shape lock as the sections above.
   ========================================================================= */

/* ---------- Compact page hero -------------------------------------------
   Interior pages keep the photographic top so the transparent header state
   still works, but at roughly half the home hero height. Single still, no
   rotation, so there is exactly one image to pay for. */
.phero{position:relative;isolation:isolate;color:#fff;overflow:hidden;
  display:flex;align-items:flex-end;
  min-height:min(58svh,520px);
  padding-block:calc(clamp(52px,6vw,80px) + 78px) clamp(40px,4.6vw,64px)}
.phero-bg{position:absolute;inset:0;z-index:-2;background:var(--navy-deep)}
.phero-bg img{width:100%;height:100%;object-fit:cover;object-position:center 58%}
/* Same two-stop scrim shape the home hero uses: held through the nav band so
   white nav type clears AA, then falling off before the headline. */
.phero-bg::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(11,22,42,.72) 0%,rgba(11,22,42,.5) 42%,rgba(11,22,42,.78) 100%)}
.phero-inner{max-width:840px}
.phero h1{color:#fff;font-size:clamp(2.1rem,4.6vw,3.5rem);text-wrap:balance;margin-bottom:.2em}
.phero h1 em{color:var(--accent-lite);font-style:normal;font-weight:700}
.phero-sub{font-size:clamp(1.02rem,1.45vw,1.18rem);color:rgba(255,255,255,.88);
  line-height:1.62;max-width:60ch;margin:0}
.phero .btn-row{margin-top:clamp(22px,2.6vw,32px)}
/* Text-only variant for legal and utility pages that carry no photograph. */
.phero.is-plain{min-height:auto;background:var(--navy-deep);
  padding-block:calc(clamp(44px,5vw,64px) + 78px) clamp(34px,4vw,52px)}
.phero.is-plain .phero-bg{display:none}

/* ---------- Breadcrumbs -------------------------------------------------- */
.crumbs{font-size:.8rem;margin-bottom:1.1rem;color:rgba(255,255,255,.66)}
.crumbs ol{list-style:none;display:flex;flex-wrap:wrap;align-items:center;gap:.5em;margin:0;padding:0}
.crumbs a{color:rgba(255,255,255,.82);text-decoration:none;transition:color .2s}
.crumbs a:hover{color:#fff;text-decoration:underline;text-underline-offset:3px}
.crumbs li+li::before{content:"/";margin-right:.5em;color:rgba(255,255,255,.4)}
.crumbs [aria-current]{color:#fff}

/* ---------- Long-form body copy -----------------------------------------
   The audit's single biggest finding was 41 of 70 pages under a 0.04
   text-to-HTML ratio. Every interior page carries a real .prose block. */
.prose{max-width:70ch}
.prose>*+*{margin-top:1.15em}
.prose h2{font-size:clamp(1.5rem,2.5vw,2.05rem);margin-top:1.9em}
/* The heading that frames the intro copy sits at the very top of the block, so
   it drops the leading gap the run-of-page h2s carry. */
.prose>:first-child,.prose h2.prose-lead{margin-top:0}
.prose h3{font-size:clamp(1.1rem,1.65vw,1.32rem);margin-top:1.7em;color:var(--navy)}
.prose p,.prose li{color:var(--ink-soft);font-size:1.02rem;line-height:1.75}
.prose strong{color:var(--navy);font-weight:600}
.prose a{color:var(--accent);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}
.prose a:hover{color:var(--accent-deep)}
.prose ul,.prose ol{padding-left:1.3em;display:grid;gap:.5em;margin-block:1.15em}
.prose li::marker{color:var(--accent)}
.prose blockquote{margin:1.6em 0;padding:1.1em 0 1.1em 1.5em;border-left:3px solid var(--accent-line);
  font-family:var(--display);font-weight:500;font-size:1.1rem;color:var(--navy);line-height:1.55}
.prose blockquote cite{display:block;margin-top:.7em;font-family:var(--sans);font-size:.82rem;
  font-style:normal;color:var(--ink-faint);font-weight:400}

/* ---------- Body plus sticky rail ---------------------------------------
   Service and city pages run copy at a readable measure with a booking card
   parked alongside it, rather than pushing the CTA to the bottom only. */
.body-grid{display:grid;grid-template-columns:minmax(0,1fr) 330px;
  gap:clamp(34px,4.4vw,72px);align-items:start}
.rail{position:sticky;top:104px;display:grid;gap:18px}
.rail-card{background:#fff;border:1px solid var(--rule);border-radius:var(--r-lg);
  padding:clamp(22px,2.4vw,28px);box-shadow:var(--shadow-md)}
.rail-card.is-navy{background:var(--navy);border-color:var(--navy);color:#fff}
.rail-card h3{font-size:1.1rem;margin-bottom:.5rem}
.rail-card.is-navy h3{color:#fff}
.rail-card p{font-size:.89rem;color:var(--ink-soft);line-height:1.6}
/* The price block sits directly above the body copy, so it needs its own gap. */
.rail-price+p{margin-top:1rem}
.rail-card.is-navy p{color:rgba(255,255,255,.78)}
.rail-card .btn{width:100%;margin-top:1rem}
.rail-price{font-family:var(--display);font-weight:700;font-size:2.1rem;color:var(--navy);line-height:1}
.rail-card.is-navy .rail-price{color:#fff}
.rail-price sup{font-size:.44em;vertical-align:.85em;margin-right:.05em;font-weight:500}
.rail-price small{display:block;font-family:var(--sans);font-size:.76rem;font-weight:400;
  color:var(--ink-faint);margin-top:.4rem;letter-spacing:.01em}
.rail-card.is-navy .rail-price small{color:rgba(255,255,255,.6)}
/* "$200" on its own read as the only price. The lead label and the link out to
   the full table make it obvious it is a floor, not the whole menu. */
.rail-price-lead{display:block;font-family:var(--sans);font-size:.72rem;font-weight:600;
  letter-spacing:.11em;text-transform:uppercase;color:var(--ink-faint);margin-bottom:.5rem}
.rail-card.is-navy .rail-price-lead{color:var(--accent-lite)}
.rail-under{display:block;margin-top:.8rem;text-align:center;font-size:.83rem;
  color:var(--accent);text-decoration:underline;text-decoration-thickness:1px;
  text-underline-offset:3px;transition:color .2s var(--ease)}
.rail-card.is-navy .rail-under{color:rgba(255,255,255,.78)}
.rail-card.is-navy .rail-under:hover{color:#fff}
.rail-list{list-style:none;margin:1rem 0 0;padding:0;display:grid;gap:.6rem;font-size:.87rem}
.rail-list li{display:flex;gap:.6em;align-items:flex-start;color:var(--ink-soft);line-height:1.5}
.rail-list svg{width:14px;height:14px;flex:none;color:var(--accent);margin-top:.25em}
/* Contact rows swap the bold tick for outline phone/envelope marks, which need
   a touch more size to carry the same weight, and centring rather than a top
   offset now that each row is a single line. */
.rail-list.is-contact li{align-items:center}
.rail-list.is-contact svg{width:15px;height:15px;margin-top:0}
.rail-card.is-navy .rail-list li{color:rgba(255,255,255,.84)}
.rail-card.is-navy .rail-list svg{color:var(--accent-lite)}
@media(max-width:1000px){
  .body-grid{grid-template-columns:1fr}
  .rail{position:static;grid-template-columns:1fr 1fr;gap:18px}
  .prose{max-width:none}
}
@media(max-width:620px){.rail{grid-template-columns:1fr}}

/* ---------- Deliverables grid -------------------------------------------
   Numbered hairline rows, not cards. Deliberately a different family from
   the home page bento so a service page does not read as a home clone. */
.spec{display:grid;grid-template-columns:1fr 1fr;gap:0 clamp(28px,3.4vw,56px);
  counter-reset:spec;border-top:1px solid var(--rule)}
.spec-row{counter-increment:spec;padding:clamp(20px,2.2vw,26px) 0;border-bottom:1px solid var(--rule);
  display:grid;grid-template-columns:auto 1fr;gap:16px;align-items:start}
.spec-row::before{content:counter(spec,decimal-leading-zero);font-family:var(--display);
  font-weight:600;font-size:.8rem;color:var(--accent);letter-spacing:.08em;
  padding-top:.25em;min-width:2ch}
.spec-row b{display:block;font-family:var(--display);font-weight:600;
  font-size:1.02rem;color:var(--navy);margin-bottom:.3rem;line-height:1.3}
.spec-row span{display:block;font-size:.9rem;color:var(--ink-soft);line-height:1.62}
@media(max-width:760px){.spec{grid-template-columns:1fr}}

/* ---------- Tick list ---------------------------------------------------- */
.ticks{list-style:none;margin:0;padding:0;display:grid;gap:.75rem}
.ticks.two-up{grid-template-columns:1fr 1fr;gap:.75rem clamp(20px,2.6vw,40px)}
.ticks li{display:flex;gap:.7em;align-items:flex-start;font-size:.96rem;
  color:var(--ink-soft);line-height:1.6}
.ticks svg{width:16px;height:16px;flex:none;color:var(--accent);margin-top:.28em}
.dark .ticks li{color:rgba(255,255,255,.82)}
.dark .ticks svg{color:var(--accent-lite)}
@media(max-width:620px){.ticks.two-up{grid-template-columns:1fr}}

/* ---------- Comparison table --------------------------------------------
   Used by the Matterport and Zillow pages, which exist precisely because
   buyers cannot tell the two products apart. */
.cmp-wrap{overflow-x:auto;border:1px solid var(--rule);border-radius:var(--r-lg);background:#fff}
.cmp{width:100%;min-width:560px;border-collapse:collapse;font-size:.92rem}
.cmp th,.cmp td{padding:15px 18px;text-align:left;border-bottom:1px solid var(--rule);vertical-align:top}
.cmp thead th{background:var(--paper-2);font-family:var(--display);font-weight:600;
  color:var(--navy);font-size:.86rem;letter-spacing:.03em;white-space:nowrap}
.cmp tbody th{font-weight:600;color:var(--navy);width:30%}
.cmp td{color:var(--ink-soft);line-height:1.6}
.cmp tr:last-child th,.cmp tr:last-child td{border-bottom:0}
.cmp .yes{color:var(--accent);font-weight:600}
.cmp .no{color:var(--ink-faint)}

/* ---------- Card grid for hub pages -------------------------------------- */
.hub-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(16px,1.9vw,26px)}
.hub-grid.is-2{grid-template-columns:repeat(2,1fr)}
.hub{position:relative;display:flex;flex-direction:column;background:#fff;
  border:1px solid var(--rule);border-radius:var(--r-lg);overflow:hidden;
  text-decoration:none;color:inherit;
  transition:transform .35s var(--ease),box-shadow .35s var(--ease),border-color .35s}
.hub::before{content:"";position:absolute;top:0;left:0;right:0;height:3px;z-index:3;
  background:var(--accent);transform:scaleX(0);transform-origin:left;
  transition:transform .45s var(--ease)}
.hub:hover::before,.hub:focus-visible::before{transform:scaleX(1)}
.hub:hover{transform:translateY(-5px);box-shadow:var(--shadow-lg);border-color:transparent}
.hub-img{aspect-ratio:16/10;overflow:hidden;background:var(--paper-2)}
.hub-img img{width:100%;height:100%;object-fit:cover;transition:transform .65s var(--ease)}
.hub:hover .hub-img img{transform:scale(1.06)}
.hub-img.is-doc{background:var(--paper-2);padding:10px}
.hub-img.is-doc img{object-fit:contain;mix-blend-mode:multiply}
.hub-body{padding:20px 22px 24px;display:flex;flex-direction:column;flex:1}
.hub h3{font-size:1.08rem;margin-bottom:.4rem;transition:color .25s}
.hub:hover h3{color:var(--accent)}
.hub p{font-size:.89rem;color:var(--ink-soft);line-height:1.6;flex:1;margin:0}
.hub .go{display:inline-flex;align-items:center;gap:.5em;margin-top:1rem;
  font-size:.82rem;font-weight:600;color:var(--accent);letter-spacing:.02em}
.hub .go svg{width:14px;height:14px;transition:transform .3s var(--ease)}
.hub:hover .go svg{transform:translateX(4px)}
@media(max-width:900px){.hub-grid,.hub-grid.is-2{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.hub-grid,.hub-grid.is-2{grid-template-columns:1fr}}

/* ---------- Plain link row (nearby cities, related services) ------------- */
.linkrow{display:flex;flex-wrap:wrap;gap:10px}
.linkrow a{display:inline-flex;align-items:center;gap:.5em;padding:.6em 1em;
  border-radius:var(--r-pill);background:#fff;border:1px solid var(--rule-strong);
  color:var(--navy);text-decoration:none;font-size:.87rem;font-weight:500;
  transition:background .25s,border-color .25s,color .25s,transform .25s var(--ease)}
.linkrow a:hover{background:var(--accent);border-color:var(--accent);color:#fff;transform:translateY(-2px)}
.linkrow svg{width:13px;height:13px;flex:none;color:var(--accent);transition:color .25s}
.linkrow a:hover svg{color:#fff}

/* ---------- Small gallery strip (interior pages) ------------------------- */
.strip{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(10px,1.2vw,16px)}
.strip .ph{position:relative;overflow:hidden;border-radius:var(--r-md);cursor:zoom-in;
  margin:0;aspect-ratio:4/3;background:var(--paper-2)}
.strip .ph img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease)}
.strip .ph:hover img{transform:scale(1.06)}
.strip .ph figcaption{position:absolute;left:0;right:0;bottom:0;padding:22px 16px 13px;
  background:linear-gradient(180deg,transparent,rgba(11,22,42,.86));
  color:#fff;font-size:.8rem;opacity:0;transform:translateY(8px);
  transition:opacity .35s var(--ease),transform .35s var(--ease)}
.strip .ph:hover figcaption,.strip .ph:focus-within figcaption{opacity:1;transform:none}
@media(max-width:900px){.strip{grid-template-columns:1fr 1fr}}

/* ---------- Local facts panel (city pages) ------------------------------- */
.facts{display:grid;grid-template-columns:repeat(3,1fr);gap:1px;background:var(--rule);
  border:1px solid var(--rule);border-radius:var(--r-lg);overflow:hidden}
.fact{background:#fff;padding:clamp(20px,2.3vw,28px)}
.fact b{display:block;font-family:var(--display);font-weight:700;
  font-size:clamp(1.5rem,2.4vw,2rem);color:var(--navy);line-height:1}
.fact span{display:block;font-size:.84rem;color:var(--ink-soft);margin-top:.5rem;line-height:1.5}
@media(max-width:760px){.facts{grid-template-columns:1fr}}

.sect-head.is-wide{max-width:68ch}

/* ---------- Guide meta and contents -------------------------------------- */
.meta{display:flex;flex-wrap:wrap;gap:.4em 1.2em;font-size:.82rem;
  color:rgba(255,255,255,.66);margin-top:1rem}
.meta span{display:inline-flex;align-items:center;gap:.45em}
.meta svg{width:14px;height:14px;opacity:.8}
.toc{background:var(--paper-2);border:1px solid var(--rule);border-radius:var(--r-lg);
  padding:clamp(20px,2.2vw,26px);margin-bottom:clamp(30px,3.4vw,44px)}
.toc h2{font-family:var(--sans);font-size:.74rem;font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-faint);margin:0 0 .9rem}
.toc ol{margin:0;padding-left:1.2em;display:grid;gap:.45em}
.toc a{color:var(--navy);text-decoration:none;font-size:.94rem;font-weight:500}
.toc a:hover{color:var(--accent);text-decoration:underline;text-underline-offset:3px}

/* ---------- Event calendar rows (networking calendar guide) -------------- */
.cal{border-top:1px solid var(--rule)}
.cal-row{display:grid;grid-template-columns:130px 1fr;gap:clamp(16px,2.2vw,32px);
  padding:clamp(20px,2.2vw,26px) 0;border-bottom:1px solid var(--rule)}
.cal-when{font-family:var(--display);font-weight:600;font-size:.92rem;color:var(--accent);line-height:1.4}
.cal-when small{display:block;font-family:var(--sans);font-weight:400;font-size:.8rem;
  color:var(--ink-faint);margin-top:.25rem}
.cal-what b{display:block;font-family:var(--display);font-weight:600;font-size:1.05rem;
  color:var(--navy);margin-bottom:.35rem}
.cal-what p{font-size:.9rem;color:var(--ink-soft);line-height:1.62;margin:0}
.cal-what a{color:var(--accent)}
@media(max-width:640px){.cal-row{grid-template-columns:1fr;gap:8px}}

/* ---------- Review wall -------------------------------------------------- */
.wall{columns:3;column-gap:clamp(16px,1.9vw,26px)}
.wall figure{break-inside:avoid;margin:0 0 clamp(16px,1.9vw,26px);background:#fff;
  border:1px solid var(--rule);border-radius:var(--r-lg);padding:clamp(20px,2.2vw,26px)}
.wall .rstars{color:var(--gold-deep);letter-spacing:.16em;font-size:.95rem;margin-bottom:.8rem}
.wall blockquote{margin:0;font-size:.95rem;color:var(--ink-soft);line-height:1.68}
.wall figcaption{margin-top:1rem;padding-top:.85rem;border-top:1px solid var(--rule);font-size:.85rem}
.wall figcaption b{display:block;color:var(--navy);font-weight:600}
.wall figcaption span{color:var(--ink-faint);font-size:.78rem}
@media(max-width:1000px){.wall{columns:2}}
@media(max-width:620px){.wall{columns:1}}

/* ---------- Compact review strip ----------------------------------------
   Proof on interior pages, sat just above the booking CTA. Deliberately
   lighter than the home page slider: three short real Google reviews, no
   score panel, no carousel, so a service or city page does not hand a
   screenful of height to testimonials. */
.revstrip{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(14px,1.7vw,22px)}
.revstrip figure{margin:0;background:#fff;border:1px solid var(--rule);
  border-radius:var(--r-lg);padding:clamp(18px,2vw,24px);
  display:flex;flex-direction:column}
.revstrip .rstars{color:var(--gold-deep);letter-spacing:.16em;font-size:.92rem;margin-bottom:.75rem}
/* flex:1 pushes every attribution to the card bottom, so the three names line
   up even when the quotes are different lengths. */
.revstrip blockquote{margin:0;font-size:.93rem;color:var(--ink-soft);line-height:1.66;flex:1}
.revstrip figcaption{margin-top:1rem;padding-top:.8rem;border-top:1px solid var(--rule);font-size:.84rem}
.revstrip figcaption b{display:block;color:var(--navy);font-weight:600}
.revstrip figcaption span{color:var(--ink-faint);font-size:.78rem}

/* Below 900px the three cards stop stacking and become a swipeable track.
   Stacked, they were a wall of testimonial on pages that are already long.
   The scroller is plain CSS overflow plus scroll-snap, so swiping works with
   no JS at all; site.js only adds the dots and the auto-advance. */
@media(max-width:900px){
  .revstrip{
    /* Card width drives the side padding, so every slide - first and last
       included - can sit dead centre with its neighbours peeking equally.
       Padding the track by exactly half the leftover space is what removes
       the visible "start" and "end": without it the first card is pinned to
       the left gutter and the last to the right, which gives the ends away
       and makes the run feel finite. */
    --rev-card:82vw;
    grid-template-columns:none;
    display:flex;
    overflow-x:auto;
    scroll-snap-type:x mandatory;
    -webkit-overflow-scrolling:touch;
    scrollbar-width:none;
    /* Bleed to the screen edges so the peek has somewhere to live. */
    margin-inline:calc(var(--gut) * -1);
    padding-inline:calc((100vw - var(--rev-card)) / 2);
    gap:12px;
  }
  .revstrip::-webkit-scrollbar{display:none}
  .revstrip figure{flex:0 0 var(--rev-card);scroll-snap-align:center}
}

/* Dots are injected by site.js and only revealed while the track actually
   overflows, so they never appear next to the desktop grid. */
.revstrip-dots{display:none}
.revstrip-dots.is-on{
  display:flex;justify-content:center;align-items:center;gap:2px;
  margin-top:clamp(16px,2vw,22px)}
/* 24px tap target (WCAG 2.5.8), with the visible dot drawn at 9px inside it. */
.revstrip-dot{width:24px;height:24px;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:radial-gradient(circle,var(--rule-strong) 0 4.5px,transparent 5px);transition:background .3s}
.revstrip-dot[aria-current="true"]{background:radial-gradient(circle,var(--accent) 0 6px,transparent 6.5px)}

.revstrip-foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;
  gap:.5rem clamp(12px,1.5vw,20px);margin-top:clamp(20px,2.3vw,30px);
  font-size:.9rem;color:var(--ink-soft);text-align:center}
.revstrip-foot .rstars{color:var(--gold);letter-spacing:.14em;font-size:1rem}
.revstrip-foot b{color:var(--navy)}
.revstrip-foot a{color:var(--accent);text-decoration:underline;
  text-decoration-thickness:1px;text-underline-offset:3px}
.revstrip-foot a:hover{color:var(--accent-deep)}

/* ---------- Notice callout ----------------------------------------------- */
.note{display:flex;gap:14px;align-items:flex-start;background:var(--paper-2);
  border:1px solid var(--rule);border-left:3px solid var(--accent);
  border-radius:var(--r-sm);padding:clamp(16px,1.8vw,22px);margin-block:1.6em}
.note svg{width:19px;height:19px;flex:none;color:var(--accent);margin-top:.15em}
.note p{margin:0;font-size:.92rem;color:var(--ink-soft);line-height:1.65}
.note b{color:var(--navy)}

/* ---------- Legal page --------------------------------------------------- */
.legal{max-width:76ch}
.legal h2{font-size:clamp(1.3rem,2vw,1.65rem);margin-top:2.2em}
.legal h2:first-of-type{margin-top:0}
.legal h3{font-size:1.05rem;margin-top:1.6em}
.legal p,.legal li{color:var(--ink-soft);font-size:.98rem;line-height:1.72}
.legal>*+*{margin-top:1.1em}
.legal ul{padding-left:1.3em;display:grid;gap:.45em}
.legal li::marker{color:var(--accent)}
.legal a{color:var(--accent);text-decoration:underline;text-underline-offset:2px}
.legal .updated{font-size:.85rem;color:var(--ink-faint)}

/* =========================================================================
   IMAGERY COMPONENTS
   Added when the interior pages were rebalanced away from walls of text.
   The home page carries a photograph in nearly every section; these are the
   pieces that let a service, city, industry or guide page do the same without
   turning into a home page clone.
   ========================================================================= */

/* ---------- Figure inside long-form copy ---------------------------------
   Sits in the reading column and breaks the prose every few hundred words.
   Full-bleed of the .prose measure, never wider, so the line length of the
   copy above and below it is untouched. */
.figset{margin:clamp(28px,3vw,42px) 0;max-width:none}
.prose>.figset{margin-block:clamp(30px,3.2vw,44px)}
.figset img{width:100%;height:auto;display:block;border-radius:var(--r-md);background:var(--paper-2)}
.figset figcaption{margin-top:.7rem;font-size:.83rem;color:var(--ink-faint);line-height:1.55;
  padding-left:12px;border-left:2px solid var(--accent-line)}
/* A document (floor plan) is a white page, so it needs a tinted ground or it
   dissolves into the paper. Same trick the home page mini cards use. */
.figset.is-doc img{background:var(--paper-2);padding:14px;border:1px solid var(--rule)}

/* A self-hosted sample film. preload="none" means the page pays for the
   poster and nothing else until the visitor presses play, so a 5MB clip costs
   the same on load as one more photograph. */
.figset.is-video .vidwrap{position:relative;border-radius:var(--r-md);
  overflow:hidden;background:var(--navy)}
.figset.is-video video{display:block;width:100%;height:auto}
/* The controls are added and removed by site.js rather than faded, because a
   hidden-but-present control bar still swallows clicks on the video. */
.figset.is-video video::-webkit-media-controls{transition:opacity .2s}
/* Two figures side by side, for a comparison that is not a before/after. */
.fig-row{display:grid;grid-template-columns:1fr 1fr;gap:clamp(12px,1.4vw,18px);
  margin:clamp(28px,3vw,42px) 0}
/* The caption lives outside the framed area, so the frame has to be the
   <picture>, not the <figure>. Otherwise the figure's tinted ground extends
   past the photo and reads as a stray panel behind the caption. */
.fig-row .ph{position:relative;margin:0;cursor:zoom-in;background:none}
.fig-row .ph picture{display:block;overflow:hidden;border-radius:var(--r-md);
  background:var(--paper-2);aspect-ratio:3/2}
.fig-row .ph img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .7s var(--ease)}
.fig-row .ph:hover img{transform:scale(1.05)}
.fig-row .ph figcaption{margin-top:.55rem;font-size:.8rem;color:var(--ink-faint);line-height:1.5}
.fig-row.is-doc .ph picture{border:1px solid var(--rule);aspect-ratio:4/3}
.fig-row.is-doc .ph img{object-fit:contain;padding:12px;mix-blend-mode:multiply}
.fig-row.is-doc .ph:hover img{transform:none}
@media(max-width:620px){.fig-row{grid-template-columns:1fr}}

/* ---------- Asymmetric gallery ------------------------------------------
   The .strip is four equal 4:3 cells, which reads as a contact sheet. The
   mosaic gives one frame the room to actually be looked at and lets the rest
   support it, which is how a photographer would hang the same eight prints. */
.mosaic{display:grid;grid-template-columns:repeat(4,1fr);
  grid-auto-rows:clamp(120px,13vw,190px);gap:clamp(10px,1.2vw,16px)}
.mosaic .ph{position:relative;overflow:hidden;border-radius:var(--r-md);cursor:zoom-in;
  margin:0;background:var(--paper-2);grid-column:span 1;grid-row:span 1}
.mosaic .ph.is-hero{grid-column:span 2;grid-row:span 2}
.mosaic .ph.is-wide{grid-column:span 2}
.mosaic .ph.is-tall{grid-row:span 2}
.mosaic .ph img{width:100%;height:100%;object-fit:cover;transition:transform .8s var(--ease)}
.mosaic .ph:hover img{transform:scale(1.06)}
.mosaic .ph figcaption{position:absolute;left:0;right:0;bottom:0;padding:26px 14px 12px;
  background:linear-gradient(180deg,transparent,rgba(11,22,42,.86));
  color:#fff;font-size:.78rem;opacity:0;transform:translateY(8px);
  transition:opacity .35s var(--ease),transform .35s var(--ease)}
.mosaic .ph:hover figcaption,.mosaic .ph:focus-within figcaption{opacity:1;transform:none}
@media(max-width:900px){
  /* Two columns, and the hero cell stops being special so nothing orphans. */
  .mosaic{grid-template-columns:1fr 1fr;grid-auto-rows:clamp(130px,22vw,170px)}
  .mosaic .ph.is-hero{grid-column:span 2;grid-row:span 2}
  .mosaic .ph.is-wide{grid-column:span 2;grid-row:span 1}
  .mosaic .ph.is-tall{grid-row:span 1}
}

/* ---------- Before / after slider ----------------------------------------
   Virtual staging and virtual twilight are the two services where the product
   IS the difference between two frames. A static pair makes the reader do the
   comparison; the handle does it for them. Degrades with JS off to the "after"
   frame at full width with the before frame clipped to half, which still
   reads as a comparison. */
.ba{position:relative;overflow:hidden;border-radius:var(--r-md);background:var(--paper-2);
  --split:50%;touch-action:pan-y;user-select:none}
.ba img{display:block;width:100%;height:auto}
/* The after frame is a <picture> rather than a bare <img> so it gets the same
   WebP and phone-sized tiers as the before frame. */
.ba .ba-after{position:absolute;inset:0;display:block;
  clip-path:inset(0 0 0 var(--split))}
.ba .ba-after img{width:100%;height:100%;object-fit:cover}
.ba-line{position:absolute;top:0;bottom:0;left:var(--split);width:2px;background:#fff;
  box-shadow:0 0 0 1px rgba(11,22,42,.28);pointer-events:none}
.ba-handle{position:absolute;top:50%;left:var(--split);transform:translate(-50%,-50%);
  width:44px;height:44px;border-radius:50%;background:#fff;border:0;cursor:ew-resize;
  box-shadow:var(--shadow-md);display:grid;place-items:center;color:var(--navy);padding:0}
.ba-handle svg{width:20px;height:20px}
.ba-handle:focus-visible{outline:3px solid var(--accent);outline-offset:3px}
.ba-tag{position:absolute;top:12px;padding:.32em .7em;border-radius:var(--r-pill);
  font-size:.7rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  background:rgba(11,22,42,.72);color:#fff;backdrop-filter:blur(4px);pointer-events:none}
.ba-tag.is-before{left:12px}
.ba-tag.is-after{right:12px}
.ba-cap{margin-top:.7rem;font-size:.83rem;color:var(--ink-faint);line-height:1.55}
.ba-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(18px,2.4vw,32px)}
/* <figure> carries a UA margin of 1em 40px, which was quietly taking 80px of
   width off every tile in the grid. */
.ba-item{margin:0}
.ba-grid.is-1{grid-template-columns:1fr;max-width:820px;margin-inline:auto}
@media(max-width:820px){.ba-grid{grid-template-columns:1fr}}

/* Three left in the gallery once a pair is promoted into the prose above.
   Three across makes each frame too small to drag comfortably, so the odd one
   keeps the tile size and centres on its own row instead. */
.ba-grid.is-3>:last-child{grid-column:1/-1;justify-self:center;
  width:calc(50% - clamp(18px,2.4vw,32px)/2)}
@media(max-width:820px){.ba-grid.is-3>:last-child{grid-column:auto;justify-self:stretch;width:auto}}

/* One comparison slider set inline in the prose, so the first image a reader
   meets on these two pages is the one that actually demonstrates the service
   rather than only its result. Sized and spaced like a .figset. */
.ba-figure{margin:clamp(28px,3vw,42px) 0;max-width:none}
.prose>.ba-figure{margin-block:clamp(30px,3.2vw,44px)}
/* .ba already clips to its own radius; a radius on the inner frames shows
   through the clip as a notch on the split edge. */
.ba-figure .ba img{border-radius:0}

/* ---------- Full-bleed photographic band ---------------------------------
   A breather between two copy-heavy sections. Carries a single line, so it is
   a pause rather than another thing to read. */
.photoband{position:relative;isolation:isolate;color:#fff;overflow:hidden;
  display:grid;place-items:center;text-align:center;
  min-height:clamp(260px,32vw,420px);padding:clamp(40px,5vw,72px) var(--gut)}
.photoband-bg{position:absolute;inset:0;z-index:-2;background:var(--navy-deep)}
.photoband-bg img{width:100%;height:100%;object-fit:cover}
.photoband-bg::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(11,22,42,.58),rgba(11,22,42,.74))}
.photoband-inner{max-width:60ch}
.photoband p.eyebrow{color:var(--accent-lite)}
.photoband blockquote{margin:0;font-family:var(--display);font-weight:500;
  font-size:clamp(1.25rem,2.5vw,1.85rem);line-height:1.4;color:#fff;text-wrap:balance}
.photoband cite{display:block;margin-top:1rem;font-family:var(--sans);font-style:normal;
  font-size:.85rem;color:rgba(255,255,255,.72)}

/* ---------- Copy beside a photograph -------------------------------------
   .intro-grid handles the home page version. This is the interior-page
   variant: it alternates side so consecutive bands do not read as a list. */
.sidefig{display:grid;grid-template-columns:1fr 1fr;gap:clamp(30px,4.4vw,68px);align-items:center}
.sidefig.is-flip .sidefig-media{order:-1}
.sidefig-media img{width:100%;height:auto;display:block;border-radius:var(--r-lg);
  box-shadow:var(--shadow-lg);background:var(--paper-2)}
.sidefig-copy h2{margin-bottom:.6rem}
.sidefig-copy p{color:var(--ink-soft);font-size:1.01rem;line-height:1.72}
.sidefig-copy p+p{margin-top:.9em}
@media(max-width:860px){
  .sidefig{grid-template-columns:1fr;gap:28px}
  .sidefig.is-flip .sidefig-media{order:0}
}

/* ---------- Document grid (floor plans) ----------------------------------
   A floor plan is a white document, not a photograph. Cropping it to fill a
   cell cuts off the rooms, which is the entire content, so these tiles letter
   box the plan on a tinted ground and put the caption underneath rather than
   over the top of it. */
.docgrid{display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(12px,1.4vw,20px)}
.docgrid .ph{position:relative;margin:0;cursor:zoom-in}
.docgrid .ph picture{display:grid;place-items:center;aspect-ratio:4/3;padding:14px;
  background:#fff;border:1px solid var(--rule);border-radius:var(--r-md);overflow:hidden}
.docgrid .ph img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply;
  transition:transform .5s var(--ease)}
.docgrid .ph:hover img{transform:scale(1.04)}
.docgrid .ph figcaption{margin-top:.6rem;font-size:.8rem;color:var(--ink-faint);line-height:1.5}
@media(max-width:1000px){.docgrid{grid-template-columns:1fr 1fr}}
@media(max-width:560px){.docgrid{grid-template-columns:1fr}}

/* =========================================================================
   SERVICE AREA MAP
   Leaflet + OpenStreetMap tiles, self-hosted in /vendor/leaflet and fetched
   by site.js only when a map nears the viewport. The city pills stay the real
   navigation; the map is the visual supplement, paired with them by the
   /service-areas/<slug> in each pill's href. Hidden without JS, and hidden
   again if the library fails to load, so there is never an empty frame.
   ========================================================================= */
.area-map{display:none;position:relative;z-index:0;width:100%;aspect-ratio:1/1;
  border:1px solid var(--rule);border-radius:var(--r-lg);overflow:hidden;
  background:#DFE6F0;box-shadow:var(--shadow-md)}
.js .area-map{display:block}
.area-map.is-failed{display:none}
.area-map.is-wide{aspect-ratio:21/8}
/* Interior pages already carry a city pill row inside a cross-link block.
   They keep it, with the map alongside, rather than growing a second service
   areas section. Same pairing, less page. */
.area-split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,.82fr);
  gap:clamp(26px,3vw,44px);align-items:center}
html:not(.js) .area-split,.area-split.no-map{grid-template-columns:1fr}
@media(max-width:900px){
  .area-split{grid-template-columns:1fr;gap:clamp(22px,3vw,30px)}
}

/* Service areas is a section in its own right on interior pages, not a third
   pill row: it gets a real H2 and copy, the same weight the home page gives
   it, set off from the cross-link rows above by a hairline and real space. */
.area-sect{margin-top:clamp(32px,4vw,56px);padding-top:clamp(32px,4vw,54px);
  border-top:1px solid var(--rule)}
.area-head{margin-bottom:clamp(22px,2.6vw,32px)}
.area-head h2{text-wrap:balance}
.area-head .lede{margin-top:1.05rem}
.area-head .area-note{margin-top:.95rem;color:var(--ink-soft);font-size:.95rem}
/* The copy sits in the left column with the pills, so the map pairs with the
   whole block rather than floating beside a short pill row. */

/* The Austin pill is tagged on every page that is not about one city, exactly
   as the home page tags it. */
.linkrow a.lead{background:var(--navy);border-color:var(--navy);color:#fff;font-weight:600}
.linkrow a.lead svg{color:var(--accent-lite)}
.linkrow a.lead:hover{background:var(--accent);border-color:var(--accent)}
.linkrow a.lead:hover svg{color:#fff}
@media(max-width:900px){
  .area-map{aspect-ratio:5/4}
  .area-map.is-wide{aspect-ratio:16/10}
}
@media(max-width:560px){.area-map,.area-map.is-wide{aspect-ratio:1/1}}

/* Full colour OpenStreetMap tiles. A greyed, washed version was tried first
   (it made the tile's own place names recede under the pins) and James
   preferred colour on 2026-09-11. */
.area-map.leaflet-container{font-family:var(--sans);background:#E9EEF4}
/* At a fractional zoom on 2x and 3x screens Chromium draws faint light lines
   along every tile edge. A transparent outline makes it anti-alias the edges
   inside the tile instead, and the grid disappears. Measured against six
   other candidates; the common "256.5px tile" overlap hack made it worse. */
.area-map .leaflet-tile{outline:1px solid transparent}

/* Pins: a round badge with a camera glyph, sized by site.js (34px, or 28px
   on a phone sized map). Big enough to tap, and it covers the place name the
   tile prints at each city's centre. Highlighting inverts it to white. */
.am-pin{background:none;border:0}
.am-dot{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  border-radius:50%;background:var(--accent);color:#fff;
  box-shadow:0 0 0 2px rgba(255,255,255,.95),0 2px 7px rgba(16,31,60,.4);
  transition:transform .25s var(--ease),background-color .25s,color .25s,box-shadow .25s}
.am-dot svg{width:50%;height:50%}
.am-pin.is-lead .am-dot,.am-pin.is-current .am-dot{background:var(--navy)}
.am-pin.is-muted .am-dot{background:var(--ink-faint);box-shadow:0 0 0 2px #fff,0 1px 4px rgba(16,31,60,.3)}
.am-pin.is-linked .am-dot{transform:scale(1.15);background:#fff;color:var(--accent);
  box-shadow:0 0 0 2px var(--accent),0 3px 10px rgba(16,31,60,.42)}
.am-pin.is-lead.is-linked .am-dot,.am-pin.is-current.is-linked .am-dot{color:var(--navy);
  box-shadow:0 0 0 2px var(--navy),0 3px 10px rgba(16,31,60,.42)}
.am-pin.is-muted.is-linked .am-dot{background:var(--accent)}
.am-pin.is-linked .am-dot::after{content:"";position:absolute;inset:-6px;border-radius:50%;
  border:2px solid var(--accent);animation:amPulse 1.3s var(--ease) infinite}
@keyframes amPulse{from{transform:scale(.55);opacity:.95}to{transform:scale(1.7);opacity:0}}

/* Labels: hover tooltips are navy; the fixed label on the lead or current
   city is white so the two never read as the same thing. */
.area-map .am-label{background:var(--navy);border:0;border-radius:var(--r-sm);
  box-shadow:0 4px 12px rgba(16,31,60,.28);padding:.3em .68em;
  font-family:var(--sans);font-size:.78rem;font-weight:600;line-height:1.3;color:#fff;white-space:nowrap}
.area-map .am-label.leaflet-tooltip-top::before{border-top-color:var(--navy)}
.area-map .am-label.is-fixed{background:#fff;color:var(--navy);box-shadow:0 2px 8px rgba(16,31,60,.22)}
.area-map .am-label.is-fixed.leaflet-tooltip-top::before{border-top-color:#fff}
.area-map .am-label.is-fixed{transition:opacity .2s}
/* Leaflet writes the tooltip opacity inline, hence the !important. */
.area-map .am-label.is-fixed.is-hushed{opacity:0 !important}

/* Touch devices get a tap popup carrying the link instead of a hover label. */
.area-map .leaflet-popup-content-wrapper{border-radius:var(--r-sm);box-shadow:var(--shadow-md)}
.area-map .leaflet-popup-content{margin:.5rem .8rem;font-family:var(--sans);font-size:.9rem;line-height:1.4}
/* Scoped under .area-map to outrank Leaflet's own .leaflet-container a. */
.area-map .am-pop{display:inline-flex;align-items:center;gap:.45em;padding:.45em 0;
  color:var(--navy);font-weight:600;text-decoration:none}
.area-map .am-pop svg{width:14px;height:14px;flex:none;color:var(--accent)}

.area-map .leaflet-bar,.area-map.leaflet-touch .leaflet-bar{border:1px solid var(--rule-strong);
  border-radius:var(--r-sm);box-shadow:var(--shadow-sm);overflow:hidden}
.area-map .leaflet-bar a,.area-map.leaflet-touch .leaflet-bar a{width:32px;height:32px;
  line-height:31px;color:var(--navy);font-size:18px}
.area-map .leaflet-bar a:hover{background:var(--paper-2)}
.area-map .leaflet-control-attribution{padding:0 5px;font-size:.56rem;line-height:1.55;
  color:var(--ink-soft);background:rgba(251,252,253,.8);border-top-left-radius:4px}
.area-map .leaflet-control-attribution a{color:var(--navy)}

/* Pill side of the pairing: the same state as hovering the pill itself. */
.area.is-linked,.linkrow a.is-linked{background:var(--accent);border-color:var(--accent);
  color:#fff;transform:translateY(-2px)}
.area.is-linked svg,.linkrow a.is-linked svg{color:#fff}

@media(prefers-reduced-motion:reduce){
  .am-pin.is-linked .am-dot::after{display:none}
}

/* =========================================================================
   SERVICE AND PROPERTY TYPE VISUALS
   Two treatments for the cross-link rows that used to be plain pills, so
   those sections carry the work rather than only naming it.
   ========================================================================= */

/* ---------- Picker: a list of links, the photograph beside it -----------
   The rows are ordinary links. Hover or keyboard focus swaps the photograph;
   a tap on a phone just follows the link, where the panel shows the first
   service and stays put. */
/* Grid items are min-width:auto by default, so without this the picker and
   the filmstrip below push the whole page wider instead of fitting the
   column and scrolling inside it. */
.xrow,.pick,.ptiles{min-width:0}
.pick{display:grid;grid-template-columns:minmax(0,.92fr) minmax(0,1.08fr);
  gap:clamp(24px,3vw,46px);align-items:start}
.pick-list{list-style:none;margin:0;padding:0;border-top:1px solid var(--rule)}
.pick-list a{display:flex;align-items:center;justify-content:space-between;gap:1em;
  padding:.74em .2em;border-bottom:1px solid var(--rule);color:var(--navy);
  text-decoration:none;font-size:.96rem;font-weight:500;
  transition:color .2s,padding-left .3s var(--ease),background .2s}
.pick-list svg{width:15px;height:15px;flex:none;color:var(--accent);opacity:0;
  transform:translateX(-6px);transition:opacity .25s,transform .3s var(--ease)}
.pick-list a:hover{color:var(--accent)}
.pick-list .is-active a{color:var(--accent);font-weight:600;padding-left:.65em}
.pick-list .is-active svg,.pick-list a:hover svg{opacity:1;transform:none}

.pick-media{position:relative;margin:0;border-radius:var(--r-lg);overflow:hidden;
  background:var(--paper-2);box-shadow:var(--shadow-lg)}
/* height:auto matters: the img carries width/height attributes, which act as
   presentational styles, and aspect-ratio only fills in an auto dimension. */
.pick-media img{display:block;width:100%;height:auto;aspect-ratio:4/3;object-fit:cover;
  transition:opacity .35s var(--ease)}
.pick-media.is-swapping img{opacity:.3}
.pick-cap{position:absolute;left:0;right:0;bottom:0;padding:clamp(16px,1.8vw,22px);
  background:linear-gradient(180deg,rgba(16,31,60,0),rgba(16,31,60,.85));color:#fff}
.pick-cap b{display:block;font-family:var(--display);font-weight:600;font-size:1.06rem}
.pick-cap span{display:block;margin-top:.25rem;font-size:.86rem;line-height:1.45;
  color:rgba(255,255,255,.82)}
/* Side by side holds down to tablet width, and only where there is a pointer
   to hover with. Anywhere else the list becomes the accordion below. */
@media(max-width:720px),(hover:none){
  .pick{grid-template-columns:1fr;gap:20px}
  .pick-media{order:-1}
}

/* ---------- Filmstrip of property types --------------------------------
   Scrolls sideways instead of stacking into a tall grid, which keeps the
   section short on pages that already carry a gallery and a map. */
.ptiles{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(250px,1fr);
  gap:clamp(10px,1.2vw,16px);overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;padding-bottom:10px;
  /* A visible slim bar, so it is obvious the row keeps going. */
  scrollbar-width:thin;scrollbar-color:var(--rule-strong) transparent}
.ptiles::-webkit-scrollbar{height:6px}
.ptiles::-webkit-scrollbar-thumb{background:var(--rule-strong);border-radius:100px}
.ptiles::-webkit-scrollbar-track{background:transparent}
.ptile{position:relative;display:block;overflow:hidden;border-radius:var(--r-md);
  background:var(--navy);text-decoration:none;scroll-snap-align:start;
  box-shadow:var(--shadow-sm);transition:transform .3s var(--ease),box-shadow .3s}
.ptile img{display:block;width:100%;height:auto;aspect-ratio:3/2;object-fit:cover;
  transition:transform .55s var(--ease)}
.ptile::after{content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(16,31,60,.04) 38%,rgba(16,31,60,.8));
  transition:background .3s}
.ptile span{position:absolute;left:13px;right:13px;bottom:11px;z-index:1;color:#fff;
  font-size:.87rem;font-weight:600;line-height:1.25;text-wrap:balance}
.ptile:hover{transform:translateY(-3px);box-shadow:var(--shadow-md)}
.ptile:hover img{transform:scale(1.06)}
.ptile:hover::after{background:linear-gradient(180deg,rgba(48,104,207,.16) 30%,rgba(16,31,60,.86))}
@media(prefers-reduced-motion:reduce){
  .ptile:hover{transform:none}
  .ptile:hover img{transform:none}
}

/* ---------- Property type slider chrome ---------------------------------
   The track above does the scrolling and the swiping natively. This adds the
   heading block, the two chevrons and the sizes the slider runs at. */
.ptype-head{margin-top:clamp(46px,6vw,84px)}
.ptype-head .lede{margin-top:1rem;max-width:64ch}
.pslide{display:flex;align-items:center;gap:clamp(8px,1vw,14px);margin-top:clamp(20px,2.4vw,30px)}
.pslide .ptiles{flex:1 1 auto;min-width:0;margin:0}
.pslide-btn{flex:none;display:grid;place-items:center;width:44px;height:44px;padding:0;
  border:1px solid var(--rule-strong);border-radius:50%;background:#fff;color:var(--navy);
  cursor:pointer;box-shadow:var(--shadow-sm);
  transition:background .25s,border-color .25s,color .25s,transform .25s var(--ease)}
.pslide-btn svg{width:19px;height:19px}
.pslide-btn:hover{background:var(--accent);border-color:var(--accent);color:#fff}
.pslide-btn:active{transform:scale(.94)}
/* Every tile already fits, so there is nothing to step through. */
.pslide.is-static .pslide-btn{display:none}
@media(max-width:900px){
  .ptiles{grid-auto-columns:minmax(210px,1fr)}
  .pslide-btn{width:38px;height:38px}
  .pslide-btn svg{width:17px;height:17px}
}

/* ---------- Picker on a phone: tap a row, its photograph opens ----------
   A shared panel beside the list is a hover idea. Without a pointer the rows
   become an accordion instead, each opening its own photograph and the link
   that actually goes somewhere. The drawers are built by site.js on first
   open, so a phone downloads one photograph rather than ten. */
/* Matches the test site.js makes: no pointer, or too narrow for a panel. */
@media(max-width:720px),(hover:none){
  .pick-media{display:none}
  /* Scoped to the row itself. The link revealed inside the drawer is also an
     anchor in this list and must not pick up the marker or lose its arrow. */
  .pick-list>li>a{padding:.85em .2em}
  .pick-list>li>a>svg{display:none}
  .pick-list>li>a::after{content:"+";font-family:var(--sans);font-size:1.15rem;font-weight:500;
    line-height:1;color:var(--accent)}
  .pick-list>li.is-open>a{color:var(--accent);font-weight:600}
  .pick-list>li.is-open>a::after{content:"\2212"}
  .pick-drawer{display:grid;grid-template-rows:0fr;
    transition:grid-template-rows .35s var(--ease)}
  .pick-list .is-open .pick-drawer{grid-template-rows:1fr}
  .pick-drawer-in{overflow:hidden}
  .pick-fig{margin:0 0 .9rem;border-radius:var(--r-md);overflow:hidden;background:var(--paper-2)}
  .pick-fig img{display:block;width:100%;height:auto;aspect-ratio:4/3;object-fit:cover}
  .pick-note{margin:0 0 .8rem;font-size:.92rem;line-height:1.5;color:var(--ink-soft)}
  .pick-go{display:inline-flex;align-items:center;gap:.45em;margin-bottom:1.1rem;
    color:var(--accent);font-weight:600;font-size:.92rem;text-decoration:underline;
    text-underline-offset:3px;text-decoration-thickness:1px}
  .pick-go svg{display:block;width:15px;height:15px}
  .pick-drawer-in>*:first-child{margin-top:.2rem}
}
@media(prefers-reduced-motion:reduce){
  .pick-drawer{transition:none}
}

/* ==========================================================================
   SAMPLE TOURS (added 2026-09-22)
   Real Matterport and Zillow 3D tours, click to load. Nothing from
   Matterport or Zillow is requested until the visitor opens a tour, so the
   page weight and Lighthouse scores are unchanged. Markup works without JS
   as plain links to each tour.
   ========================================================================== */
.tours{display:grid;grid-template-columns:minmax(0,1fr) 300px;gap:clamp(16px,2vw,26px);align-items:start;margin-top:clamp(26px,3vw,40px)}
.tour-stage{position:relative;aspect-ratio:16/9;border-radius:var(--r-md);overflow:hidden;background:#0b1528;box-shadow:var(--shadow-sm)}
.tour-stage iframe{position:absolute;inset:0;width:100%;height:100%;border:0;display:block}
.tour-poster{position:absolute;inset:0;display:block;width:100%;height:100%;padding:0;border:0;background:none;cursor:pointer;color:#fff;text-decoration:none}
.tour-poster picture,.tour-poster img{display:block;width:100%;height:100%}
.tour-poster img{object-fit:cover;transition:transform .8s var(--ease)}
.tour-poster::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(11,21,40,.05) 30%,rgba(11,21,40,.72))}
.tour-poster:hover img{transform:scale(1.03)}
.tour-play{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:1;display:flex;align-items:center;gap:12px;
  background:#fff;color:var(--navy);border-radius:999px;padding:12px 22px 12px 14px;box-shadow:0 10px 30px rgba(0,0,0,.28);white-space:nowrap}
.tour-play svg{width:34px;height:34px;flex:none;border-radius:50%;background:var(--accent);color:#fff;padding:8px}
.tour-play b{font-family:var(--display);font-weight:600;font-size:1rem}
.tour-cap{position:absolute;left:18px;right:18px;bottom:14px;z-index:1;text-align:left;font-size:.86rem;color:rgba(255,255,255,.9)}
.tour-poster:focus-visible{outline:3px solid var(--accent-lite);outline-offset:-3px}
.tour-list{display:grid;gap:10px;list-style:none;margin:0;padding:0}
.tour-pick{display:grid;grid-template-columns:96px 1fr;gap:12px;align-items:center;width:100%;padding:8px;border-radius:var(--r-sm);
  border:1px solid rgba(255,255,255,.14);background:rgba(255,255,255,.04);color:#fff;text-align:left;cursor:pointer;font:inherit;
  transition:border-color .25s,background .25s}
.tour-pick:hover{border-color:rgba(255,255,255,.4)}
.tour-pick[aria-pressed="true"]{border-color:var(--accent-lite);background:rgba(136,166,221,.14)}
.tour-pick img{width:96px;height:54px;object-fit:cover;border-radius:4px;display:block}
.tour-pick b{display:block;font-size:.92rem;font-weight:600;line-height:1.3}
.tour-pick small{display:block;font-size:.78rem;color:rgba(255,255,255,.66);margin-top:.15rem}
.tour-note{grid-column:1/-1;margin:0;font-size:.84rem;color:rgba(255,255,255,.66)}
.tour-note a{color:var(--accent-lite)}
@media(max-width:900px){
  .tours{grid-template-columns:1fr}
  .tour-list{grid-auto-flow:column;grid-auto-columns:minmax(260px,40%);overflow-x:auto;scroll-snap-type:x mandatory;padding-bottom:6px}
  .tour-pick{grid-template-columns:80px 1fr}
  .tour-pick img{width:80px;height:45px}
  .tour-pick{scroll-snap-align:start}
  .tour-list{scrollbar-width:none}
  .tour-list::-webkit-scrollbar{display:none}
}
@media(max-width:640px){
  /* A taller frame on phones: the tour controls and the floor plan both need
     the height, and a 16:9 box at 390px wide is too short to steer. */
  .tour-stage{aspect-ratio:4/5}
  .tour-play{padding:10px 18px 10px 10px}
  .tour-play b{font-size:.92rem}
  .tour-list{grid-auto-columns:minmax(200px,64%)}
  .tour-pick{grid-template-columns:64px 1fr;gap:10px;padding:7px}
  .tour-pick img{width:64px;height:40px}
  .tour-pick small{display:none}
}

/* Portrait gallery for headshot work (2:3 frames, 4 across, 2 on phones). */
.hs-grid{display:grid;grid-template-columns:repeat(6,1fr);gap:clamp(10px,1.2vw,16px)}
.hs-grid .ph{position:relative;margin:0;overflow:hidden;border-radius:var(--r-md);cursor:zoom-in;aspect-ratio:2/3;background:var(--paper-3,#e9edf3)}
.hs-grid .ph img{width:100%;height:100%;object-fit:cover;display:block;transition:transform .8s var(--ease)}
.hs-grid .ph:hover img{transform:scale(1.04)}
.hs-grid .ph figcaption{position:absolute;left:0;right:0;bottom:0;padding:26px 12px 10px;font-size:.8rem;color:#fff;background:linear-gradient(transparent,rgba(11,21,40,.72))}
@media(max-width:1000px){.hs-grid{grid-template-columns:repeat(3,1fr)}}
@media(max-width:560px){.hs-grid{grid-template-columns:repeat(2,1fr)}}
/* Portrait pair inside prose: headshots are 2:3, so the 3:2 frame would crop heads. */
.fig-row.is-portrait{max-width:620px}
.fig-row.is-portrait .ph picture{aspect-ratio:2/3}

/* Lightbox trigger: site.js lays a transparent button over every gallery
   photo. The ring is drawn inset because most .ph figures clip overflow. */
.ph-open{position:absolute;inset:0;z-index:2;width:100%;height:100%;margin:0;padding:0;
  border:0;background:none;cursor:zoom-in;border-radius:inherit}
.ph-open:focus-visible{outline-offset:-3px}
