/* ============================================================================
   Homepage composition — "Night Glass"

   GROUND RHYTHM (audited, never guessed):
     bar        coal (violet-black)
     hero       coal + photograph
     services   white
     why        panel  (light violet-grey)
     areas      white
     schedule   COAL  ← the one flat dark accent band
     hours      white
     faq        panel
     contact    coal + photograph
     colophon   coal-2
   No three consecutive bands share a ground; the only flat inverted band is the
   schedule strip. The two other dark moments are photographs, not colour.
   ========================================================================= */

/* ===================================================== 1. HERO =========== */
.hero{position:relative;background:var(--coal);color:#fff;isolation:isolate}
.hero__bg{position:absolute;inset:0;overflow:hidden;z-index:0}
.hero__bg img{width:100%;height:100%;object-fit:cover;object-position:62% 42%}
.hero__scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(90deg,
      rgba(16,12,21,.96) 0%, rgba(16,12,21,.93) 34%, rgba(16,12,21,.78) 52%,
      rgba(16,12,21,.46) 70%, rgba(16,12,21,.22) 86%, rgba(16,12,21,.14) 100%),
    linear-gradient(180deg, rgba(16,12,21,.55) 0%, rgba(16,12,21,0) 26%)}
.hero__in{position:relative;z-index:2;
  min-height:clamp(540px,76vh,720px);display:flex;flex-direction:column;
  justify-content:center;padding-block:clamp(52px,7vh,86px)}
.hero__c{max-width:680px}

.h1{margin:0 0 20px;font-family:var(--f-disp);font-weight:800;
  font-size:clamp(32px,4.3vw,57px);line-height:1.02;letter-spacing:var(--tr-xl);
  text-wrap:balance;font-optical-sizing:auto}
.h1 .ln{display:block}
/* The client's own name is the first line of the source H1 — it sets like the
   comp's eyebrow while remaining, character for character, part of the H1. */
.h1 .ln--1{font-size:clamp(12px,1vw,13.4px);font-weight:600;line-height:1.5;
  letter-spacing:var(--tr-label);color:var(--plum-lt);margin-bottom:18px;
  text-transform:none}
.h1 .ln--1 i{font-style:normal;opacity:.55}
.h1 .x{color:var(--plum-br)}

.hero__lede{font-size:clamp(15.8px,1.18vw,17.6px);line-height:1.62;
  color:rgba(255,255,255,.84);max-width:54ch;margin-bottom:26px;text-wrap:pretty}
.hero__acts{display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.hero__call{display:block;margin-top:20px;font-size:14.6px;line-height:1.6;
  color:rgba(255,255,255,.86)}
.hero__call a{color:#fff;font-weight:700;text-decoration:none;
  border-bottom:1.5px solid var(--plum-br);padding-bottom:1px}

/* the smoked-glass credential rail — one object, not eight pills, and the
   page's single deliberate boundary break */
.hero__rail{position:relative;z-index:4;margin-bottom:-38px;
  background:rgba(16,12,21,.84);   /* was .72 + a 16px backdrop blur: re-blurred under the moving lamp every frame */
  border-top:1px solid rgba(255,255,255,.14);
  border-bottom:1px solid rgba(255,255,255,.08);
  box-shadow:0 26px 60px -34px rgba(0,0,0,.9)}
.rail{display:grid;grid-template-columns:repeat(4,1fr)}
.rail__i{display:flex;align-items:center;gap:10px;padding:16px 20px 16px 0;
  font-size:13.7px;font-weight:500;line-height:1.35;color:rgba(255,255,255,.9);
  letter-spacing:-.002em;border-right:1px solid rgba(255,255,255,.09)}
.rail__i:nth-child(4n){border-right:0;padding-right:0}
.rail__i:nth-child(n+5){border-top:1px solid rgba(255,255,255,.09)}
.rail__i svg{width:16px;height:16px;flex:none;color:var(--plum-br)}
@media (max-width:1040px){
  .rail{grid-template-columns:repeat(2,1fr)}
  .rail__i:nth-child(2n){border-right:0;padding-right:0}
  .rail__i:nth-child(2n+1){border-right:1px solid rgba(255,255,255,.09);padding-right:20px}
  .rail__i:nth-child(n+3){border-top:1px solid rgba(255,255,255,.09)}
}
@media (max-width:560px){
  .rail{grid-template-columns:1fr}
  .rail__i{padding:12px 0;font-size:13.2px}
  .rail__i:nth-child(n+2){border-top:1px solid rgba(255,255,255,.09)}
  .rail__i:nth-child(2n+1){border-right:0;padding-right:0}
}

@media (max-width:900px){
  .hero__bg img{object-position:58% 38%}
  /* the portrait crop puts bright sky behind the headline, so the phone ramp
     starts heavier than the desktop one — computed, not guessed */
  .hero__scrim{background:
    linear-gradient(180deg, rgba(16,12,21,.8) 0%, rgba(16,12,21,.87) 40%,
      rgba(16,12,21,.94) 72%, rgba(16,12,21,.97) 100%)}
  .hero__in{min-height:clamp(500px,72vh,640px)}
}
@media (max-width:520px){
  .hero__acts .btn{flex:1 1 100%;justify-content:center}
}

/* ===================================================== section heads ===== */
.sec{padding-block:var(--sec)}
.sec--white{background:var(--white)}
.sec--panel{background:var(--panel)}
.shd{display:grid;grid-template-columns:1.18fr .82fr;gap:clamp(20px,4vw,72px);
  align-items:end;margin-bottom:clamp(36px,4.6vw,58px);
  padding-top:26px;border-top:1px solid var(--line-2);position:relative}
.shd::before{content:"";position:absolute;left:0;top:-1px;width:64px;height:3px;
  background:var(--plum)}
.dark .shd{border-top-color:rgba(255,255,255,.14)}
.dark .shd::before{background:var(--plum-br)}
.shd--c{grid-template-columns:1fr;max-width:760px;margin-inline:auto;text-align:center;
  align-items:center;border-top:0;padding-top:0}
.shd--c::before{left:50%;transform:translateX(-50%);top:-34px}
.shd--c .lede{margin-inline:auto}
@media (max-width:860px){ .shd{grid-template-columns:1fr;gap:16px;align-items:start} }

/* ===================================================== 2. SERVICES ======= */
/* (#services used to pad +38px for the hero rail's overlap; the quote band sits between them now) */
.svc__gr{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2vw,26px)}
@media (max-width:1000px){ .svc__gr{grid-template-columns:repeat(2,1fr)} }
@media (max-width:640px){ .svc__gr{grid-template-columns:1fr} }

