/* Alder Heating & Air Co. demo — the page's own styles.
 *
 * Forked from the solo sample at /hvac/alder on 2026-09-24. Everything the
 * two share below the hero is the export's; everything that differs is in
 * the "the departure" block directly under this comment, plus the .cohero
 * and .board rules where the banner used to be. If you are changing one of
 * the two demos and wondering whether the other needs the same change: the
 * answer is usually no, and that is the point of them being separate files.
 *
 * Ported from the design export "Alder Heating and Air - offline.html". The
 * canvas writes every declaration as an inline style attribute, which is how
 * the canvas works and not how a page should ship, so they are lifted into
 * classes here. Every VALUE is the export's: the clamps, the easings, the odd
 * 14.5px and 17.5px sizes, the 4/4.4 about ratio, the 1.05fr/0.95fr hero
 * split. If a number here disagrees with the canvas, this file is wrong.
 *
 * Three deliberate departures, each noted where it appears:
 *
 *  - the export branches its layout on window.innerWidth at 760, 900, 1180
 *    and 1220; those are media queries here. A media query measures the
 *    viewport WITHOUT the classic scrollbar and innerWidth measures it with,
 *    so the two disagree by up to ~15px right at a breakpoint. Nothing in
 *    this layout is knife-edge at those widths, and the alternative is a
 *    resize listener re-rendering the page.
 *  - the four views are real sections toggled with [hidden] rather than
 *    re-rendered subtrees.
 *  - the site footer sits outside <main> and carries main's frame itself.
 *
 * Nocturne's own tokens and component classes (.btn, .tag, .lighten, the
 * palette) come from nocturne.css and are not restated.
 *
 * On the eyebrow sizes: the export uses 12px for section and page labels,
 * 11.5px for labels inside a panel, and 11px in the footer. They are three
 * classes on purpose. One .eyebrow carrying whichever size was measured
 * first is how the sibling demo rendered every eyebrow as body text.
 */

/* ------------------------------------------------------- the departure ---
   nocturne.css is byte-identical across all three Nocturne demos, so the
   whole of each one's identity is here. This sample is steel on cool pale
   ground with square corners; the solo HVAC one is violet on lavender-grey
   with soft ones; the electrical company one is copper on warm cream with
   tight ones. Night values only -- page.js writes daylight onto the root as
   inline custom properties, which outrank any :root rule. */
:root {
  --color-accent: #43c3dd;
  --color-accent-100: #eafaff;
  --color-accent-200: #d3f3fb;
  --color-accent-300: #a8e6f4;
  --color-accent-800: #10454f;
  --color-accent-900: #0b2e36;
  --color-accent-2-300: #9fd8e6;

  /* Square, all the way down. Kept in step with CURVE in page.js by hand. */
  --radius-sm: 0px;
  --radius-md: 0px;
  --radius-lg: 0px;
}

/* --------------------------------------- hero: the board, on a photograph -
   Two columns on a wide screen, stacked on a narrow one. The copy is capped
   at a measure rather than filling the column, because a 1280px line of
   17.5px body text is unreadable and the board is what should take the slack.

   The photograph went in on 2026-09-23. Type that sits on it is light in BOTH
   themes, so the colours in this block are literal rather than var()s: a
   token that flips with the theme puts dark text on a dark picture the moment
   someone hits the sun. --banner-ink is the scrim's colour and the only value
   here tied to this particular frame. */
