/* Marek Electric demo — the page's own styles.
 *
 * Ported from the design export "Marek Electric.dc.html" (project c6e486c5).
 * 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 15.5px and 17.5px sizes, the 4/3.3 hero ratio. If a number here
 * disagrees with the canvas, this file is wrong.
 *
 * Two deliberate departures, both noted where they appear: the mobile call
 * bar is a media query rather than a resize listener, and the four views are
 * real sections toggled with [hidden] rather than re-rendered subtrees.
 *
 * Nocturne's own tokens and component classes (.btn, .tag, .lighten, the
 * palette) come from nocturne.css and are not restated.
 */

/* ------------------------------------------------------- the departure ---
   nocturne.css is byte-identical to the copy the HVAC demo uses, and until
   now so was everything derived from it: same #9184d9 accent, same 8/16/28
   radii, same twelve component classes. Two samples that are meant to show a
   shop what ITS site could look like should not be the same site. So this
   one is copper on warm ground with tight corners, and the HVAC one keeps
   the violet on cool ground with soft ones.

   These override nocturne.css rather than editing it -- that file stays the
   export's, unmodified, and every departure from it lives in here where it
   can be read in one place. Night values only: daylight is written onto the
   root element as inline custom properties by page.js, which outranks any
   :root rule, so the day ramp lives in the DAY map beside it.

   Every one of these was measured against the page after the fact, in both
   themes. See the contrast table in the commit. */
:root {
  --color-accent: #e09a3d;
  --color-accent-100: #fff6e8;
  --color-accent-200: #fdecd4;
  --color-accent-300: #f8d7a4;
  --color-accent-800: #5a3a10;
  --color-accent-900: #3a2710;
  --color-accent-2-300: #f0cda6;

  /* Tight, not soft. The HVAC demo keeps 8/16/28; page.js writes these onto
     the root for both themes, so the values here are the fallback and the
     ones in CURVE are what actually land. They are kept in step by hand --
     if you change one, change the other. */
  --radius-sm: 2px;
  --radius-md: 4px;
  --radius-lg: 6px;
}

/* ---------------------------------------------------------------- base ---
   The page ground, off the export's root wrapper div. */
body {
  margin: 0;
  background:
    radial-gradient(1100px 680px at 86% -180px, color-mix(in srgb, var(--color-accent-900) 78%, transparent), transparent 60%),
    radial-gradient(1000px 760px at -8% 100%, color-mix(in srgb, black 32%, transparent), transparent 55%),
    var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  min-height: 100vh;
  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, and the
   normalisation filter with it. */
body[data-theme="day"] .lighten { mix-blend-mode: normal; }
body[data-theme="day"] .lighten img { filter: none; }
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, which beats a bare `aspect-ratio` here: without this the
   hero rendered 574x1125 instead of 574x474, a 0.51:1 slot that cropped
   the electrician out of his own photograph. */
img { max-width: 100%; height: auto; }

@keyframes nq-rise { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
@keyframes nq-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes nq-line { from { width: 0; opacity: 0; } to { width: 44px; opacity: 1; } }
@keyframes nq-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.35; transform: scale(0.72); } }
@keyframes nq-sweep { from { transform: translateX(-120%); } to { transform: translateX(320%); } }

.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, 64px);
  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); }

/* Shared frame. The export repeats max-width:1340px and the same horizontal
   clamp on nearly every section; these are that, once. */
.wrap { max-width: 1340px; margin-inline: auto; }
.pad { padding-inline: clamp(18px, 5vw, 64px); }

/* ------------------------------------------------------------- top bar --- */
.topbar {
  display: flex; flex-wrap: wrap; gap: 8px 20px;
  align-items: center; justify-content: space-between;
  padding: 9px clamp(18px, 5vw, 64px);
  font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--color-neutral-400);
  border-bottom: 1px solid var(--color-divider);
}
.topbar__live { display: flex; align-items: center; gap: 9px; }
.topbar__dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--color-accent); display: inline-block;
  animation: nq-pulse 2.6s ease-in-out infinite;
}