/* ===================================================== 3. WHY =========== */
/* The photograph used to bleed off the left edge of the page. It made the band
   asymmetric — zero margin on the left, the full 152px page margin left over on
   the right — and it squeezed the eight reasons into two 289px columns that
   broke titles mid-phrase. Both columns now sit inside the page margins like
   every other section, the reasons run as ONE wider ruled list, and the
   photograph is sticky: it holds while the list travels past it, which is
   scroll choreography with no JavaScript at all. */
.why__gr{display:grid;grid-template-columns:minmax(0,.62fr) minmax(0,1fr);
  gap:clamp(28px,3.6vw,56px);align-items:start}
/* The body column is far taller than a 4:5 plate, and centring the photograph
   beside it left a hole above and below. The photograph takes the row's full
   height instead: the image is absolutely positioned so the grid, not the
   picture's own ratio, sets the height. */
.why__ph{position:sticky;top:calc(var(--bar) + 28px);align-self:start;
  height:clamp(430px,64vh,620px);
  border-radius:var(--r-lg);overflow:hidden;
  box-shadow:var(--sh-2);background:var(--panel-2)}
.why__ph img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.why__badge{position:absolute;left:0;bottom:0;z-index:2;
  display:flex;align-items:center;gap:10px;
  background:var(--coal);color:#fff;padding:14px 20px;border-radius:0 var(--r) 0 0;
  font-family:var(--f-disp);font-weight:600;font-size:14.6px;letter-spacing:var(--tr-md)}
.why__badge svg{width:18px;height:18px;flex:none;color:var(--plum-br);
  fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.why__bd .feat{grid-template-columns:1fr;margin:0 0 30px;gap:0}
.why__bd .feat__i{padding:17px 0;border-top:1px solid var(--line-2);
  grid-template-columns:40px 1fr;gap:16px}
.why__bd .feat__i:first-child{border-top:0;padding-top:0}
.why__bd .feat__d{max-width:58ch}
.why__ask{display:flex;flex-wrap:wrap;align-items:center;gap:16px 22px;
  padding-top:24px;border-top:1px solid var(--line-2)}
.why__ask p{font-family:var(--f-disp);font-weight:600;font-size:clamp(16.2px,1.35vw,19.4px);
  letter-spacing:var(--tr-md);line-height:1.32;flex:1 1 260px;margin:0}
@media (max-width:980px){
  .why__gr{grid-template-columns:1fr;gap:30px}
  /* Stacked, a sticky picture would pin over the list it belongs to. It stays
     POSITIONED though: the image inside is absolute, and with a static parent
     it anchored to the initial containing block instead — 814px wide at
     left:-23 inside a 768px viewport, which is where the horizontal overflow
     at every width below 980px came from. */
  .why__ph{position:relative;height:auto;aspect-ratio:16/10;max-height:400px}
}

/* ===================================================== 4. AREAS ========== */
/* Map on the left, the whole index down the right. The two groups are 10 and
   13 rows, so side by side the shorter one left a measured 141px hole - a
   third of the taller one's height. Stacked in one column they simply run on,
   and the map gets to be the thing a "where we work" section is about. */
.area__split{display:grid;grid-template-columns:minmax(0,.96fr) minmax(0,1.04fr);
  gap:clamp(24px,3.4vw,54px);align-items:start}
.area__side{position:sticky;top:calc(var(--bar) + 26px)}
.area__side .area__media{grid-template-columns:1fr;margin-top:0;gap:14px}
/* Tall enough that the map plus the forecast card come out level with the
   index beside them; at the default 360px the left column stopped 210px short. */
.area__side .map iframe{min-height:clamp(360px,44vw,556px)}
.area__gr{display:grid;grid-template-columns:1fr;gap:clamp(26px,3.2vw,40px);
  align-items:start}
@media (max-width:980px){
  .area__split{grid-template-columns:1fr;gap:clamp(22px,3vw,32px)}
  /* the drawn map leads on narrow screens: there is no hover link to the index
     there, so it is the visual hook, and after 23 list rows nobody reaches it */
  .area__side{position:static}
}
.area__h{font-size:clamp(17px,1.5vw,20.5px);font-weight:600;
  letter-spacing:var(--tr-md);margin-bottom:9px}
.area__i{font-size:14.8px;line-height:1.58;color:var(--gray);margin-bottom:16px;
  text-wrap:pretty}
.area__ls{display:grid;grid-template-columns:1fr 1fr;gap:0 26px;
  border-top:1px solid var(--line)}
.area__r{position:relative;display:flex;align-items:center;gap:10px;
  padding:13px 4px;border-bottom:1px solid var(--line);
  font-size:14.5px;font-weight:500;color:var(--ink-2);text-decoration:none;
  transition:color .25s var(--ease),transform .4s var(--ease)}
.area__r svg{width:15px;height:15px;flex:none;color:var(--acc);fill:none;
  stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;
  transition:transform .4s var(--ease)}
.area__r--plain{color:var(--gray);font-weight:500}
/* One hue for every pin. At --line-2 the plain ones were all but invisible,
   and they no longer need to carry the distinction: the arrow does that. */
.area__r--plain svg{color:var(--acc);opacity:.42}
/* One pin, one meaning. What separates a row that is a PAGE from a row that is
   just a place name is the arrow, not a second icon colour - an affordance
   rather than a decoration. */
.area__r > span{flex:1 1 auto;min-width:0}
a.area__r > svg:last-child{width:15px;height:15px;color:var(--acc);
  opacity:0;transform:translateX(-6px);
  transition:opacity .3s var(--ease),transform .4s var(--ease)}
@media (hover:hover){
  a.area__r:hover > svg:last-child{opacity:1;transform:none}
}
a.area__r:focus-visible > svg:last-child{opacity:1;transform:none}
@media (hover:none){ a.area__r > svg:last-child{opacity:.5;transform:none} }
/* the sweep is a pseudo-element so the hover costs no layout */
a.area__r::after{content:"";position:absolute;left:-6px;right:-6px;top:1px;bottom:1px;
  z-index:-1;border-radius:var(--r-sm);background:var(--plum-tint);
  opacity:0;transition:opacity .3s var(--ease)}
@media (hover:hover){
  a.area__r:hover{color:var(--acc);transform:translateX(8px)}
  a.area__r:hover::after{opacity:1}
  a.area__r:hover svg{transform:scale(1.15)}
}
a.area__r:focus-visible{color:var(--acc);transform:translateX(8px)}
a.area__r:focus-visible::after{opacity:1}
.area__ask{display:flex;flex-wrap:wrap;align-items:center;gap:16px 22px;
  margin-top:clamp(26px,3.4vw,40px);padding:22px 24px;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r)}