.cohero {
  --banner-ink: 8, 20, 26;
  /* The wrap's left margin: 0 until the viewport passes .wrap's 1280px, then
     half the overflow. The horizontal stops below hang off it. Fixed
     2026-09-23 alongside the same fault on /electrician/marek -- stops
     measured from the viewport edge leave a dead band on a wide screen and,
     worse, let the centred copy walk out of its own scrim. */
  --gx: max(0px, (100vw - 1280px) / 2);
  position: relative; isolation: isolate;
  border-bottom: 3px solid var(--color-accent);
  animation: al-fade 0.7s ease both;
}
.cohero__media { position: absolute; inset: 0; z-index: -1; overflow: hidden; }
.cohero__media img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 44%;
  filter: saturate(0.92) contrast(1.04);
}
/* Two passes. The vertical one is light: it is there for the strip the sticky
   rail sits over and the foot of the section, nothing more. The horizontal
   one does the work, and its shape was measured rather than guessed.

   The left of this frame is dark -- mean 33 of 255 -- but a fan grille sits
   about a third of the way across with specular highlights in it (99.5th
   percentile 239), and the longest heading line runs straight over them. A
   gentle ramp left "Nine trucks, one" at 2.85:1.

   The stops are in PIXELS, not percentages, and that is the point of them.
   The copy column is a fixed ~507px measure at every desktop width, so its
   right edge is 39% of 1440 and 69% of 820; a ramp in percentages either
   leaves the copy exposed at one end of that range or buries the photograph
   at the other. 500/660/800px tracks the column, and hanging them off --gx
   rather than off zero is what keeps them tracking it once .wrap stops
   growing and starts centring. Past --gx + 800px the photograph is
   untouched, which at 1440 is the strip beside the board and the bands above
   and below it, and on a 2560 display is most of the right-hand half.

   Layered gradients compound: 0.14 over 0.86 is 0.88, not 0.86. Getting that
   backwards is what turned the first attempt into a flat slab. */
.cohero__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg,
      rgba(var(--banner-ink), 0.52) 0%,
      rgba(var(--banner-ink), 0.12) 30%,
      rgba(var(--banner-ink), 0.16) 66%,
      rgba(var(--banner-ink), 0.58) 100%),
    linear-gradient(90deg,
      rgba(var(--banner-ink), 0.30) calc(var(--gx) - 300px),
      rgba(var(--banner-ink), 0.84) var(--gx),
      rgba(var(--banner-ink), 0.80) calc(var(--gx) + 500px),
      rgba(var(--banner-ink), 0.34) calc(var(--gx) + 660px),
      rgba(var(--banner-ink), 0.04) calc(var(--gx) + 800px));
}
/* Narrow: the copy runs the full width and cover() blows up a thin vertical
   slice of the frame. Left un-steered that slice is the middle of the
   photograph, which is its brightest part -- the lede measured 2.01:1 at
   375px. Pulling object-position to the left edge picks the dark end of the
   frame instead, and the scrim goes flat because there is no longer a column
   of copy to protect, just all of it. */
@media (max-width: 759px) {
  .cohero__media img { object-position: 6% 50%; }
  .cohero__scrim {
    background: linear-gradient(180deg,
      rgba(var(--banner-ink), 0.82) 0%,
      rgba(var(--banner-ink), 0.74) 42%,
      rgba(var(--banner-ink), 0.86) 100%);
  }
}
.cohero__inner {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(26px, 4vw, 52px); align-items: center;
  padding-block: clamp(38px, 6vw, 82px) clamp(34px, 5vw, 74px);
}
/* 50ch, not the 54 the boxed hero used, and the lede is pulled in further
   still. Every character the copy runs to the right is a character the scrim
   has to cover, and the scrim is what the photograph is paying for. */
.cohero__copy { max-width: 50ch; }
.cohero .kicker { margin-bottom: 20px; }
/* A square marker instead of the 44px hairline the section kickers keep: the
   same 9px block the board's own heading uses, so the two things standing on
   the photograph are marked the same way. */