/* ------------------------------------------------------------ masthead --- */
.masthead {
  display: flex; flex-wrap: wrap; gap: 12px 24px;
  align-items: center; justify-content: space-between;
  padding: 14px clamp(18px, 5vw, 64px);
  position: sticky; top: 0; z-index: 30;
  background: color-mix(in srgb, var(--color-bg) 86%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--color-divider);
}
.brand {
  display: flex; flex-direction: column; gap: 1px;
  background: none; border: 0; padding: 0; cursor: pointer;
  text-align: left; font-family: var(--font-body);
}
.brand__name {
  font-family: var(--font-heading); font-weight: 500; font-size: 19px;
  letter-spacing: -0.012em; color: var(--color-text);
}
.brand__tag { font-size: 11.5px; color: var(--color-neutral-400); letter-spacing: 0.05em; }

.mainnav { display: flex; align-items: center; gap: clamp(10px, 1.8vw, 22px); flex-wrap: wrap; }
.navlink {
  background: none; border: 0; padding: 4px 0; cursor: pointer;
  font-family: var(--font-body); font-size: 14.5px; letter-spacing: 0.01em;
  transition: color 0.25s ease;
  border-bottom: 1px solid transparent;
  color: var(--color-neutral-300);
}
.navlink:hover { color: var(--color-accent-200); }
.navlink[aria-current="page"] { border-bottom-color: var(--color-accent); color: var(--color-text); }

.variant {
  display: flex; padding: 2px; gap: 2px; margin-left: 4px;
  border: 1px solid var(--color-neutral-800); border-radius: 999px;
}
.variant__tab {
  background: transparent; color: var(--color-neutral-400);
  border: 0; border-radius: 999px; padding: 5px 13px;
  font-size: 12.5px; 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. */
.variant__tab--icon { display: grid; place-items: center; padding: 6px 12px; }
.variant__tab[aria-pressed="true"] {
  background: color-mix(in srgb, var(--color-accent-800) 80%, transparent);
  color: var(--color-accent-200);
}
.masthead__call { text-decoration: none; white-space: nowrap; }

/* --------------------------------------------------------------- views ---
   The export swaps subtrees in and out of the DOM. These are four real
   sections and [hidden] picks one, which keeps the markup readable, keeps
   every page's copy in the document, and costs nothing at this size. */
.view[hidden] { display: none; }
.view { animation: nq-fade 0.4s ease both; }

/* ------------------------------------------------------ shared type ------ */
/* The type goes on the PARENT, not on a child span. Seven of the eight
   kickers write their label as a bare text node --
   <p class="kicker"><span class="rule"></span>01 What I fix</p> -- so a
   `.kicker > span:last-child` rule selects the 44px rule, which has its own
   width/height/background and shows nothing, while the label falls through to
   16px sentence-case body white. Every section on the page then opens with the
   wrong thing. The rule span is immune to inherited text properties, so the
   parent is the right place for them. */
.kicker {
  display: flex; align-items: center; gap: 12px; margin: 0 0 16px;
  font-size: 12px; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--color-accent);
}
/* The three subpage kickers sit 18px off their heading, not 16px. */
.view[data-view="services"] .kicker,
.view[data-view="about"] .kicker,
.view[data-view="faq"] .kicker { margin-bottom: 18px; }
.rule { width: 44px; height: 1px; background: var(--color-accent); display: block; flex: none; }
.rule--grow { animation: nq-line 0.7s 0.1s ease-out both; }

.eyebrow {
  font-size: 12px; letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--color-neutral-500);
}
.eyebrow--accent { color: var(--color-accent); }