.area__ask p{flex:1 1 280px;font-family:var(--f-disp);font-weight:600;
  font-size:clamp(15.8px,1.3vw,18.4px);letter-spacing:var(--tr-md);
  line-height:1.34;margin:0}

.area__media{display:grid;grid-template-columns:1.62fr 1fr;gap:clamp(16px,2vw,26px);
  margin-top:clamp(26px,3.4vw,40px);align-items:start}
/* A raw Google satellite tile is brown and green on a plum and coal page - the
   one element on the site that belonged to somebody else's palette. Greyscale
   first, then a sepia base rotated onto the accent hue, so it reads as part of
   the band; the filter lifts on hover, because someone reaching for the map
   wants the real thing. */
.map{margin:0;border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  background:var(--panel-2);position:relative}
/* Duotone by BLEND, not by filter maths. Chaining sepia + hue-rotate +
   saturate onto satellite imagery lands wherever the source pixels happen to
   be - here a pastel pink, not the plum of the palette. Greyscale first, then
   one plum layer in `color` blend mode, puts the hue exactly where the token
   is. The layer is pointer-events:none so the map still pans and zooms. */
.map iframe{display:block;width:100%;height:100%;min-height:360px;border:0;
  filter:grayscale(1) contrast(1.06) brightness(1.04);
  transition:filter .5s var(--ease)}
.map::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:1;
  background:var(--plum);mix-blend-mode:multiply;opacity:.58;
  transition:opacity .5s var(--ease)}
@media (hover:hover){
  .map:hover iframe{filter:none}
  .map:hover::after{opacity:0}
}
.map:focus-within iframe{filter:none}
.map:focus-within::after{opacity:0}
@media (prefers-reduced-motion:reduce){
  .map iframe,.map::after{transition:none}
}
/* ---- THE VALLEY MAP -------------------------------------------------------
   A radar of the service territory, drawn from the client's own embed
   coordinates (see inc/valley-map.php). Dark card on the light section: it is
   a figure, not a band, so it spends none of the page's one inverted band. */
.vm{position:relative;aspect-ratio:var(--vm-ar);max-height:min(74vh,660px);
  border-radius:var(--r-lg);overflow:hidden;isolation:isolate;
  background:radial-gradient(120% 90% at 50% 20%,var(--coal-3),var(--coal) 55%,var(--coal-2));
  box-shadow:0 1px 0 rgba(255,255,255,.04) inset,0 22px 50px -30px rgba(22,19,32,.55)}
.vm__svg{position:relative;z-index:1;display:block;width:100%;height:100%}

.vm__grid line{stroke:rgba(255,255,255,.045);stroke-width:1}
.vm__rings circle{fill:none;stroke:rgba(201,143,216,.22);stroke-width:1;
  stroke-dasharray:2 5}
.vm__rings circle:nth-child(4){stroke-dasharray:none;stroke:rgba(201,143,216,.16)}
.vm__spoke{stroke:var(--plum-br);stroke-width:1;opacity:0;
  transition:opacity var(--t-feedback) var(--ease)}
.vm__spoke.is-on{opacity:.55}

.vm__dot{fill:var(--plum-br);transform-box:fill-box;transform-origin:center;
  transition:transform var(--t-gesture) var(--spring),fill var(--t-feedback) var(--ease)}