.cohero .kicker .rule { width: 9px; height: 9px; background: #7fd8ea; }
/* Every one of these is qualified with .cohero, and none of them can lose the
   qualifier. This block sits above the base styles, so at equal specificity
   the LATER rule wins: a bare .cohero__lede is (0,1,0) and so is the .lede it
   is meant to override, which left the hero lede rendering in
   --color-neutral-200 -- slate on a dark photograph. Same for .fine--on
   against .fine, and .kicker--on's span against .kicker's, which is (0,2,1)
   and needs three classes to beat. */
.cohero .kicker--on > span:not(.rule) { color: rgba(255, 255, 255, 0.86); }
.cohero .cohero__h { color: #fff; }
.cohero .cohero__lede { color: rgba(255, 255, 255, 0.90); max-width: 42ch; }
.cohero .fine--on { color: rgba(255, 255, 255, 0.82); }
.cohero__foot { display: block; margin: 18px 0 0; }
/* Neither button survives here with its accent. .btn-primary is an outlined
   accent button and .btn-ghost is accent text; over this scrim the day accent
   #0d6b7d measures 1.6:1, which is not a near miss. White is above 14:1 in
   both themes and does not move when the palette does. Square, like
   everything else on this demo. */
.cohero .btn-primary { background: #fff; color: #11212a; border-color: #fff; }
.cohero .btn-primary:hover { background: rgba(255, 255, 255, 0.88); border-color: rgba(255, 255, 255, 0.88); }
.cohero .btn-ghost { color: #fff; border-color: rgba(255, 255, 255, 0.45); padding-inline: 26px; }
.cohero .btn-ghost:hover { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.72); }

.board {
  border: 1px solid var(--color-neutral-800);
  background: var(--color-surface);
  padding: clamp(16px, 2vw, 22px);
}
.board__h {
  display: flex; align-items: center; gap: 9px;
  margin: 0 0 14px;
  font-size: 12px; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--color-neutral-400);
}
/* Not animated. A pulsing dot on a page whose numbers never change is a lie
   told in CSS; this is a marker, and the note under the panel says the rest. */
.board__live {
  width: 7px; height: 7px; flex: none;
  background: var(--color-accent);
}
.board__row {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  align-items: baseline; justify-content: space-between;
  padding: 11px 0;
  border-top: 1px solid var(--color-divider);
}
.board__row:first-child { border-top: 0; padding-top: 0; }
.board__k { font-size: 13.5px; color: var(--color-neutral-300); }
.board__v {
  font-size: 14.5px; color: var(--color-text); text-align: right;
  font-variant-numeric: tabular-nums;
}
.board__note {
  margin: 14px 0 0; font-size: 12px; line-height: 1.5;
  color: var(--color-neutral-500);
}
/* On the photograph the panel needs an edge of its own and something to lift
   it off the frame. Still opaque, so every contrast figure measured for the
   board against the page ground still holds. */
.cohero .board {
  border-color: rgba(255, 255, 255, 0.18);
  border-top: 3px solid var(--color-accent);
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.38);
}

/* ---------------------------------------------------------------- base ---
   The page ground, off the export's root wrapper div. */
body {
  margin: 0;
  min-height: 100vh;
  background:
    radial-gradient(1100px 700px at 88% -180px, color-mix(in srgb, var(--color-accent-900) 74%, transparent), transparent 60%),
    radial-gradient(900px 700px at -6% 100%, color-mix(in srgb, black 30%, transparent), transparent 55%),
    var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  text-wrap: pretty;
  -webkit-font-smoothing: antialiased;
  transition: background 0.45s ease;
}
/* mix-blend-mode: lighten over a dark ground lifts the photograph; over a
   light one it washes it to nothing. Daylight turns it off. */
body[data-theme="day"] .lighten { mix-blend-mode: normal; }
a { color: var(--color-accent-300); text-decoration: none; }
a:hover { color: var(--color-accent-200); }
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
/* height:auto matters: the width/height ATTRIBUTES map to a presentational
   height hint that beats a bare aspect-ratio, which on the sibling demo
   cropped the subject out of its own photograph. The slots that do want a
   fixed height say so again below. */
img { max-width: 100%; height: auto; display: block; }
/* [hidden] is a UA declaration; .about below sets display:grid, which is an
   author one and wins. Without this the About view renders under Home. */
[hidden] { display: none !important; }

@keyframes al-rise { from { opacity: 0; transform: translateY(18px); } to { opacity: 1; transform: none; } }
@keyframes al-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes al-wipe { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } }
@keyframes al-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.3; transform: scale(0.7); } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--color-surface); color: var(--color-text);
  padding: 10px 16px; border-radius: var(--radius-md);
}
.skip:focus { left: 8px; top: 8px; }

.noscript {
  margin: 0; padding: 18px clamp(18px, 5vw, 56px);
  background: var(--color-surface); border-bottom: 1px solid var(--color-divider);
  font-size: 15px; line-height: 1.6;
}
.noscript p { margin: 0 0 8px; max-width: 62ch; }
.noscript p:last-child { margin: 0; color: var(--color-neutral-400); }