.h1 {
  font-family: var(--font-heading); font-weight: 500;
  font-size: clamp(36px, 5.4vw, 74px); line-height: 1.04; letter-spacing: -0.022em;
  margin: 0 0 22px; margin-left: -0.05em;
}
.h1--page { font-size: clamp(32px, 4.4vw, 58px); line-height: 1.06; letter-spacing: -0.02em; margin-bottom: 20px; max-width: 16ch; }
[data-view="about"] .h1--page { font-size: clamp(32px, 4.2vw, 56px); margin-bottom: 22px; max-width: 15ch; }
[data-view="faq"]   .h1--page { font-size: clamp(32px, 4.2vw, 56px); margin-bottom: 30px; }

.h2 { font-family: var(--font-heading); font-weight: 500; margin: 0; }
.h2--wide { font-size: clamp(26px, 3.1vw, 40px); line-height: 1.14; letter-spacing: -0.016em; margin-bottom: 10px; max-width: 19ch; }
.h2--mid  { font-size: clamp(24px, 2.7vw, 34px); line-height: 1.18; letter-spacing: -0.016em; margin-bottom: 18px; max-width: 21ch; }
.h2--sm   { font-size: clamp(23px, 2.5vw, 30px); line-height: 1.2;  letter-spacing: -0.015em; margin-bottom: 18px; }
.h2--cta  { font-size: clamp(28px, 3.6vw, 46px); line-height: 1.1;  letter-spacing: -0.02em;  margin-bottom: 12px; max-width: 16ch; }

.lede {
  font-size: clamp(16px, 1.25vw, 18.5px); line-height: 1.6;
  max-width: 46ch; margin: 0 0 26px; color: var(--color-neutral-200);
}
[data-view="services"] .lede { font-size: 17px; line-height: 1.65; max-width: 56ch; margin-bottom: clamp(24px, 4vw, 44px); }

.body { font-size: 15.5px; line-height: 1.65; color: var(--color-neutral-300); max-width: 62ch; margin: 0 0 16px; }
.body--intro { margin-bottom: clamp(16px, 2.5vw, 30px); }
.body--narrow { line-height: 1.7; max-width: 34ch; margin: 14px 0 18px; }
.split .body { line-height: 1.75; max-width: 54ch; }
.split .body:last-of-type { margin-bottom: 0; }

.fine { font-size: 14px; color: var(--color-neutral-400); margin: 0; }
.fine--dim { font-size: 13px; color: var(--color-neutral-500); margin: 12px 0 0; }
.tnum { font-feature-settings: 'tnum' 1; }

.rise   { animation: nq-rise 0.7s 0.06s cubic-bezier(0.2, 0.7, 0.3, 1) both; }
.rise-1 { animation-delay: 0.16s; }
.rise-2 { animation-delay: 0.24s; }

.actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.actions--after { margin-top: clamp(26px, 4vw, 44px); }
.btn-lg { font-size: 16px; padding: 14px 26px; }
.btn-ghost.btn-lg { font-size: 15px; padding: 14px 20px; }
.btn-xl { font-size: 18px; padding: 16px 30px; }
/* nocturne's .btn is sized for a form row (5.6px block padding). The design
   gives these three their own size, and without it they render at 30px tall
   beside ghost buttons the export sizes at 43-45px. */
.price .actions .btn-primary { padding: 12px 22px; color: var(--color-neutral-100); border-color: var(--color-accent-2-300); }
.price .actions .btn-ghost { color: color-mix(in srgb, var(--color-neutral-100) 82%, transparent); }
.actions--after .btn-primary { padding: 13px 24px; }

.divider {
  height: 1px;
  background: linear-gradient(to right, transparent, var(--color-divider) 48px calc(100% - 48px), transparent);
}
.divider--mb { margin-bottom: clamp(26px, 4vw, 46px); }

/* ---------------------------------------------------------------- hero --- */
/* Type first, photograph underneath as a band. It was a two-column grid --
   copy left, a 4:3.3 portrait right -- which is the shape the solo electrical
   sample and the HVAC one both use above the fold. This one leads with the
   sentence and puts the work under it. */