.vm__p--zip .vm__dot{fill:rgba(201,143,216,.7)}
.vm__halo{fill:var(--plum-vv);opacity:0;transform-box:fill-box;transform-origin:center}
.vm__p.is-on .vm__dot{fill:#fff;transform:scale(1.9)}
.vm__p{cursor:pointer}

.vm__l{font-family:var(--f-disp);font-size:11.5px;font-weight:600;letter-spacing:.02em;
  fill:rgba(255,255,255,.86);pointer-events:none;
  paint-order:stroke;stroke:var(--coal);stroke-width:3px;stroke-linejoin:round}

.vm__base-ring{fill:none;stroke:var(--plum-lt);stroke-width:1.5;opacity:.7;
  transform-box:fill-box;transform-origin:center}
.vm__base{fill:#fff;stroke:var(--plum-vv);stroke-width:3}

/* the sweep: a conic wedge turning around the base, bright on its leading edge */
.vm__sweep{position:absolute;z-index:0;aspect-ratio:1;translate:-50% -50%;
  border-radius:50%;pointer-events:none;opacity:0;
  background:conic-gradient(from -58deg,transparent 0deg,rgba(162,75,184,.34) 56deg,
    rgba(227,194,236,.55) 58deg,transparent 58.4deg);
  -webkit-mask:radial-gradient(closest-side,#000 0,#000 72%,transparent 100%);
          mask:radial-gradient(closest-side,#000 0,#000 72%,transparent 100%)}

.vm__tip{position:absolute;z-index:2;translate:-50% calc(-100% - 16px);
  padding:6px 11px;border-radius:99px;white-space:nowrap;pointer-events:none;
  font-family:var(--f-disp);font-size:12.6px;font-weight:600;color:var(--ink);
  background:#fff;box-shadow:0 10px 24px -12px rgba(0,0,0,.6)}

/* reveal: the points light up outward from the base, nearest first */
.js .vm__p,.js .vm__l{opacity:0;transition:opacity .45s var(--ease)}
.js .vm__p{transition-delay:var(--rd)}
.js .vm__l{transition-delay:var(--rd)}
.js .ro.in .vm__p,.js .ro.in .vm__l{opacity:1}
.vm__p--base{opacity:1!important}

/* ambient motion runs only while the map is on screen (.vm--live, set by
   site.js) and never under reduced motion - site.js does not set it then */
.vm--live .vm__sweep{opacity:1;animation:vm-sweep var(--vm-period) linear infinite}
.vm--live .vm__halo{animation:vm-ping var(--vm-period) linear infinite;animation-delay:var(--d)}
/* (the dots no longer flash on the sweep: animating an SVG `fill` repainted the
   whole map every frame while it was on screen) */
.vm--live .vm__base-ring{animation:vm-base 2.6s var(--ease) infinite}
@keyframes vm-sweep{to{rotate:360deg}}
@keyframes vm-ping{0%{opacity:.8;transform:scale(.5)}12%{opacity:0;transform:scale(2.6)}100%{opacity:0}}
@keyframes vm-hit{0%{fill:#fff}14%{fill:var(--plum-br)}100%{fill:var(--plum-br)}}
@keyframes vm-base{0%{transform:scale(1);opacity:.7}70%{transform:scale(2.1);opacity:0}100%{opacity:0}}
.vm__p.is-on .vm__dot{animation:none}

/* the index answers the map: a row whose place is under the cursor lights up */
a.area__r.is-lit{color:var(--acc)}
a.area__r.is-lit::after{opacity:1}

/* ---- OPEN NOW ------------------------------------------------------------ */
.now{display:inline-flex;align-items:center;gap:10px;margin-top:14px;
  padding:7px 14px 7px 12px;border-radius:99px;
  border:1px solid rgba(255,255,255,.16);background:rgba(255,255,255,.05);
  font-family:var(--f-disp);font-size:13.6px;font-weight:600;color:#fff}
.now__dot{width:9px;height:9px;border-radius:50%;background:var(--plum-br);flex:none}
.now--open .now__dot{background:#5ee08f;box-shadow:0 0 0 0 rgba(94,224,143,.6);
  animation:now-pulse 2.2s var(--ease) infinite}
@keyframes now-pulse{0%{box-shadow:0 0 0 0 rgba(94,224,143,.55)}
  70%{box-shadow:0 0 0 10px rgba(94,224,143,0)}100%{box-shadow:0 0 0 0 rgba(94,224,143,0)}}
@media (prefers-reduced-motion:reduce){ .now--open .now__dot{animation:none} }

/* The widget is third-party: it replaces the anchor's contents when it loads
   and leaves the anchor alone when it is blocked. Reserving a tall box gave a
   large empty frame in that case, so the card is sized by its own content and
   the client's own label stays as the visible link. */
.wx{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;
  background:var(--white);display:flex;flex-direction:column;align-self:start;
  min-height:190px}
.wx__hd{display:flex;align-items:center;gap:8px;padding:13px 16px;
  border-bottom:1px solid var(--line);font-family:var(--f-disp);font-size:10.8px;
  font-weight:600;letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--gray)}
.wx__hd svg{width:14px;height:14px;color:var(--acc);fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.wx a{display:block;padding:16px;font-size:14.4px;font-weight:700;
  color:var(--acc);text-decoration:none}
@media (hover:hover){ .wx a:hover{text-decoration:underline;text-underline-offset:3px} }
@media (max-width:900px){
  /* .map iframe here still serves the LOCATION pages, whose media block keeps
     the two-up layout; the homepage's own .area__side rule out-specifies it. */
  .area__media{grid-template-columns:1fr}
  .map iframe{min-height:290px}
  /* Not 0. The widget swaps the anchor for an iframe that collapses whenever
     its data call to forecast7.com is blocked, and at 0 the card became a 47px
     header with nothing under it - which reads as broken rather than as a card
     waiting for data. Enough room for the label, not enough to be a hole. */
  .wx{min-height:116px}
}
@media (max-width:560px){ .area__ls{grid-template-columns:1fr} }

/* ===================================================== 5. SCHEDULE ======= */
.steps{position:relative;display:grid;grid-template-columns:repeat(3,1fr);
  gap:clamp(22px,3vw,40px);margin-top:clamp(36px,4.4vw,56px)}
/* the hairline the numerals sit on, drawn left-to-right when the band enters */
.steps__rule{position:absolute;left:28px;right:28px;top:27px;height:1px;
  background:linear-gradient(90deg,var(--plum-br) 0%,rgba(201,143,216,.5) 58%,rgba(255,255,255,0) 100%);
  transform:scaleX(0);transform-origin:0 50%;
  transition:transform 1.1s var(--ease) .05s}
.steps.in .steps__rule{transform:scaleX(1)}
.steps__s{position:relative;padding-right:14px}
.steps__n{position:relative;z-index:2;
  display:inline-flex;align-items:center;justify-content:center;
  width:56px;height:56px;border-radius:50%;background:var(--coal);color:#fff;
  border:1.5px solid var(--plum-br);
  font-family:var(--f-disp);font-weight:700;font-size:23px;letter-spacing:0;
  font-variant-numeric:tabular-nums;margin-bottom:20px;
  box-shadow:0 0 0 8px var(--coal)}
.steps__t{display:block;font-family:var(--f-disp);font-weight:600;
  font-size:clamp(17px,1.5vw,20.5px);letter-spacing:var(--tr-md);margin-bottom:8px;
  color:#fff;line-height:1.22}
.steps__d{font-size:14.9px;line-height:1.6;color:rgba(255,255,255,.78);margin:0;
  text-wrap:pretty}

@media (max-width:860px){
  .steps{grid-template-columns:1fr;gap:26px}
  .steps__rule{left:27px;right:auto;top:28px;bottom:28px;width:1px;height:auto;
    background:linear-gradient(180deg,var(--plum-br) 0%,rgba(201,143,216,.5) 58%,rgba(255,255,255,0) 100%);
    transform:scaleY(0);transform-origin:50% 0}
  .steps.in .steps__rule{transform:scaleY(1)}
  .steps__s{display:grid;grid-template-columns:56px 1fr;gap:4px 18px}
  .steps__n{grid-row:span 2;margin-bottom:0}
}

/* ===================================================== 6. HOURS ========== */
/* closes the dark band; see the note in home-page.php */
.hours{display:grid;grid-template-columns:auto 1fr;align-items:center;
  gap:18px clamp(26px,4vw,56px);margin-top:clamp(44px,5.4vw,72px);
  padding-top:clamp(28px,3.4vw,40px);border-top:1px solid rgba(255,255,255,.14)}
.hours__l{display:flex;align-items:center;gap:14px}
.hours__l svg{width:26px;height:26px;flex:none;color:var(--plum-br);fill:none;
  stroke:currentColor;stroke-width:1.6;stroke-linecap:round;stroke-linejoin:round}
.hours h2{color:#fff}
.hours__v{font-size:clamp(15px,1.25vw,16.8px);line-height:1.62;
  color:rgba(255,255,255,.8);margin:0;text-wrap:pretty}
.hours__v + .hours__v{margin-top:8px}
@media (max-width:760px){ .hours{grid-template-columns:1fr;gap:14px} }

/* ===================================================== 7. FAQ =========== */
.faqw{display:grid;grid-template-columns:.78fr 1.22fr;gap:clamp(26px,4vw,60px);
  align-items:start}
.faqw__l{position:sticky;top:calc(var(--bar) + 26px)}
.faq{display:grid;gap:10px}
.faq__i{background:var(--white);border:1px solid var(--line);border-radius:var(--r);
  transition:border-color .25s var(--ease),box-shadow .3s var(--ease)}
.faq__i[open]{border-color:var(--line-2);box-shadow:var(--sh)}
.faq__q{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:14px;
  padding:17px 19px;cursor:pointer;list-style:none}
.faq__q::-webkit-details-marker{display:none}
.faq__n{font-family:var(--f-disp);font-size:12.5px;font-weight:500;color:var(--acc);
  font-variant-numeric:tabular-nums;letter-spacing:.03em}
/* A QUESTION IS A LINE OF READING, NOT A HEADING. Rendered on three options
   side by side (current / text face 500 / display face 400): the display face
   at REGULAR weight in the softer ink keeps the site's typographic voice
   without the weight. Seven to nine of these stack in a column, and at 500-600
   in near-black they read as a column of shouting; the user flagged it twice.
   The open question is the one that turns plum - a single highlight. */
.faq__q .h3{font-size:clamp(16px,1.24vw,17.2px);line-height:1.42;font-weight:400;
  letter-spacing:-.008em;color:var(--ink-2)}
.faq__i[open] .faq__q .h3{color:var(--acc-2)}
.faq__x{position:relative;width:18px;height:18px;flex:none;color:var(--acc)}
.faq__x::before,.faq__x::after{content:"";position:absolute;left:50%;top:50%;
  background:currentColor;border-radius:2px;transition:transform .35s var(--ease)}
.faq__x::before{width:14px;height:2px;transform:translate(-50%,-50%)}
.faq__x::after{width:2px;height:14px;transform:translate(-50%,-50%)}
.faq__i[open] .faq__x::after{transform:translate(-50%,-50%) rotate(90deg);opacity:0}
.faq__a{padding:0 19px 19px 51px}
.faq__a .copy{font-size:15px}
@media (hover:hover){ .faq__q:hover .h3{color:var(--acc-2)} }
.faq__q:focus-visible .h3{color:var(--acc-2)}
@media (max-width:900px){
  .faqw{grid-template-columns:1fr;gap:24px}
  .faqw__l{position:static}
  .faq__a{padding-left:19px}
}

/* ===================================================== 8. CONTACT ======== */
.con{position:relative;background:var(--coal);color:#fff;isolation:isolate;
  padding-block:var(--sec)}
.con__bg{position:absolute;inset:0;overflow:hidden;z-index:0}
.con__bg img{width:100%;height:100%;object-fit:cover;object-position:50% 46%}
.con__scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:linear-gradient(100deg,
    rgba(16,12,21,.96) 0%, rgba(16,12,21,.93) 40%, rgba(16,12,21,.82) 58%,
    rgba(16,12,21,.7) 78%, rgba(16,12,21,.62) 100%)}
.con__gr{position:relative;z-index:2;display:grid;grid-template-columns:1fr 1.02fr;
  gap:clamp(30px,4vw,64px);align-items:start}
.con__l .copy{color:rgba(255,255,255,.84)}
.con__acts{display:flex;flex-wrap:wrap;gap:12px;margin-top:26px}
.con__facts{display:grid;gap:12px;margin-top:30px;padding-top:26px;
  border-top:1px solid var(--line-dk)}
.con__f{display:flex;align-items:center;gap:11px;font-size:14.8px;
  color:rgba(255,255,255,.82)}
.con__f svg{width:17px;height:17px;flex:none;color:var(--plum-br);fill:none;
  stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
/* the glass seam — the signature that marks every dark band */
.con::before{content:"";position:absolute;left:0;right:0;top:0;height:2px;z-index:3;
  background:linear-gradient(90deg,var(--plum-vv) 0%,var(--plum-br) 42%,transparent 88%)}
@media (max-width:980px){ .con__gr{grid-template-columns:1fr} }

/* ===================================================== request sheet ===== */
/* THE QUOTE BAND (inc/quote-band.php), directly after every hero: Night Glass seen in daylight.
   The ground is lit by two soft plum lights and crossed by two faint reflection streaks; the
   sheet is a pane of clear glass on it - translucent white, a bright upper edge, a plum-tinted
   shadow - with a dark SHADE BAND down its left side (on a phone, across its top: the tinted
   strip of a windscreen), opening with the 2px plum seam every dark pane on this site carries.

   Painted once. No backdrop-filter: it re-blurs whatever moves beneath it on every frame, and
   the 2026-09-30 lag fix removed exactly that. Over a ground that is itself soft gradients, a
   translucent pane reads as glass without any blur. */
.qband{position:relative;isolation:isolate;overflow:hidden;background:var(--panel);
  padding-block:clamp(52px,6.4vw,88px)}
/* a hero with a credential rail hangs it 38px over whatever follows */
.hero:has(.hero__rail) + .qband{padding-top:calc(clamp(52px,6.4vw,88px) + 38px)}
/* ...and must sit ABOVE the band: the band is positioned and comes later in the DOM, so
   without this it painted over the rail's last 38px (its second row, cut in half) */
.hero:has(+ .qband){z-index:2}
.qband::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:
    radial-gradient(40% 70% at 8% 14%,rgba(162,75,184,.20),transparent 70%),
    radial-gradient(36% 64% at 94% 92%,rgba(109,47,112,.16),transparent 70%),
    radial-gradient(28% 50% at 64% 2%,rgba(227,194,236,.62),transparent 72%),
    linear-gradient(112deg,transparent 0 57%,rgba(255,255,255,.62) 57% 58.3%,
      transparent 58.3% 60%,rgba(255,255,255,.42) 60% 60.6%,transparent 60.6%)}
.qband__in{max-width:1080px;margin-inline:auto}

.qcard{position:relative;display:grid;grid-template-columns:minmax(0,.34fr) minmax(0,.66fr);
  border-radius:24px;overflow:hidden;color:var(--ink);
  background:linear-gradient(140deg,rgba(255,255,255,.92),rgba(255,255,255,.72));
  border:1px solid rgba(255,255,255,.95);
  box-shadow:inset 0 1px 0 #fff,0 34px 70px -38px rgba(79,31,85,.5),
    0 6px 18px -10px rgba(22,19,32,.14)}

/* the shade band */
.qcard__hd{position:relative;display:flex;flex-direction:column;gap:14px;
  padding:clamp(24px,2.6vw,34px);color:#fff;
  background-color:var(--coal);   /* a real base under the gradient: the contrast audit reads colours, not images */
  background-image:linear-gradient(165deg,#251c31 0%,var(--coal) 58%,#2a1632 100%)}
.qcard__hd::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(118deg,rgba(255,255,255,.075) 0 34%,transparent 34%)}
.qcard__hd::after{content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--plum-vv) 0%,var(--plum-br) 42%,transparent 88%)}
.qcard__hd > *{position:relative}
.qcard__t{display:block;font-family:var(--f-disp);font-weight:700;
  font-size:clamp(21px,1.9vw,26px);line-height:1.14;letter-spacing:var(--tr-lg);color:#fff}
.qcard__tel{display:inline-flex;align-items:center;gap:10px;margin-top:auto;
  font-family:var(--f-disp);font-weight:700;font-size:clamp(19px,1.6vw,22px);
  letter-spacing:var(--tr-md);color:#fff;text-decoration:none;
  font-variant-numeric:tabular-nums}
.qcard__tel svg{width:19px;height:19px;flex:none;color:var(--plum-br)}
@media (hover:hover){ .qcard__tel:hover{color:var(--plum-lt)} }
.qcard__hrs{display:flex;align-items:flex-start;gap:9px;font-size:14px;line-height:1.5;
  color:rgba(255,255,255,.78)}
.qcard__hrs svg{width:16px;height:16px;flex:none;margin-top:2px;color:var(--plum-br);
  fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}

/* the clear side: a bright upper edge, as a pane catches daylight */
.qp__f{position:relative;padding:clamp(22px,2.6vw,32px)}
.qp__f::before{content:"";position:absolute;left:0;right:0;top:0;height:46%;pointer-events:none;
  background:linear-gradient(180deg,rgba(255,255,255,.6),rgba(255,255,255,0))}
.qp__f > :not(.qp__hp){position:relative}
.qp__grid{display:grid;grid-template-columns:1fr 1fr;gap:14px 16px}
.qp__fl--w{grid-column:1/-1}
.qp__fl{display:block}
.qp__lb{display:block;font-family:var(--f-disp);font-size:11.4px;font-weight:600;
  letter-spacing:.13em;text-transform:uppercase;color:var(--gray);margin-bottom:8px}
.qp__lb b{color:var(--acc);font-weight:700}
/* Inputs are set INTO the glass: a faint inner shadow and a bright lower lip - the one
   neumorphic touch, kept subtle so the boxes still read as boxes. 16px text: below 16 iOS
   Safari zooms the page on focus. */
.qp__f input,.qp__f textarea,.qp__capbox{font:inherit;font-size:16px;color:var(--ink);
  background:rgba(255,255,255,.84);border:1px solid rgba(109,47,112,.2);border-radius:12px;
  box-shadow:inset 0 1px 2px rgba(22,19,32,.07),0 1px 0 rgba(255,255,255,.95);
  transition:border-color .2s var(--ease),box-shadow .2s var(--ease),background-color .2s var(--ease)}
.qp__f input,.qp__f textarea{display:block;width:100%;padding:12px 14px}
.qp__f textarea{resize:vertical;min-height:84px;line-height:1.55}
/* a warm grey from the plum family at 4.9:1 (the contrast audit does not read ::placeholder) */
.qp__f input::placeholder,.qp__f textarea::placeholder{color:#756e80;font-size:14.6px}
.qp__f input:focus,.qp__f textarea:focus,.qp__capbox:focus-within{outline:none;
  border-color:var(--plum);background:#fff;
  box-shadow:0 0 0 4px rgba(162,75,184,.15),inset 0 1px 2px rgba(22,19,32,.04)}
.qp__foot{display:flex;flex-wrap:wrap;align-items:end;gap:14px;margin-top:14px}
.qp__cap{flex:1 1 210px}
/* the check: the sum a muted prefix inside a box that behaves like the other inputs */
.qp__capbox{display:flex;align-items:center;gap:8px;padding:0 0 0 14px}
.qp__q{font-size:15px;color:var(--gray);white-space:nowrap;font-variant-numeric:tabular-nums}
.qp__capbox input{flex:1 1 auto;min-width:3.5em;border:0;padding-left:4px;
  background:transparent;box-shadow:none}
.qp__capbox input:focus{box-shadow:none;background:transparent}
.qp__bt{flex:0 0 auto;justify-content:center}
.qp__bt[disabled]{opacity:.55;cursor:not-allowed;box-shadow:none}
.qp__msg{margin-top:12px;font-size:14px;line-height:1.55;color:var(--gray)}
.qp__msg:empty{margin:0}
.qp__msg.err{color:#b4232b;font-weight:600}
.qp__hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
/* qf.js replaces the form with one line on success */
.qp__f .qf-done{margin:0;padding:clamp(8px,1.6vw,22px) 0;font-size:16px;line-height:1.62;
  color:var(--ink-2)}
.qp__f .qf-done::before{content:"Received";display:table;margin-bottom:12px;padding:7px 14px;
  border-radius:999px;background:var(--plum-tint);color:var(--acc);font-size:12px;
  font-weight:700;letter-spacing:.14em;text-transform:uppercase}

@media (max-width:860px){
  .qcard{grid-template-columns:1fr}
  .qcard__hd{flex-direction:row;flex-wrap:wrap;align-items:center;gap:8px 22px}
  .qcard__t{flex:1 0 100%}
  .qcard__tel{margin-top:0}
}
@media (max-width:520px){
  .qp__grid{grid-template-columns:1fr}
  .qp__bt{flex:1 1 100%}
}

/* ===================================================== closing call card = */
/* Where the request sheet used to sit in the closing band (it renders once now, after the
   hero): a pane of smoked glass on the photograph - translucent coal, a bright upper edge,
   the plum seam - holding the phone, the client's hours and the way back up to the sheet. */
.ccard{position:relative;overflow:hidden;border-radius:22px;padding:clamp(24px,2.6vw,32px);
  background:linear-gradient(155deg,rgba(255,255,255,.13),rgba(255,255,255,.035) 48%),
    rgba(16,12,21,.66);
  border:1px solid rgba(255,255,255,.16);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.2),0 34px 70px -36px rgba(0,0,0,.85)}
.ccard::before{content:"";position:absolute;left:0;right:0;top:0;height:2px;
  background:linear-gradient(90deg,var(--plum-vv) 0%,var(--plum-br) 42%,transparent 88%)}
.ccard__tel{display:flex;align-items:center;gap:12px;font-family:var(--f-disp);
  font-weight:800;font-size:clamp(28px,3vw,38px);letter-spacing:var(--tr-lg);color:#fff;
  text-decoration:none;font-variant-numeric:tabular-nums}
.ccard__tel svg{width:26px;height:26px;flex:none;color:var(--plum-br)}
@media (hover:hover){ .ccard__tel:hover{color:var(--plum-lt)} }
.ccard__facts{list-style:none;margin:20px 0 0;padding:20px 0 0;display:grid;gap:12px;
  border-top:1px solid rgba(255,255,255,.14)}
.ccard__facts li{display:flex;align-items:flex-start;gap:11px;font-size:14.8px;line-height:1.5;
  color:rgba(255,255,255,.86)}
.ccard__facts svg{width:17px;height:17px;flex:none;margin-top:2px;color:var(--plum-br);
  fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.ccard__acts{display:flex;flex-wrap:wrap;gap:12px;margin-top:24px}
.ccard__acts .btn{flex:1 1 auto;justify-content:center}


/* ============================================================================
   MOTION — one direction (everything rises), one curve, one load sequence.

   The hero sequence is pure CSS with `backwards` fill and is scoped to `.js`,
   so it cannot strand content: with scripting off the hero simply renders, and
   under prefers-reduced-motion the global rule collapses every duration and the
   elements land on their end state. Nothing here animates anything but
   transform and opacity.

   BEAT 0  0.00s  the photograph settles (14s drift, starts immediately)
   BEAT 1  0.10s  headline lines rise, 90ms apart  -> readable by ~1.1s
   BEAT 2  0.46s  lede fades up
   BEAT 3  0.60s  actions
   BEAT 4  0.70s  call line
   BEAT 5  0.80s  the glass rail slides up, its items fading 60ms apart
   Total settle < 1.9s.
   ========================================================================= */
@keyframes ng-rise{from{opacity:0;transform:translateY(22px)}to{opacity:1;transform:none}}
@keyframes ng-rise-sm{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
@keyframes ng-railup{from{opacity:0;transform:translateY(100%)}to{opacity:1;transform:none}}
@keyframes ng-drift{from{transform:scale(1.07)}to{transform:scale(1)}}

.js .hero__bg img{animation:ng-drift 14s var(--ease) backwards}
.js .h1 .ln{animation:ng-rise var(--t-entrance) var(--ease) backwards}
.js .h1 .ln--1{animation-delay:.10s}
.js .h1 .ln--2{animation-delay:.19s}
.js .h1 .ln--3{animation-delay:.28s}
.js .h1 .ln--4{animation-delay:.37s}
.js .hero__lede{animation:ng-rise var(--t-entrance) var(--ease) .46s backwards}
.js .hero__acts{animation:ng-rise var(--t-entrance) var(--ease) .60s backwards}
.js .hero__call{animation:ng-rise-sm var(--t-entrance) var(--ease) .70s backwards}
.js .hero__rail{animation:ng-railup 1.05s var(--ease) .80s backwards}
.js .rail__i{animation:ng-rise-sm .7s var(--ease) backwards}
.js .rail__i:nth-child(1){animation-delay:.95s} .js .rail__i:nth-child(2){animation-delay:1.01s}
.js .rail__i:nth-child(3){animation-delay:1.07s} .js .rail__i:nth-child(4){animation-delay:1.13s}
.js .rail__i:nth-child(5){animation-delay:1.19s} .js .rail__i:nth-child(6){animation-delay:1.25s}
.js .rail__i:nth-child(7){animation-delay:1.31s} .js .rail__i:nth-child(8){animation-delay:1.37s}

/* WHY — the photograph wipes open from its own bleeding edge rather than
   fading like everything else. It is the largest object on the page, and big
   objects should move slowly and little (design-method 5.1). */
.js .why__ph{clip-path:inset(0 0 0 0)}
.js .why__ph.ro{opacity:1;transform:none;clip-path:inset(0 100% 0 0);
  transition:clip-path 1.1s var(--ease)}
.js .why__ph.ro.in{clip-path:inset(0 0 0 0)}
.js .why__ph img{transform:scale(1.06);transition:transform 1.3s var(--ease)}
.js .why__ph.ro.in img{transform:none}
/* the feature rows follow the picture, in pairs */
.js .why__bd .feat__i{opacity:0;transform:translateY(12px);
  transition:opacity .45s var(--ease),transform .6s var(--ease)}
.js .why__bd.in .feat__i{opacity:1;transform:none}
.js .why__bd.in .feat__i:nth-child(1),.js .why__bd.in .feat__i:nth-child(2){transition-delay:.03s}
.js .why__bd.in .feat__i:nth-child(3),.js .why__bd.in .feat__i:nth-child(4){transition-delay:.07s}
.js .why__bd.in .feat__i:nth-child(5),.js .why__bd.in .feat__i:nth-child(6){transition-delay:.11s}
.js .why__bd.in .feat__i:nth-child(7),.js .why__bd.in .feat__i:nth-child(8){transition-delay:.15s}

/* SCHEDULE — the numerals arrive after the rule has drawn past them. One
   spring in the viewport, on an element well under 80px: the documented limit. */
.js .steps__n{opacity:0;transform:scale(.72);
  transition:opacity .4s var(--ease),transform .55s var(--spring),
  background-color .45s var(--ease),box-shadow .45s var(--ease),border-color .45s var(--ease)}
.js .steps.in .steps__n{opacity:1;transform:none}
.js .steps.in .steps__s:nth-child(2) .steps__n{transition-delay:.15s}
.js .steps.in .steps__s:nth-child(3) .steps__n{transition-delay:.32s}
.js .steps.in .steps__s:nth-child(4) .steps__n{transition-delay:.49s}

/* AREAS — rows arrive in a short cascade, capped so the last never waits */
.js .area__ls .area__r{opacity:0;transform:translateY(8px);
  transition:opacity .4s var(--ease),transform .5s var(--ease)}
.js .ro.in .area__ls .area__r{opacity:1;transform:none}
.js .ro.in .area__ls .area__r:nth-child(1){transition-delay:.01s}
.js .ro.in .area__ls .area__r:nth-child(2){transition-delay:.03s}
.js .ro.in .area__ls .area__r:nth-child(3){transition-delay:.05s}
.js .ro.in .area__ls .area__r:nth-child(4){transition-delay:.07s}
.js .ro.in .area__ls .area__r:nth-child(5){transition-delay:.09s}
.js .ro.in .area__ls .area__r:nth-child(6){transition-delay:.11s}
.js .ro.in .area__ls .area__r:nth-child(7){transition-delay:.13s}
.js .ro.in .area__ls .area__r:nth-child(n+8){transition-delay:.15s}

/* FAQ — the answer unfolds instead of appearing. Height is animated only where
   the browser can interpolate to `auto`; everywhere else the answer still
   fades and rises, so the behaviour degrades to a fade rather than to nothing. */
@keyframes ng-answer{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
.faq__i[open] .faq__a{animation:ng-answer .5s var(--ease)}
@supports (interpolate-size: allow-keywords){
  :root{interpolate-size:allow-keywords}
  .faq__i{overflow:hidden}
  .faq__i::details-content{block-size:0;opacity:0;
    transition:block-size .45s var(--ease),content-visibility .45s allow-discrete,opacity .35s var(--ease);
    content-visibility:hidden}
  .faq__i[open]::details-content{block-size:auto;opacity:1;content-visibility:visible}
  .faq__i[open] .faq__a{animation:none}
}

/* CONTACT — the request sheet is the page's last object; it settles, it does
   not slide in from the side. */
.js .con__r.ro{transform:translateY(30px)}
.js .con__r.ro.in{transform:none}

@media (prefers-reduced-motion:reduce){
  .js .hero__bg img,.js .h1 .ln,.js .hero__lede,.js .hero__acts,.js .hero__call,
  .js .hero__rail,.js .rail__i{animation:none}
  .js .why__ph.ro,.js .why__ph.ro.in{clip-path:none}
  .js .why__ph img,.js .why__ph.ro.in img{transform:none}
  .js .why__bd .feat__i,.js .steps__n,.js .area__ls .area__r{opacity:1;transform:none}
}

/* ===================================================== THE LAMP ========== */
/* (see home-page.php) Two layers, both MOVED, never redrawn: site.js writes
   only `transform` on them, which the compositor does without painting.
   The first version masked the whole hero scrim with a gradient that followed
   the pointer - a full-hero repaint per frame, 50ms frames at 4x CPU.

   .lamp__night  a huge square: clear at the centre, darkening outward - it only
                 ever ADDS dark on top of the approved scrim, so wherever it
                 falls, the copy is at least as dark as the still hero.
   .lamp__glow   a faint warm light at the same point, normal blending, held by
                 site.js ~200px clear of the copy's measured text edge.
   Wide screens only; no script / reduced motion = the approved still hero. */
.hero__lamp{position:absolute;inset:0;z-index:1;pointer-events:none;overflow:hidden;
  opacity:0;transition:opacity .9s var(--ease)}
.hero__lamp i{position:absolute;left:0;top:0;will-change:transform}
.lamp__night{width:4400px;height:4400px;margin:-2200px 0 0 -2200px;
  background:radial-gradient(circle at center,transparent 0,transparent 64px,
    rgba(12,9,17,.31) 150px,rgba(12,9,17,.5) 245px,rgba(12,9,17,.5) 100%)}
.lamp__glow{width:520px;height:520px;margin:-260px 0 0 -260px;
  background:radial-gradient(circle at center,rgba(255,244,252,.12) 0,
    rgba(227,194,236,.075) 70px,rgba(162,75,184,.045) 150px,transparent 250px)}
@media (min-width:981px){ .hero.is-lamp .hero__lamp{opacity:1} }

/* FOCUS - the headline comes into focus rather than sliding in: clarity is
   what a glass company sells. Reference B's entrance engine; blur only on the
   headline (a big, short-lived filter), everything else keeps its rise. */
@keyframes ng-focus{from{opacity:0;filter:blur(12px);transform:translateY(10px)}
  to{opacity:1;filter:blur(0);transform:none}}
.js .h1 .ln,.js .h1.h1--int{animation-name:ng-focus}   /* .h1.h1--int: interior.css loads later */

/* THE PROCESS LIGHT - the numbered band's seam is a plum light the READER
   drives: it runs along the rule as the band scrolls through the viewport,
   and each numeral lights as it arrives (Reference B's scroll-linked dial,
   re-set as Night Glass's one plum light). site.js adds .steps--live and
   writes --p; without it the rule draws on reveal exactly as before. */
/* .steps.in .steps__rule (the reveal's scaleX(1)) is three classes deep */
.steps.steps--live .steps__rule,.steps.steps--live.in .steps__rule{
  transform:scaleX(var(--p,0));transition:none}
/* a light is brightest at its HEAD: the static rule fades toward its end,
   which on a moving line read as a light going out */
.steps.steps--live .steps__rule{height:2px;top:26.5px;
  background:linear-gradient(90deg,rgba(201,143,216,.28),var(--plum-br));
  box-shadow:0 0 12px rgba(162,75,184,.55)}
@media (max-width:860px){
  .steps.steps--live .steps__rule,.steps.steps--live.in .steps__rule{transform:scaleY(var(--p,0))}
  .steps.steps--live .steps__rule{width:2px;height:auto;top:28px;left:26.5px;
    background:linear-gradient(180deg,rgba(201,143,216,.28),var(--plum-br))}
}
.steps--live .steps__s.is-lit .steps__n{background-color:var(--plum);border-color:var(--plum-br);
  box-shadow:0 0 0 8px var(--coal),0 0 26px 2px rgba(162,75,184,.55)}