/* The export's mainStyle, shared with the footer that used to live inside it. */
.wrap {
  max-width: 1280px;
  margin-inline: auto;
  padding-inline: clamp(18px, 5vw, 56px);
}
/* .wrap moved off <main> and onto the views, so the banner and the ribbon
   can run edge to edge. These two carry what main.wrap used to. */
.page { padding-top: clamp(24px, 3.4vw, 48px); }
.home__rest { padding-top: clamp(26px, 3.4vw, 44px); }
.fade { animation: al-fade 0.4s ease both; }

/* ---------------------------------------------------------------- rail ---
   A real site header, not a dashboard rail: sticky, blurred, one row. */
.rail {
  position: sticky; top: 0; z-index: 30;
  display: grid; align-items: center;
  gap: 12px clamp(16px, 2.6vw, 40px);
  grid-template-columns: minmax(0, 1fr);
  padding: 14px clamp(18px, 5vw, 56px);
  background: color-mix(in srgb, var(--color-bg) 92%, transparent);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--color-divider);
}
.brand {
  display: flex; flex-direction: column; gap: 3px;
  background: none; border: 0; padding: 0; cursor: pointer; text-align: left;
  /* The UA font shorthand on a form control sets family AND line-height, and
     neither inherits from body. The export wraps the brand in a <div>, so
     without this the tagline renders in Arial. */
  font-family: var(--font-body);
}
.brand__name {
  font-family: var(--font-heading); font-weight: 500; font-size: 21px;
  letter-spacing: -0.015em; color: var(--color-text);
}
.brand__tag { font-size: 11.5px; line-height: 1.6; letter-spacing: 0.05em; color: var(--color-neutral-400); }

.rail__nav {
  display: flex; gap: clamp(14px, 2vw, 28px); flex-wrap: wrap; align-items: center;
  justify-self: start;
}
.navlink {
  background: none; border: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 15px; letter-spacing: 0.01em;
  text-align: left; padding: 5px 0;
  border-bottom: 1px solid transparent;
  color: var(--color-neutral-300);
  transition: color 0.25s ease, border-color 0.25s ease;
}
.navlink[aria-current="page"] { border-bottom-color: var(--color-accent); color: var(--color-text); }

.rail__toggles { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; justify-self: start; }
.pillgroup {
  display: flex; padding: 2px; gap: 2px;
  border: 1px solid var(--color-neutral-800); border-radius: 999px;
}
.pilltab {
  background: transparent; color: var(--color-neutral-400);
  border: 0; border-radius: 999px; padding: 5px 12px;
  font-size: 12px; font-family: var(--font-body); cursor: pointer;
  transition: background 0.3s ease, color 0.3s ease;
}
/* The icon buttons are square-ish rather than word-width. grid + place-items
   centres the 15px glyph without the line-box padding a text label needed. */
.pilltab--icon { display: grid; place-items: center; padding: 6px 11px; }
.pilltab[aria-pressed="true"] {
  background: color-mix(in srgb, var(--color-accent-800) 80%, transparent);
  color: var(--color-accent-200);
}

.rail__foot { display: none; justify-self: end; align-items: center; gap: 14px; }
.rail__live {
  font-size: 11.5px; line-height: 1.5; color: var(--color-neutral-500);
  display: flex; align-items: center; gap: 8px; text-align: right;
}
.rail__dot {
  width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--color-accent); display: inline-block;
  animation: al-pulse 2.6s ease-in-out infinite;
}
.rail__call { text-decoration: none; padding: 11px 20px; white-space: nowrap; }