/* The hero was type first with the photograph boxed underneath until
   2026-09-23. It is the photograph now, with the type on it.

   The wash is color-mix on --color-bg, not a fixed ink, and that is the whole
   idea: the page's own ground laid over the frame at varying strength. In
   daylight that is cream and the type stays dark; after dark it is the night
   ground and the type stays light; --color-text, --color-accent and the
   buttons need no on-photo variants at all, because what they sit on is
   almost the same colour they sit on everywhere else. The two HVAC demos
   cannot do this -- their frames are dark in both themes, so their type is
   literal white and their scrims are literal ink.

   The vertical pass ends at a SOLID stop, so the banner has no bottom edge.
   It dissolves into the page rather than closing with a rule the way
   /hvac/alder-co does. */
.hero {
  /* The wrap's left margin: 0 until the viewport passes .wrap's 1340px, then
     half the overflow. Every horizontal stop in the wash hangs off this.
     Anchoring them to the viewport edge instead is what put a dead band
     beside the banner on a wide screen -- and, underneath that, walked the
     copy out of its own wash: 1.17:1 at 2560px on 2026-09-23.

     100vw counts the classic scrollbar and .wrap does not, so this can be
     out by its width. That is about 7px on a 340px ramp, which is nothing. */
  --gx: max(0px, (100vw - 1340px) / 2);
  position: relative; isolation: isolate;
  display: grid; align-items: center;
  min-height: clamp(460px, 70vh, 620px);
}
.hero__media { position: absolute; inset: 0; z-index: -1; overflow: hidden; }
/* 2000x1125 against a box near 2.3:1, so cover scales by width and there is
   no horizontal pan to be had; the percentage below only moves it vertically.
   42% keeps the cap and the junction box in frame and drops some foreground. */
.hero__media img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 42%;
  display: block;
}
/* Two passes, and they compound: 0.16 over 0.93 is 0.94, not 0.93. The
   horizontal stops are in PIXELS because the copy is a fixed 48ch measure --
   its right edge is a different fraction of the viewport at every width, and
   percentage stops would either expose the copy at one end of the range or
   bury the photograph at the other. Past 940px the frame is nearly clear,
   which is where the electrician and the roof are.

   0.93 over the copy and not 0.88, which was the first try. The kicker is
   12px copper and the ghost button is copper text; both are around 5:1 on
   this page's plain cream ground to begin with, so a frame showing through
   at 12% dropped them to 4.15 and 4.35 -- under AA, in daylight only. The
   answer is to hold the copy column nearly solid and spend the difference on
   the right-hand side, where the photograph is now clearer than it was.

   The first horizontal stop is negative on purpose. Below 1340px --gx is 0,
   so the opening ramp sits almost entirely off canvas and the left edge
   stays around 87% -- indistinguishable from the flat plateau it replaced.
   Past 1340px the ramp walks on screen and grows with the margin, so the
   wider the display, the more of the frame runs to the edge. */
.hero__wash {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--color-bg) 62%, transparent) 0%,
      color-mix(in srgb, var(--color-bg) 16%, transparent) 26%,
      color-mix(in srgb, var(--color-bg) 20%, transparent) 58%,
      color-mix(in srgb, var(--color-bg) 62%, transparent) 88%,
      var(--color-bg) 100%),
    linear-gradient(90deg,
      color-mix(in srgb, var(--color-bg) 32%, transparent) calc(var(--gx) - 340px),
      color-mix(in srgb, var(--color-bg) 97%, transparent) var(--gx),
      color-mix(in srgb, var(--color-bg) 96%, transparent) calc(var(--gx) + 580px),
      color-mix(in srgb, var(--color-bg) 48%, transparent) calc(var(--gx) + 760px),
      color-mix(in srgb, var(--color-bg) 6%, transparent) calc(var(--gx) + 960px));
}
.hero__inner { width: 100%; padding-block: clamp(34px, 5vw, 72px); }
.hero__copy { max-width: 48ch; }
.hero .kicker { margin-bottom: 20px; animation: nq-fade 0.6s ease both; }
.herofoot { font-size: 13.5px; color: var(--color-neutral-400); margin: 18px 0 0; animation: nq-fade 0.8s 0.35s ease both; }
/* Narrow: the copy runs the full width, so a left-to-right wipe has nothing
   to wipe to and the 580px plateau simply covers the whole screen -- the
   photograph disappears. The wash turns vertical instead: near-solid behind
   the copy, then it opens up under it, so the frame is still there on a
   phone and the electrician is in it. cover() has ~727px of horizontal pan
   to give at 375px, which is what object-position spends. */