/* ------------------------------------------------------------ typography */
.h1 {
  font-family: var(--font-heading); font-weight: 500;
  font-size: clamp(32px, 3.8vw, 54px); line-height: 1.05; letter-spacing: -0.024em;
  margin: 0 0 18px; margin-left: -0.05em;
}
.rise { animation: al-rise 0.8s 0.05s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.rise-1 { animation-delay: 0.15s; }
.rise-2 { animation-delay: 0.25s; }

.h1--page {
  font-size: clamp(30px, 3.8vw, 50px); line-height: 1.06; letter-spacing: -0.022em;
  margin: 12px 0 20px; margin-left: -0.05em;
}
/* Each page's heading has its own measure and trailing space in the export. */
[data-view="services"] .h1--page { font-size: clamp(30px, 4vw, 52px); margin-bottom: 18px; max-width: 16ch; }
[data-view="about"] .h1--page { max-width: 15ch; }
[data-view="faq"] .h1--page { margin-bottom: 26px; max-width: 17ch; }

.h2 { font-family: var(--font-heading); font-weight: 500; letter-spacing: -0.015em; margin: 0; }
.h2--bar { font-size: clamp(21px, 2.2vw, 28px); }
.h2--sec { font-size: clamp(22px, 2.4vw, 30px); }
.h2--mid {
  font-size: clamp(24px, 2.6vw, 34px); line-height: 1.16; letter-spacing: -0.018em;
  margin: 12px 0 14px; max-width: 18ch;
}

/* No display:block. Where the export uses a standalone <span> the line box
   is sized by its parent's 16px strut, not by the 12px label -- 25.6px, not
   19.2px. Blockifying it lost 6px under four headings and left every page
   6px shorter than the canvas. Inside .sec__bar and .compare__head these are
   flex/grid items and get blockified anyway, exactly as in the export. */
.eyebrow {
  font-size: 12px; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--color-neutral-500);
  margin: 0;
}
.eyebrow--accent { color: var(--color-accent); }
.eyebrow--sm { font-size: 11.5px; }

.kicker { display: flex; align-items: center; gap: 12px; margin: 0 0 18px; }
.kicker .rule { width: 44px; height: 1px; background: var(--color-accent); display: block; flex: none; }
.kicker > span:not(.rule) {
  font-size: 12px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-accent);
}

.lede {
  font-size: clamp(15.5px, 1.2vw, 17.5px); line-height: 1.65; max-width: 44ch;
  margin: 0 0 26px; color: var(--color-neutral-200);
}
.lede--page {
  font-size: 16.5px; line-height: 1.7; max-width: 58ch;
  margin: 0 0 clamp(22px, 3vw, 38px);
}
.body { font-size: 15.5px; line-height: 1.7; color: var(--color-neutral-300); margin: 0; max-width: 46ch; }
.fine { font-size: 13.5px; color: var(--color-neutral-400); }
.fine--dim { margin: 0; }
.tnum { font-feature-settings: 'tnum' 1; }

.actions { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
.actions .btn { text-decoration: none; }
.btn-lg { font-size: 16px; padding: 14px 26px; }
.actions--after { margin-top: clamp(22px, 3vw, 36px); gap: 12px; }
.actions--after .btn-primary { padding: 13px 24px; }
.actions--after .fine { font-size: 14px; }


/* -------------------------------------------------------------- sections */
.sec { margin-top: clamp(34px, 5vw, 64px); }
.sec--triage { margin-top: clamp(20px, 3vw, 34px); }
/* Numbered heads, where the solo sample puts a hairline and a tick across
   the top. The number comes from a CSS counter rather than the markup, so
   the sections stay in order on their own and nothing has to be renumbered
   by hand when one moves. */
body { counter-reset: sec; }
.sec { counter-increment: sec; }
.sec__bar {
  position: relative;
  display: flex; flex-wrap: wrap; gap: 10px 18px;
  align-items: baseline; justify-content: space-between;
  padding-left: 42px;
  margin-bottom: 18px;
}
.sec__bar::before {
  content: counter(sec, decimal-leading-zero);
  position: absolute; left: 0; top: 0.35em;
  font-size: 12px; letter-spacing: 0.08em;
  font-variant-numeric: tabular-nums;
  color: var(--color-accent);
}
.sec--triage .sec__bar { margin-bottom: 16px; }
.sec__bar .btn-ghost { cursor: pointer; }

/* -------------------------------------------------------------- triage --- */
.pills { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 18px; }
.pill {
  cursor: pointer; font-family: var(--font-body); font-size: 14px;
  padding: 9px 16px; border-radius: 999px;
  border: 1px solid var(--color-neutral-800);
  background: transparent; color: var(--color-neutral-300);
  transition: all 0.3s ease;
}
.pill[aria-pressed="true"] {
  border-color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent-900) 70%, transparent);
  color: var(--color-text);
}
.triage {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: clamp(16px, 2.5vw, 32px);
  padding: clamp(20px, 3vw, 32px);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-surface) 66%, transparent);
  box-shadow: var(--shadow-sm);
}
.triage .eyebrow--accent { margin-bottom: 8px; }
.triage__cause {
  margin: 0 0 14px;
  font-family: var(--font-heading); font-weight: 500;
  font-size: clamp(19px, 2vw, 24px); line-height: 1.3; letter-spacing: -0.012em;
}
.triage__detail { margin: 0; font-size: 15px; line-height: 1.7; color: var(--color-neutral-300); max-width: 52ch; }
.triage__side { display: grid; gap: 14px; align-content: start; }
.triage__side .eyebrow { margin-bottom: 4px; }
.triage__v { margin: 0; font-size: 15px; color: var(--color-text); }
.triage__cta { text-decoration: none; text-align: center; }

/* ------------------------------------------------------------- compare --- */
.split { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(20px, 3vw, 56px); align-items: start; }
.compare { display: grid; gap: 0; }
.compare__head {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 6px clamp(16px, 3vw, 40px);
  padding-bottom: 12px; border-bottom: 1px solid var(--color-neutral-800);
}
.compare__row {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 4px clamp(16px, 3vw, 40px);
  padding: 14px 0; border-bottom: 1px solid var(--color-divider);
  font-size: 15px; line-height: 1.55;
}
.compare__a { color: var(--color-text); }
.compare__b { color: var(--color-neutral-400); }

/* ------------------------------------------------------------ services --- */
.svcgrid {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 1px; background: var(--color-divider);
  border-radius: var(--radius-md); overflow: hidden;
}
.svc {
  background: var(--color-bg); padding: 20px;
  display: grid; gap: 6px;
  transition: background 0.3s ease;
}
.svc:hover { background: color-mix(in srgb, var(--color-accent-900) 40%, transparent); }
.svc__title { margin: 0; font-family: var(--font-heading); font-weight: 500; font-size: 17.5px; letter-spacing: -0.01em; }
.svc__body { margin: 0; font-size: 14.5px; line-height: 1.6; color: var(--color-neutral-300); }
.svc__meta { margin: 4px 0 0; font-size: 12px; letter-spacing: 0.04em; color: var(--color-accent); }

/* the services page's own rows */
.svcrows { display: grid; gap: 0; }
.svcrow {
  display: grid; grid-template-columns: minmax(0, 1fr);
  gap: 6px clamp(18px, 3vw, 48px);
  padding: 20px 0; border-top: 1px solid var(--color-neutral-800);
  align-items: baseline;
}
.svcrow__title { margin: 0; font-family: var(--font-heading); font-weight: 500; font-size: 19px; letter-spacing: -0.012em; }
.svcrow__body { margin: 0; font-size: 15px; line-height: 1.65; color: var(--color-neutral-300); max-width: 58ch; }
.svcrow__meta { margin: 0; font-size: 12.5px; color: var(--color-accent); letter-spacing: 0.03em; }

/* --------------------------------------------------------------- price --- */
.prices { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(14px, 2vw, 22px); }
.price {
  padding: clamp(20px, 3vw, 30px); border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-surface) 66%, transparent);
  box-shadow: var(--shadow-sm);
}
.price--lit {
  background:
    radial-gradient(600px 260px at 85% -30%, color-mix(in srgb, var(--color-section-glow) 72%, transparent), transparent 64%),
    var(--color-section);
  box-shadow: var(--shadow-md);
}
.price .eyebrow { margin-bottom: 10px; }
.eyebrow--lit { color: color-mix(in srgb, var(--color-neutral-100) 72%, transparent); }
.price__fig {
  margin: 0; font-family: var(--font-heading); font-weight: 500;
  font-size: clamp(34px, 3.6vw, 46px); line-height: 1; letter-spacing: -0.025em;
}
.price__fig--lit { color: var(--color-neutral-100); }
.price__per { font-size: 16px; letter-spacing: 0; }
.price__note { margin: 12px 0 0; font-size: 14.5px; line-height: 1.6; color: var(--color-neutral-300); }
.price__note--lit { color: color-mix(in srgb, var(--color-neutral-100) 88%, transparent); }