@media (max-width: 759px) {
  .hero { min-height: clamp(520px, 88vh, 760px); }
  /* Panned to the work rather than to the man: at this width the clear band
     is under the copy, and 74% put his cap up in the washed part and his
     back in the open part. This lands the drill, the gloves and the open
     box in the band you can actually see. */
  .hero__media img { object-position: 54% 50%; }
  .hero__wash {
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--color-bg) 97%, transparent) 0%,
      color-mix(in srgb, var(--color-bg) 97%, transparent) 64%,
      color-mix(in srgb, var(--color-bg) 34%, transparent) 84%,
      var(--color-bg) 100%);
  }
  .hero__inner { align-self: start; }
}

/* --------------------------------------------------------- credentials --- */
.creds {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 20px clamp(18px, 3vw, 48px);
  padding-block: clamp(20px, 3vw, 32px);
}
.creds--inline { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 18px; padding: 0; }
.cred__k { margin: 0; font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-neutral-500); }
.cred__v { margin: 6px 0 0; font-size: 15.5px; color: var(--color-text); }

/* ------------------------------------------------------------ sections --- */
.sec { padding-block: clamp(36px, 5.5vw, 76px) clamp(24px, 4vw, 44px); }
.sec--jobs     { padding-block: clamp(18px, 3vw, 36px) clamp(34px, 5vw, 60px); }
.sec--reviews  { padding-block: 0 clamp(34px, 5vw, 60px); }
/* .split is declared below this and would win at equal specificity, giving
   the areas/hours section 76px of top padding the design does not have. */
.sec--areas.split { padding-block: 0 clamp(36px, 5vw, 64px); }
.sec--keepring { padding-block: 0 clamp(40px, 6vw, 72px); }
/* A rule down the left, where the HVAC demo puts a hairline and a tick
   across the top. Same job -- telling you a section has started -- read from
   a different direction. */
.sec__bar {
  display: flex; flex-wrap: wrap; gap: 10px 24px;
  align-items: baseline; justify-content: space-between;
  margin-bottom: clamp(16px, 2.5vw, 28px);
  padding-left: clamp(14px, 1.6vw, 20px);
  border-left: 3px solid var(--color-accent);
}
/* The heading in a .sec__bar sits level with the eyebrow opposite it and runs
   as long as it likes -- it borrows .h2--mid for its size only, not for the
   21ch cap and 18px margin that belong to the standalone heading. */
.sec__bar .h2 { max-width: none; margin-bottom: 0; }
.sec__more { margin: 22px 0 0; }

/* --------------------------------------------------- services, the list --- */
.svc__line { border-top: 1px solid var(--color-neutral-800); }
.svc__row {
  display: grid; grid-template-columns: 44px minmax(0, 280px) minmax(0, 1fr);
  gap: 8px clamp(16px, 3.5vw, 56px); align-items: baseline;
  padding: 20px 8px; border-radius: var(--radius-md);
  transition: background 0.35s ease, padding-left 0.35s ease, color 0.35s ease;
}
.svc__row:hover {
  background: color-mix(in srgb, var(--color-accent-900) 45%, transparent);
  padding-left: 16px;
}
.svc__n { margin: 0; font-family: var(--font-heading); font-size: 13.5px; color: var(--color-accent); font-feature-settings: 'tnum' 1; }
.svc__title { margin: 0; font-family: var(--font-heading); font-weight: 500; font-size: 20px; letter-spacing: -0.01em; }
.svc__body { margin: 0; font-size: 15.5px; line-height: 1.6; color: var(--color-neutral-300); max-width: 56ch; }

/* --------------------------------------------------------------- price --- */
.price {
  background:
    radial-gradient(900px 420px at 85% -40%, color-mix(in srgb, var(--color-section-glow) 70%, transparent), transparent 64%),
    var(--color-section);
  padding: clamp(34px, 5vw, 62px) clamp(18px, 5vw, 64px);
  margin-top: clamp(16px, 3vw, 36px);
}
.price__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: clamp(22px, 4vw, 64px); align-items: start;
}
.price__label { margin: 0 0 12px; font-size: 12px; letter-spacing: 0.09em; text-transform: uppercase; 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(46px, 5.4vw, 68px); line-height: 1; letter-spacing: -0.025em; color: var(--color-neutral-100); }
.price__note { margin: 12px 0 0; font-size: 16px; line-height: 1.55; color: var(--color-neutral-100); max-width: 30ch; }
.price__right { display: grid; gap: 18px; }
.price__body { margin: 0; font-size: 15.5px; line-height: 1.7; color: color-mix(in srgb, var(--color-neutral-100) 88%, transparent); max-width: 46ch; }

/* --------------------------------------------------------------- split --- */
.split {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: clamp(22px, 4vw, 72px); align-items: center;
  padding-block: clamp(36px, 5.5vw, 76px);
}
.split--even { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: clamp(22px, 4vw, 64px); align-items: start; }
.split__photo { margin: 0; }
.split__frame { border-radius: var(--radius-lg); overflow: hidden; }
.split__photo img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block; }
.split__photo figcaption { font-size: 13px; color: var(--color-neutral-400); padding: 10px 2px 0; }

/* ---------------------------------------------------------------- jobs --- */
/* Three across, pinned, and no max-width. It used to be capped at 1000px
   inside a content column that is 1212px at the top of .wrap's range, which
   left the eyebrow stranded over a quarter-column of nothing. auto-fit is no
   good once the cap is gone either: 1212px takes four 280px tracks, and six
   jobs across four columns leaves an orphan row of two. */
.jobs {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(22px, 2.6vw, 38px) clamp(16px, 2.4vw, 28px);
}
@media (max-width: 899px) { .jobs { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 559px) { .jobs { grid-template-columns: minmax(0, 1fr); } }

.job { margin: 0; }
.job__frame {
  border-radius: var(--radius-md); overflow: hidden; box-shadow: var(--shadow-sm);
  /* Without a stacking context of its own the scaled child paints over the
     rounded corner in Safari. */
  transform: translateZ(0);
}
.job img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; display: block;
  transition: transform 0.7s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.job:hover img { transform: scale(1.04); }

/* The caption hangs off a hairline with a copper tick at its left end that
   runs the width of the tile on hover -- the same gesture as .rule--grow in
   the hero and the rule down the left of every .sec__bar, which is how this
   demo says a block has started. The HVAC pair marks its blocks across the
   top instead, so the two do not converge. */
.job__cap {
  position: relative; display: block;
  margin-top: 14px; padding: 13px 2px 0;
  border-top: 1px solid var(--color-divider);
}
.job__cap::before {
  content: ''; position: absolute; top: -1px; left: 0; height: 1px; width: 34px;
  background: var(--color-accent);
  transition: width 0.55s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.job:hover .job__cap::before { width: 100%; }
/* The work in the heading face, the place and month dropped under it. One
   line each at every column width, so the six tiles end level -- the single
   run-on caption wrapped on three of them and left the row ragged. */
.job__t {
  display: block; font-family: var(--font-heading); font-weight: 500;
  font-size: 16px; line-height: 1.3; letter-spacing: -0.008em;
  color: var(--color-text);
}
.job__m {
  display: block; margin-top: 5px;
  font-size: 12.5px; line-height: 1.45; color: var(--color-neutral-400);
  font-feature-settings: 'tnum' 1;
}

/* ------------------------------------------------------------- reviews --- */
.reviews {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(20px, 3vw, 44px); align-items: start;
}
.review {
  margin: 0; padding: 22px; border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-surface) 70%, transparent);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.4s ease, transform 0.4s ease;
}
.review:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); }
.review__quote {
  margin: 0 0 16px; font-family: var(--font-heading); font-weight: 500;
  font-size: 17.5px; line-height: 1.5; letter-spacing: -0.008em; color: var(--color-text);
}
.review__who { font-size: 12.5px; color: var(--color-neutral-400); }
.stars { color: var(--color-accent); letter-spacing: 0.08em; }