/* ---------------------------------------------------------------- work --- */
.work { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(14px, 2vw, 24px); align-items: start; }
.work__main { margin: 0; }
.work__frame { border-radius: var(--radius-lg); overflow: hidden; box-shadow: var(--shadow-sm); }
.work__frame img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.work__cap { font-size: 13px; color: var(--color-neutral-400); padding: 10px 2px 0; }
.thumbs { display: grid; gap: clamp(12px, 1.6vw, 18px); }
.thumb {
  margin: 0; display: grid; grid-template-columns: 96px minmax(0, 1fr);
  gap: 14px; align-items: center;
  transition: transform 0.35s ease;
}
.thumb:hover { transform: translateX(4px); }
.thumb__frame { border-radius: var(--radius-md); overflow: hidden; }
.thumb__frame img { width: 96px; height: 72px; object-fit: cover; }
.thumb__cap { font-size: 13.5px; line-height: 1.5; color: var(--color-neutral-300); }

/* ----------------------------------------------------- review + coverage */
.review {
  margin: 0; padding: clamp(20px, 3vw, 32px); border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--color-surface) 62%, transparent);
  box-shadow: var(--shadow-sm);
}
.review__quote {
  margin: 0 0 16px; font-family: var(--font-heading); font-weight: 500;
  font-size: clamp(19px, 2.1vw, 26px); line-height: 1.45; letter-spacing: -0.012em;
}
.review__who { font-size: 13px; color: var(--color-neutral-400); }
.stars { color: var(--color-accent); letter-spacing: 0.08em; }
.areas { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; }
.coverage .eyebrow--sm { margin-bottom: 6px; }
.hours { margin: 0 0 4px; font-size: 15px; color: var(--color-text); }

/* ------------------------------------------------------------ keepring --- */
.keepring {
  position: relative; overflow: hidden;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  padding: clamp(24px, 3.5vw, 44px);
  background:
    radial-gradient(700px 300px at 92% 0%, color-mix(in srgb, var(--color-accent-900) 85%, transparent), transparent 62%),
    var(--color-surface);
}
.keepring__wipe {
  position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(to right, transparent, var(--color-accent), transparent);
  animation: al-wipe 1.2s ease-out both;
}
.keepring__grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(20px, 3vw, 48px); align-items: center; }
.keepring__h {
  font-size: clamp(21px, 2.4vw, 30px); line-height: 1.22;
  margin: 12px 0 12px; max-width: 22ch;
}
.keepring__steps { display: grid; gap: 10px; }
.krstep {
  display: grid; grid-template-columns: 24px 1fr; gap: 12px; align-items: start;
  padding: 12px 14px; border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-bg) 55%, transparent);
}
.krstep__n { font-family: var(--font-heading); font-size: 13px; color: var(--color-accent); font-feature-settings: 'tnum' 1; }
.krstep__t { font-size: 14.5px; line-height: 1.55; color: var(--color-neutral-200); }

/* --------------------------------------------------------------- about --- */
.about { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(22px, 3.5vw, 64px); align-items: start; }
.about .body { font-size: 16px; line-height: 1.75; max-width: 56ch; margin: 0 0 16px; }
/* after .about .body: same specificity, so the first paragraph's 16.5px only
   survives if it is declared later. */
.about .body--lead { font-size: 16.5px; color: var(--color-neutral-200); }
.about .body--last { margin-bottom: 24px; }
.creds { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 16px; }
.cred__k { margin: 0; font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-neutral-500); }
.cred__v { margin: 5px 0 0; font-size: 15px; color: var(--color-text); }
.about__photo { margin: 0; border-radius: var(--radius-lg); overflow: hidden; }
.about__photo img { width: 100%; aspect-ratio: 4 / 4.4; object-fit: cover; }

/* ----------------------------------------------------------------- faq --- */
/* The cap is on the children, not the view. .faq used to be a 980px block
   sitting at the left of the 1280px measure <main> supplied; now that the view
   carries .wrap itself, a max-width here would meet .wrap's margin-inline:auto
   and centre the whole column instead of leaving it where it was. */