/* ------------------------------------------------------- areas & hours --- */
.areas { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 16px; }
.hours { display: grid; gap: 1px; max-width: 420px; }
.hours__row {
  display: flex; justify-content: space-between; gap: 16px; padding: 8px 0;
  border-bottom: 1px solid var(--color-divider);
  font-size: 14.5px; font-feature-settings: 'tnum' 1;
}
.hours__row span:first-child { color: var(--color-neutral-300); }
.hours__row span:last-child { color: var(--color-text); }

/* ------------------------------------------------------------ keepring --- */
.keepring {
  position: relative; overflow: hidden;
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  padding: clamp(26px, 4vw, 52px);
  background:
    radial-gradient(700px 300px at 90% 0%, color-mix(in srgb, var(--color-accent-900) 85%, transparent), transparent 62%),
    var(--color-surface);
}
.keepring__sweep {
  position: absolute; top: 0; left: 0; height: 1px; width: 28%;
  background: linear-gradient(to right, transparent, var(--color-accent), transparent);
  animation: nq-sweep 5s linear infinite;
}
.keepring__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(20px, 3vw, 48px); align-items: center;
}
.keepring__h { margin: 14px 0 12px; max-width: 22ch; font-size: clamp(23px, 2.6vw, 32px); }
.keepring .body { max-width: 48ch; line-height: 1.7; margin: 0; }
.keepring__steps { display: grid; gap: 10px; }
.krstep {
  display: grid; grid-template-columns: 26px 1fr; gap: 14px; align-items: start;
  padding: 12px 14px; border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-bg) 55%, transparent);
  transition: transform 0.35s ease;
}
.krstep:hover { transform: translateX(4px); }
.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); }

/* ------------------------------------------------- services & about ------ */
.view[data-view="services"],
.view[data-view="about"],
.view[data-view="faq"] { padding-block: clamp(32px, 5vw, 72px) clamp(30px, 4vw, 56px); }
.view[data-view="about"] { gap: clamp(24px, 4vw, 72px); align-items: start; }
.view[data-view="faq"] { max-width: 1040px; }

.svccards { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: clamp(14px, 2vw, 22px); }
.svccard {
  padding: 24px; border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--color-surface) 62%, transparent);
  box-shadow: var(--shadow-sm);
  transition: box-shadow 0.4s ease, transform 0.4s ease;
}
.svccard:hover { box-shadow: var(--shadow-md); transform: translateY(-4px); }
.svccard__n { margin: 0 0 12px; font-family: var(--font-heading); font-size: 13px; color: var(--color-accent); font-feature-settings: 'tnum' 1; }
.svccard__title { margin: 0 0 10px; font-family: var(--font-heading); font-weight: 500; font-size: 21px; letter-spacing: -0.012em; }
.svccard__body { margin: 0 0 14px; font-size: 15px; line-height: 1.65; color: var(--color-neutral-300); }
.svccard__meta { margin: 0; font-size: 13px; color: var(--color-neutral-500); letter-spacing: 0.03em; }

.body--lead { font-size: 16.5px; line-height: 1.75; color: var(--color-neutral-200); max-width: 56ch; margin: 0 0 18px; }
[data-view="about"] .body { font-size: 16px; line-height: 1.75; max-width: 56ch; margin: 0 0 18px; }
[data-view="about"] .body--lead { font-size: 16.5px; color: var(--color-neutral-200); }
.body--last { margin-bottom: 26px !important; }
.about__photo { margin: 0; border-radius: var(--radius-lg); overflow: hidden; animation: nq-fade 0.9s 0.1s ease both; }
.about__photo img { width: 100%; aspect-ratio: 4 / 4.2; object-fit: cover; display: block; }

/* ----------------------------------------------------------------- faq --- */
.faq__item { border-top: 1px solid var(--color-neutral-800); }
.faq__h { margin: 0; font: inherit; }
.faq__q {
  display: flex; width: 100%; gap: 16px; align-items: baseline; justify-content: space-between;
  text-align: left; background: none; border: 0; padding: 20px 0; cursor: pointer;
  font-family: var(--font-heading); font-weight: 500;
  font-size: clamp(17px, 1.8vw, 20px); letter-spacing: -0.01em;
  color: var(--color-text); transition: color 0.25s ease;
}
.faq__q[aria-expanded="true"] { color: var(--color-accent-200); }
.faq__qtext { display: flex; gap: 14px; align-items: baseline; }
.faq__n { font-size: 13px; color: var(--color-accent); font-feature-settings: 'tnum' 1; }
.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);
  transform: rotate(0deg);
}
.faq__q[aria-expanded="true"] .faq__icon { transform: rotate(45deg); }
/* 0fr -> 1fr is what animates; the <p> needs min-height:0 or it refuses to
   shrink below its content and the row never closes. */
.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 p {
  min-height: 0; margin: 0; padding: 0 0 20px 34px;
  font-size: 15.5px; line-height: 1.7; color: var(--color-neutral-300); max-width: 68ch;
}

/* ----------------------------------------------------------------- cta --- */
.cta {
  background:
    radial-gradient(800px 380px at 20% 120%, color-mix(in srgb, var(--color-accent-900) 70%, transparent), transparent 62%),
    color-mix(in srgb, var(--color-surface) 55%, transparent);
  border-top: 1px solid var(--color-divider);
  padding: clamp(36px, 5vw, 68px) clamp(18px, 5vw, 64px);
}
.cta__inner { display: flex; flex-wrap: wrap; gap: 24px; align-items: end; justify-content: space-between; }
.cta .fine { font-size: 14.5px; }
[data-view="faq"] .actions--after { margin-top: 32px; }

/* -------------------------------------------------------------- footer --- */
.sitefoot {
  padding: clamp(26px, 3.5vw, 44px) clamp(18px, 5vw, 64px) 40px;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 26px 40px; font-size: 14px; color: var(--color-neutral-400);
  border-top: 1px solid var(--color-divider);
}
.sitefoot p { margin: 0; line-height: 1.65; }
.sitefoot__name { margin: 0 0 8px !important; font-family: var(--font-heading); font-size: 16px; color: var(--color-text); }
.sitefoot__k { margin: 0 0 8px !important; font-size: 11px; letter-spacing: 0.09em; text-transform: uppercase; color: var(--color-neutral-500); }
.sitefoot__links { display: grid; gap: 6px; justify-items: start; }
.footlink {
  background: none; border: 0; padding: 0; cursor: pointer;
  font-family: var(--font-body); font-size: 14px; color: var(--color-neutral-300);
}
.footlink:hover { color: var(--color-accent-200); }

/* ---------------------------------------------------------- mobile bar ---
   The export carried a resize listener and a `narrow` state to set
   display:block under 720px. A media query is the same result with no
   JavaScript, no listener, and no first-paint flash. */
.mobilebar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; display: none;
  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 { padding: 14px; font-size: 16px; text-decoration: none; }
@media (max-width: 719px) {
  .mobilebar { display: block; }
  /* so the bar never sits over the last line of the footer */
  body { padding-bottom: 76px; }
}

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

/* 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; }