.faq > * { max-width: 980px; }
.faq__list { display: grid; gap: 0; }
.faq__item { border-top: 1px solid var(--color-neutral-800); }
.faq__h { margin: 0; font-size: inherit; font-weight: inherit; }
.faq__q {
  display: flex; width: 100%; gap: 16px;
  align-items: baseline; justify-content: space-between; text-align: left;
  background: none; border: 0; padding: 18px 0; cursor: pointer;
  font-family: var(--font-heading); font-weight: 500;
  font-size: clamp(16.5px, 1.7vw, 19px); letter-spacing: -0.01em;
  color: var(--color-text);
  transition: color 0.25s ease;
}
.faq__q[aria-expanded="true"] { color: var(--color-accent-200); }
.faq__icon {
  font-size: 20px; color: var(--color-accent); line-height: 1;
  transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.faq__q[aria-expanded="true"] .faq__icon { transform: rotate(45deg); }
.faq__a {
  display: grid; grid-template-rows: 0fr; opacity: 0; overflow: hidden;
  transition: grid-template-rows 0.4s cubic-bezier(0.2, 0.7, 0.3, 1), opacity 0.3s ease;
}
.faq__a[data-open] { grid-template-rows: 1fr; opacity: 1; }
.faq__a > div { min-height: 0; overflow: hidden; }
.faq__a p {
  margin: 0; padding: 0 0 20px;
  font-size: 15.5px; line-height: 1.7; color: var(--color-neutral-300); max-width: 68ch;
}
.faq .actions--after { margin-top: 28px; }

/* -------------------------------------------------------------- footer --- */
.sitefoot {
  margin-top: clamp(36px, 5vw, 72px);
  padding-top: clamp(20px, 3vw, 32px);
  padding-bottom: 96px;
  border-top: 1px solid var(--color-divider);
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 22px 36px;
  font-size: 13.5px; color: var(--color-neutral-400);
}
.sitefoot p { margin: 0; line-height: 1.65; }
.sitefoot__name { margin: 0 0 6px !important; font-family: var(--font-heading); font-size: 15.5px; color: var(--color-text); }
.sitefoot__k {
  margin: 0 0 6px !important;
  font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-neutral-500);
}
.sitefoot__links { display: grid; gap: 5px; justify-items: start; }
.footlink {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 13.5px; color: var(--color-neutral-300);
}
.footlink:hover { color: var(--color-accent-200); }

/* ----------------------------------------------------------- mobile bar --- */
.mobilebar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--color-bg) 92%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--color-divider);
}
.mobilebar .btn { text-decoration: none; padding: 14px; font-size: 16px; margin-top: 0; }

/* ==========================================================================
   The export's `wide` branch: window.innerWidth >= 760.
   ========================================================================== */
@media (min-width: 760px) {
  .rail { grid-template-columns: minmax(0, 1fr) auto; }
  .rail__nav { justify-self: end; }
  .rail__foot { display: flex; }
  .mobilebar { display: none; }
  .sitefoot { padding-bottom: 72px; }

  .cohero__inner { grid-template-columns: minmax(0, 1.15fr) minmax(0, 340px); }

  .triage { grid-template-columns: minmax(0, 1.6fr) minmax(0, 220px); }
  .split, .keepring__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr); }
  .about { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); }
  .compare__head, .compare__row { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .svcgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .svcrow { grid-template-columns: minmax(0, 240px) minmax(0, 1fr) minmax(0, 150px); }
  .work { grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); }
}

@media (min-width: 900px) {
  .prices { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 1180px) {
  .svcgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* The four-column rail: brand, nav, toggles, phone. */
@media (min-width: 1220px) {
  .rail { grid-template-columns: auto minmax(0, 1fr) auto auto; }
  .rail__nav { justify-self: start; }
}

/* Visually hidden, still announced. The mode buttons carry no text on screen
   and an icon-only button without an accessible name is read out as, simply,
   "button". aria-hidden on the SVG keeps the graphic out of the name so what
   is announced is the span and nothing else. */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}
.modeicon { width: 15px; height: 15px; display: block; }
