
  :root {
    --background:   #fcfaf4;
    --foreground:   #2c2017;
    --card:         #fffefb;
    --brand:        #db9338;
    --brand-deep:   #a75c00;
    --brand-glow:   #fab549;
    --on-brand:     #26160e;
    --secondary:    #f3e8da;
    --muted:        #f3ece1;
    --muted-fg:     #706052;
    --accent:       #f1dbc8;
    --border:       #e6ded4;
    --scrim:        37, 23, 13;

    /* Tailwind's radius scale, resolved from the reference's --radius: 0.625rem.
       Every step is radius +/- a fixed offset, which is why these are not round
       numbers -- and why guessing them by eye drifts. md is what every form
       control uses; 3xl is the service card; the three big panels are bracket
       values in the source. */
    --r-md:    8px;    /* rounded-md   radius-2  : inputs, textarea */
    --radius:  10px;   /* rounded-lg   radius    */
    --r-xl:    14px;   /* rounded-xl   radius+4  : footer blocks */
    --r-2xl:   18px;   /* rounded-2xl  radius+8  : service icons */
    --r-3xl:   22px;   /* rounded-3xl  radius+12 : service cards */
    --radius-panel: 28px;  /* rounded-[1.75rem]  : the booking panel */
    --pill: 999px;         /* rounded-full       : buttons, chips, dots */
    --header-h: 114px;     /* licence strip (34) + nav row (80) */
    /* ONE spacing for every hero. The homepage used to open 96px below
       the header while the sub-pages opened 40px below it, so the two
       heroes started at visibly different heights. The sub-page value
       won: 96px of empty photograph above the eyebrow pushed the
       headline down for nothing. */
    --hero-gap: 40px;      /* clear space above the hero content */
    --hero-gap-b: 72px;    /* and below it */

    --gradient-brand: linear-gradient(135deg, var(--brand), var(--brand-glow));
    --shadow-elegant: 0 30px 70px -25px rgba(44,32,23,0.32);
    --shadow-panel:   0 30px 70px -30px rgba(44,32,23,0.30);
    --shadow-brand:   0 18px 40px -16px rgba(167,92,0,0.9);
    --shadow-brand-sm:0 14px 30px -12px rgba(219,147,56,0.6);
    }
  * { box-sizing: border-box; border-color: var(--border); }
  html { scroll-behavior: smooth; }
  body {
    margin: 0; background: var(--background); color: var(--foreground);
    font-family: 'Manrope', ui-sans-serif, system-ui, -apple-system, sans-serif;
    font-size: 16px; line-height: 1.65;
    -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  }
  h1, h2, h3, h4 {
    font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
    font-weight: 600; letter-spacing: -0.02em; margin: 0; text-wrap: balance;
  }
  h1 { font-size: clamp(36px, 5.2vw, 60px); line-height: 1.05; letter-spacing: -0.025em; }
  h2 { font-size: clamp(30px, 3.9vw, 48px); line-height: 1.1; }
  h3 { font-size: 18px; line-height: 1.35; }
  p { margin: 0; }
  a { color: inherit; text-decoration: none; }
  ul { margin: 0; padding: 0; list-style: none; }
  img { max-width: 100%; display: block; }
  svg { flex-shrink: 0; }
  .wrap { max-width: 1280px; margin: 0 auto; padding: 0 32px; }

  /* text-gradient-brand, their @utility */
  .nb { white-space: nowrap; }
  /* A link inside running copy. The rest of the site links through headings
     and buttons, so body-copy links need an underline to read as links at
     all. */
  .sec__after { margin-top: 32px; max-width: 54rem; font-size: 15.5px;
                line-height: 1.8; color: var(--muted-fg); }
  .inlink { color: var(--brand-deep); font-weight: 600;
            border-bottom: 1px solid rgba(219,147,56,0.5);
            transition: border-color .18s, color .18s; }
  .inlink:hover { color: var(--foreground); border-bottom-color: var(--foreground); }
  .grad { background-image: var(--gradient-brand); -webkit-background-clip: text;
          background-clip: text; color: transparent; }
  /* The same highlight for a light ground. --gradient-brand runs brand ->
     brand-glow, which is tuned for the espresso hero; on #fcfaf4 that pair
     drops to about 2:1 against the page and the word goes pale. This one runs
     brand-deep -> brand instead, which keeps the copper reading as emphasis.
     A background-clip gradient also leaves `color: transparent` behind if the
     image fails, so the fallback colour is set first. */
  .grad--light { color: var(--brand-deep);
                 background-image: linear-gradient(135deg, var(--brand-deep), var(--brand));
                 -webkit-background-clip: text; background-clip: text;
                 -webkit-text-fill-color: transparent; }

  .eyebrow {
    display: inline-flex; align-items: center; gap: 8px;
    border-radius: var(--pill); padding: 6px 16px;
    font-size: 12px; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase;
    border: 1px solid rgba(252,250,244,0.25); background: rgba(252,250,244,0.1);
    color: rgba(252,250,244,0.9); backdrop-filter: blur(8px);
  }
  .eyebrow::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--brand-glow); }
  .eyebrow--light { border-color: rgba(219,147,56,0.3); background: rgba(219,147,56,0.1);
                    color: var(--brand-deep); backdrop-filter: none; }
  .lede { font-size: 17px; line-height: 1.7; color: var(--muted-fg); }

  /* ---- buttons: rounded-full, h-12 on the big ones ---- */
  .btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
         font-family: 'Sora', sans-serif; font-weight: 600; font-size: 15px;
         height: 48px; padding: 0 28px; border-radius: var(--pill);
         border: 1px solid transparent; cursor: pointer;
         transition: background .2s, color .2s, border-color .2s, box-shadow .2s, opacity .2s; }
  .btn svg { width: 16px; height: 16px; }
  .btn--brand { background: var(--brand); color: var(--on-brand); box-shadow: var(--shadow-brand); }
  .btn--brand:hover { background: var(--brand-deep); color: #fff; }
  .btn--glass { border-color: rgba(252,250,244,0.3); background: rgba(252,250,244,0.05);
                color: var(--background); backdrop-filter: blur(8px); padding: 0 24px; }
  .btn--glass:hover { background: rgba(252,250,244,0.15); }
  .btn--ink { background: var(--foreground); color: var(--background); height: 40px; padding: 0 20px; font-size: 14.5px; }
  .btn--ink:hover { opacity: 0.9; }
  .btn--outline { border-color: rgba(44,32,23,0.28); color: var(--foreground); }
  .btn--outline:hover { border-color: var(--foreground); }

  /* The licence/rating strip sits above the nav inside the fixed header and
     collapses once the page scrolls, so the sticky bar settles back to the
     reference's 80px rather than permanently eating 114px of viewport. */
  .strip { height: 34px; overflow: hidden; display: flex; align-items: center;
           border-bottom: 1px solid rgba(252,250,244,0.14);
           transition: height .4s, opacity .4s, border-color .4s; }
  .strip__in { display: flex; justify-content: space-between; align-items: center; gap: 16px;
               width: 100%; max-width: 1280px; margin: 0 auto; padding: 0 32px;
               font-size: 12.5px; color: rgba(252,250,244,0.72); }
  .strip__in b { color: var(--brand-glow); font-weight: 600; }
  .strip__in div { display: inline-flex; align-items: center; gap: 7px; }
  .strip__hours { display: none !important; }
  .strip__in svg { width: 13px; height: 13px; color: var(--brand-glow); fill: var(--brand-glow); }
  header.stuck .strip { height: 0; opacity: 0; border-color: transparent; }
  header.stuck { height: 80px; }
  header { height: 114px; }

  /* ---- header: h-20, transparent -> blurred ivory at 24px of scroll ---- */
  header { position: fixed; inset-inline: 0; top: 0; z-index: 50;
           border-bottom: 1px solid transparent; transition: all .5s; }
  header.stuck { background: rgba(252,250,244,0.8); backdrop-filter: blur(24px);
                 border-bottom-color: rgba(230,222,212,0.6); }
  .hdr { display: flex; align-items: center; justify-content: space-between; gap: 24px;
         height: 80px; max-width: 1280px; margin: 0 auto; padding: 0 32px; }
  /* Wordmark, no badge. The hairline divider separates the name from what the
     business does, so "MKH" reads as a name rather than the first word of a
     phrase. Defaults are the light-on-dark values -- that is what the footer
     and the un-scrolled header both need -- and header.stuck inverts them. */
  .logo { display: inline-flex; align-items: center; gap: 9px; }
  /* A touch more air after the mark than between the two words, so the
     lockup reads as [mark] [MKH | Appliance Repair] and not as three
     evenly spaced things. */
  .logo__mark { flex: none; margin-right: 3px; color: var(--background);
                transition: color .5s; }
  .logo__mk { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 21px;
              letter-spacing: -0.04em; line-height: 1; color: var(--background);
              transition: color .5s; }
  .logo__pipe { width: 1px; height: 20px; flex-shrink: 0;
                background: rgba(252,250,244,0.25); transition: background .5s; }
  .logo__sv { font-family: 'Sora', sans-serif; font-weight: 400; font-size: 18px;
              letter-spacing: -0.02em; line-height: 1; color: var(--brand); }
  header.stuck .logo__mk { color: var(--foreground); }
  header.stuck .logo__mark { color: var(--foreground); }
  header.stuck .logo__pipe { background: var(--border); }
  .nav { display: flex; align-items: center; gap: 28px; }
  .navlink { position: relative; display: inline-flex; align-items: center; gap: 5px; font-size: 14px;
             font-weight: 500; color: rgba(252,250,244,0.75); transition: color .5s; }
  .navlink:hover { color: var(--background); }
  header.stuck .navlink { color: rgba(44,32,23,0.7); }
  header.stuck .navlink:hover { color: var(--foreground); }

  /* ---- dropdowns ----
     Each row is an icon chip plus a label, the open trigger carries a copper
     underline, and the panel hangs flush off the bottom of the 80px header
     row. That last part is what makes it feel attached: .nav__item is given
     the full row height, so top:100% lands the panel exactly on the header's
     lower edge and there is no gap for the pointer to fall through. */
  .nav__item { position: relative; display: flex; align-items: center; height: 80px; }
  .nav__item > .navlink::after { content: ""; position: absolute; left: 0; right: 0;
    bottom: 0; height: 2px; background: var(--brand); border-radius: 2px 2px 0 0;
    transform: scaleX(0); transition: transform .2s; }
  .nav__item:hover > .navlink::after,
  .nav__item:focus-within > .navlink::after { transform: scaleX(1); }
  .nav__caret { width: 11px; height: 11px; stroke: currentColor; fill: none;
                stroke-width: 2.3; stroke-linecap: round; stroke-linejoin: round;
                transition: transform .2s; }
  .nav__item:hover .nav__caret, .nav__item:focus-within .nav__caret { transform: rotate(180deg); }

  .nav__menu { position: absolute; top: 100%; left: -16px; z-index: 60;
               margin: 0; padding: 16px; list-style: none;
               background: var(--card); border: 1px solid var(--border);
               border-radius: var(--r-2xl);
               box-shadow: 0 24px 60px -14px rgba(44,32,23,0.26);
               display: grid; gap: 2px 10px;
               opacity: 0; visibility: hidden; transform: translateY(6px);
               pointer-events: none; transition: opacity .15s, transform .15s; }
  .nav__item:hover .nav__menu, .nav__item:focus-within .nav__menu {
    opacity: 1; visibility: visible; transform: translateY(0); pointer-events: auto; }
  .nav__menu a { display: flex; align-items: center; gap: 11px;
                 padding: 9px 12px; border-radius: var(--r-md);
                 font-size: 13.5px; font-weight: 500; color: var(--foreground);
                 white-space: nowrap; transition: background .15s, color .15s; }
  .nav__menu a:hover { background: var(--muted); color: var(--brand-deep); }
  /* The icon chip. Copper tint at rest, solid copper on hover -- the same
     treatment the service cards use, so the menu and the grid below it read
     as one system. */
  .nav__ic { width: 30px; height: 30px; flex: none; border-radius: 9px;
             display: flex; align-items: center; justify-content: center;
             background: rgba(219,147,56,0.1); color: var(--brand);
             transition: background .15s, color .15s; }
  .nav__ic svg { width: 16px; height: 16px; }
  .nav__menu a:hover .nav__ic { background: var(--brand); color: var(--on-brand); }
  /* Rows without a chip keep the same rhythm: the chip was 30px plus an 11px
     gap, so a plain row gets a matching left inset and a copper bullet in its
     place rather than collapsing against the panel edge. */
  .nav__row--plain { position: relative; padding-left: 26px !important; }
  .nav__row--plain::before { content: ""; position: absolute; left: 12px; top: 50%;
    width: 5px; height: 5px; margin-top: -2.5px; border-radius: 50%;
    background: rgba(219,147,56,0.45); transition: background .15s; }
  .nav__row--plain:hover::before { background: var(--brand); }
  /* Column headings inside the brands panel. */
  .nav__ghead { padding: 4px 12px 10px; font-size: 11px; font-weight: 600;
                letter-spacing: 0.12em; text-transform: uppercase;
                color: var(--muted-fg); }
  .nav__menu--3 { grid-template-columns: repeat(3, 1fr); }
  .nav__menu--2 { grid-template-columns: repeat(2, 1fr); }
  .nav__all { grid-column: 1 / -1; margin-top: 6px; padding-top: 12px !important;
              border-top: 1px solid var(--border);
              color: var(--brand-deep) !important; font-weight: 600 !important;
              border-radius: 0 !important; }
  .nav__all:hover { background: transparent !important; }

  .hdr__right { display: flex; align-items: center; gap: 16px; }
  /* The 24/7 line. The dot is the whole signal, so it gets the animation and
     the text stays still. */
  .hdr__live { display: flex; flex-direction: column; gap: 1px; text-align: right;
               font-size: 12px; line-height: 1.35; }
  .hdr__live b { display: inline-flex; align-items: center; justify-content: flex-end;
                 gap: 6px; font-weight: 600; color: rgba(252,250,244,0.92);
                 transition: color .5s; }
  .hdr__live span { color: rgba(252,250,244,0.6); transition: color .5s; }
  header.stuck .hdr__live b { color: var(--foreground); }
  header.stuck .hdr__live span { color: var(--muted-fg); }
  .hdr__dot { width: 7px; height: 7px; border-radius: 50%; background: #35c26a;
              box-shadow: 0 0 0 0 rgba(53,194,106,0.65); animation: live 2.4s infinite; }
  @keyframes live {
    70%  { box-shadow: 0 0 0 7px rgba(53,194,106,0); }
    100% { box-shadow: 0 0 0 0 rgba(53,194,106,0); }
  }
  .hdr__tel { display: inline-flex; align-items: center; gap: 8px; font-size: 14px;
              font-weight: 500; color: rgba(252,250,244,0.85); transition: color .5s; }
  .hdr__tel svg { width: 16px; height: 16px; color: var(--brand); }
  header.stuck .hdr__tel { color: rgba(44,32,23,0.8); }

  /* ---- burger + mobile drawer ----
     Hidden above 1023px. Below it the hover dropdowns are useless (there is no
     hover on a touch screen) and the nav was simply display:none, which left
     the phone the only way to reach anything. */
  .burger { display: none; width: 40px; height: 40px; flex: none; padding: 0;
            background: none; border: 0; cursor: pointer;
            flex-direction: column; justify-content: center; align-items: center; gap: 5px; }
  .burger span { display: block; width: 22px; height: 2px; border-radius: 2px;
                 background: var(--background); transition: transform .25s, opacity .2s, background .5s; }
  header.stuck .burger span { background: var(--foreground); }

  /* ---- the header while the mobile drawer is open ----
     THE BUG THIS FIXES: the header's defaults are light-on-dark, because
     un-scrolled it sits over the hero photograph. Only `header.stuck`
     inverted them, and opening the drawer at the top of the page does not
     make the header stuck. So the drawer painted cream across the viewport
     and the white wordmark, the white burger and the white strip text all
     went invisible against it -- the menu opened with no visible logo and,
     worse, no visible close button.
     These are COLOUR rules only. Deliberately not `header.stuck`'s height
     rules: collapsing the strip would change --header-h out from under the
     drawer's top padding and slide the menu under the header. */
  header.menu-open .logo__mk { color: var(--foreground); }
  header.menu-open .logo__mark { color: var(--foreground); }
  header.menu-open .logo__pipe { background: var(--border); }
  header.menu-open .burger span { background: var(--foreground); }
  header.menu-open .strip { border-bottom-color: var(--border); }
  header.menu-open .strip__in { color: var(--muted-fg); }
  header.menu-open .navlink { color: rgba(44,32,23,0.7); }
  header.menu-open .hdr__tel { color: rgba(44,32,23,0.8); }
  header.menu-open .hdr__live b { color: var(--foreground); }
  header.menu-open .hdr__live span { color: var(--muted-fg); }
  .burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  .drawer { display: none; position: fixed; inset: 0; z-index: 49;
            background: var(--background); overflow-y: auto;
            padding: calc(var(--header-h) + 16px) 20px 40px; }
  .drawer.open { display: block; }
  .drawer details { border-bottom: 1px solid var(--border); }
  .drawer summary { list-style: none; cursor: pointer; padding: 16px 2px;
                    display: flex; align-items: center; justify-content: space-between;
                    font-family: 'Sora', sans-serif; font-size: 17px; font-weight: 600;
                    color: var(--foreground); }
  .drawer summary::-webkit-details-marker { display: none; }
  .drawer summary::after { content: "+"; font-size: 22px; font-weight: 400;
                           color: var(--brand); line-height: 1; transition: transform .2s; }
  .drawer details[open] summary::after { transform: rotate(45deg); }
  .drawer__list { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 10px;
                  padding: 0 0 14px; list-style: none; margin: 0; }
  .drawer__list a { display: block; padding: 9px 2px; font-size: 14px;
                    color: var(--muted-fg); }
  .drawer__list a:hover { color: var(--brand-deep); }
  .drawer > a { display: block; padding: 16px 2px; border-bottom: 1px solid var(--border);
                font-family: 'Sora', sans-serif; font-size: 17px; font-weight: 600;
                color: var(--foreground); }
  .drawer__cta { display: grid; gap: 10px; margin-top: 24px; }
  .drawer__cta .btn { width: 100%; }
  body.locked { overflow: hidden; }

  /* ---- sticky call bar (mobile only) ----
     Hidden by default and shown under 1023px. It sits above the iOS home
     indicator via env(safe-area-inset-bottom), and body gets matching bottom
     padding so it never covers the last line of the footer. It hides while
     the drawer is open, where it would sit on top of the menu's own buttons. */
  .callbar { display: none; position: fixed; left: 0; right: 0; bottom: 0; z-index: 48;
             padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
             background: rgba(252,250,244,0.9);
             -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
             border-top: 1px solid rgba(230,222,212,0.8); }
  .callbar .btn { width: 100%; height: 52px; font-size: 16px; }
  body.locked .callbar { display: none !important; }

  /* ---- hero ---- */
  .hero { position: relative; overflow: hidden; background: var(--foreground); }
  .hero__bg { position: absolute; inset: 0; }
  .hero__bg img { width: 100%; height: 100%; object-fit: cover; }
  .hero__bg::after { content: ""; position: absolute; inset: 0;
    /* The reference's 110deg wash, plus a second pass up from the floor. Their
       hero is short enough that the 88% end covers the whole copy column; ours
       is taller, so the trust row and stats sat over a bright cabinet run and
       read washed out. The second layer only darkens the lower band. */
    background:
      linear-gradient(to top, rgba(var(--scrim),0.50) 0%, rgba(var(--scrim),0) 48%),
      linear-gradient(110deg,
        rgba(var(--scrim),0.88) 0%, rgba(var(--scrim),0.45) 55%, rgba(var(--scrim),0.18) 100%); }
  .hero__in { position: relative; max-width: 1280px; margin: 0 auto;
              padding: calc(var(--header-h) + var(--hero-gap)) 32px var(--hero-gap-b); }
  /* START, not stretch. Stretching made sense while the homepage copy
   column was the taller of the two; with the lede trimmed to one line
   and the tick list in place it is now the SHORTER one, so stretching
   pulled the booking panel taller than its contents and the submit
   button -- which has margin-top:auto -- was pushed to the bottom,
   leaving a dead band under the message box. */
  .hero__grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 40px; align-items: start; }
  .hero__copy { color: var(--background); }
  .hero h1 { margin-top: 24px; }
  .hero__lede { margin: 24px 0 36px; max-width: 32rem; font-size: 18px;
                line-height: 1.7; color: rgba(252,250,244,0.8); }
  .hero__cta { display: flex; gap: 12px; flex-wrap: wrap; }

  /* ---- hero proof block ----
     One block: a rating line with the two review profiles, a hairline, then
     the three terms as divided tiles. It replaces the glass $99 panel and the
     trust row, which between them said the same three things in two different
     shapes and took three times the height.

     The rating is DISPLAYED ONLY. There is deliberately no aggregateRating in
     the page schema -- a self-serving rating with no on-page reviews is
     penalised, and that is the rule across this whole network. */
  .hproof { margin-top: 34px; margin-bottom: 4px; max-width: 34rem; }
  /* ---- Sherman Oaks hero experiment ----
     A ticked list in place of the lede paragraph, and a 2x2 grid of
     per-source ratings in place of the blended score. Scoped to whatever
     page passes checks= / badges= to page_hero(), so no other hero moves.

     The tick is GREEN and it is the only green on the site. That is the
     point: it is a verification mark, not a brand colour, and copper ticks
     on a copper-accented hero would read as decoration. --ok is defined
     here rather than in :root because nothing else uses it. */
  /* Tighter than the standalone lede: it is a caption on the ticks below
     it, not the paragraph the hero used to lead with. */
  .hero__lede--tight { margin: 18px 0 20px; font-size: 16.5px; line-height: 1.6;
                       max-width: 30rem; }
  .hero__checks { --ok: #6ee7a8;
                  list-style: none; margin: 0 0 30px; padding: 0;
                  display: grid; gap: 11px; max-width: 34rem; }
  .hero__checks li { display: flex; align-items: flex-start; gap: 11px;
                     font-size: 16px; line-height: 1.5;
                     color: rgba(252,250,244,0.92); }
  .hero__checks svg { width: 17px; height: 17px; flex: none; margin-top: 3px;
                      color: var(--ok); stroke-width: 2.8; }
  /* The asterisk has to land somewhere. A same-day promise that is not
     qualified in sight of itself is the kind of claim that turns into a
     complaint on the phone. */
  .hero__checks-note { margin: -18px 0 30px; font-size: 13px; line-height: 1.5;
                       color: rgba(252,250,244,0.6); max-width: 34rem; }

  /* Two across, so four badges make a block rather than a row that wraps
     unevenly at the width the hero column actually gets. */
  /* Set exactly like the warranty/fee/same-day strip these replaced: the
     figure large, the source in small caps under it, hairline sticks
     between. Two across and not four, because four of these inside the
     hero column would give each about 120px.

     The sticks are BORDERS ON THE ITEMS, not elements of their own -- the
     same reason the terms strip did it that way. A divider drawn as its own
     element hangs in mid-air the moment a row wraps. */
  /* The rules form a CREST: one vertical down the middle, one horizontal
     across, meeting at the centre of the block. That only works if the grid
     has no row-gap -- a gap breaks the vertical line in half where the two
     rows part. The air between rows is padding on the items instead, so the
     borders stay continuous and actually cross. */
  .hbadges { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
             row-gap: 0; max-width: 32rem; margin-top: 30px; }
  .hbadge { display: flex; align-items: center; gap: 13px; padding: 17px 24px; }
  .hbadge:nth-child(odd) { padding-left: 0; }
  .hbadge:nth-child(even) { border-left: 1px solid rgba(252,250,244,0.16); }
  .hbadge:nth-child(n+3) { border-top: 1px solid rgba(252,250,244,0.16); }
  .hbadge svg { flex: none; }
  /* The marks sit on the same white disc the footer review chips use, which
     is what makes a multicolour logo readable over a photograph. Bigger than
     the footer's 26px because this is the hero. */
  .hbadge .bchip { width: 38px; height: 38px; box-shadow: 0 2px 6px rgba(0,0,0,0.22); }
  .hbadge .bchip svg { width: 21px; height: 21px; }
  /* The two redrawn seals ARE discs already, with their own fill and text
     inside. They fill the white chip edge to edge rather than floating in
     the middle of it, so the white reads as a ring around the seal instead
     of a plate under it. */
  .hbadge--yelp-verified .bchip svg,
  .hbadge--thumbtack .bchip svg { width: 32px; height: 32px; }
  .hbadge b { display: flex; align-items: center; gap: 7px;
              font-family: 'Sora', sans-serif; font-size: 18px; font-weight: 600;
              letter-spacing: -0.02em; line-height: 1.1; color: var(--background); }
  /* The source name sits on a lit photograph, and at 11.5px / 65% opacity it
     was the least readable text on the page. CONTRAST is what fixed it --
     0.65 -> 0.88 -- with a point of size and a heavier weight behind it.
     Weight alone at 65% would have made it bolder and still grey-on-bright.
     The extra letter-spacing is what uppercase at 600 needs to stay open. */
  .hbadge small { display: block; margin-top: 6px; font-size: 12.5px;
                  font-family: 'Sora', sans-serif; font-weight: 600;
                  letter-spacing: 0.085em; text-transform: uppercase;
                  color: rgba(252,250,244,0.88); }
  /* 14px, not 11. The score beside them is set at 18px, and stars that sit
     well under two-thirds of the number they belong to read as a texture
     rather than as a rating. */
  .hbadge__stars { display: inline-flex; gap: 1.5px; }
  .hbadge__stars svg { width: 14px; height: 14px;
                       color: var(--brand-glow); fill: var(--brand-glow); }
  /* One column on a phone: the crest has nothing to cross, so it becomes a
     plain stack with a rule between each pair. */
  @media (max-width: 480px) {
    .hbadges { grid-template-columns: 1fr; }
    .hbadge { padding: 13px 0; border-left: 0; }
    .hbadge + .hbadge { border-top: 1px solid rgba(252,250,244,0.16); }
  }

  .hproof__top { display: flex; flex-wrap: wrap; align-items: center;
                 gap: 12px 20px; }
  .hproof__rating { display: inline-flex; align-items: center; gap: 9px; }
  .hproof__stars { display: inline-flex; gap: 2px; }
  .hproof__stars svg { width: 16px; height: 16px;
                       color: var(--brand-glow); fill: var(--brand-glow); }
  .hproof__score { font-weight: 700; font-size: 15px; color: var(--background); }
  .hproof__count { font-size: 14px; color: rgba(252,250,244,0.78); }

  /* Source marks, NOT links. The only two clickable things in this hero are
     the phone number and Book online; an outbound link to Google or Yelp here
     sends a ready-to-call visitor to someone else's page at the exact moment
     they were about to act. The real profile links live in the footer, which
     is where leaving is fine. These are <span>, so there is nothing to click
     and no hover state promising one. */
  /* inline-grid with 1fr auto-columns, not inline-flex: in a shrink-to-fit
     grid every fr track resolves to the widest item's max-content size, so the
     two pills come out exactly equal without a hand-tuned min-width that would
     go stale the moment a label changes. */
  .hproof__marks { display: inline-grid; grid-auto-flow: column;
                   grid-auto-columns: 1fr; gap: 8px; }
  /* .hmark, NOT `.hproof__marks span`. That descendant selector also matched
     the .bchip span nested inside each pill, and at (0,1,1) it outranked
     .bchip at (0,1,0) -- so the white disc behind each logo was repainted with
     the pill's own translucent fill and the marks rendered as smudges. A class
     on the pill itself cannot reach the chip. */
  .hmark { display: inline-flex; align-items: center; gap: 7px;
           padding: 5px 13px 5px 5px; border-radius: var(--pill);
           border: 1px solid rgba(252,250,244,0.22);
           background: rgba(252,250,244,0.07);
           -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
           font-size: 13px; font-weight: 600; color: rgba(252,250,244,0.92); }

  .hproof__terms { display: flex; flex-wrap: wrap; margin-top: 22px;
                   padding-top: 20px; border-top: 1px solid rgba(252,250,244,0.16); }
  .hproof__terms > div { padding: 0 26px; }
  .hproof__terms > div:first-child { padding-left: 0; }
  /* The rules are borders on the tiles, not separate elements, so a tile that
     wraps to a second line does not leave a divider hanging in mid-air. */
  .hproof__terms > div + div { border-left: 1px solid rgba(252,250,244,0.16); }
  .hproof__terms b { display: block; font-family: 'Sora', sans-serif;
                     font-size: 23px; font-weight: 600; letter-spacing: -0.02em;
                     line-height: 1.1; color: var(--background); }
  .hproof__terms small { display: block; margin-top: 5px; font-size: 11.5px;
                         letter-spacing: 0.06em; text-transform: uppercase;
                         color: rgba(252,250,244,0.65); }


  /* ---- booking panel: rounded-[1.75rem] ---- */
  .panel { border-radius: var(--radius-panel); border: 1px solid rgba(230,222,212,0.7);
           background: var(--card); padding: 32px; box-shadow: var(--shadow-panel);
           display: flex; flex-direction: column; height: 100%; }
  .panel form { display: flex; flex-direction: column; flex: 1; }
  .panel form .btn--brand { margin-top: auto; }
  /* The reference heads this panel with a hairline rule and a copper label --
     no icon. The h-14 circle in their source is the SUCCESS state after
     submit (a CheckCircle2), which is why it does not appear on the live page. */
  .panel__eyebrow { display: flex; align-items: center; gap: 8px;
                    font-size: 12px; font-weight: 500; letter-spacing: 0.18em;
                    text-transform: uppercase; color: var(--brand); }
  .panel__eyebrow::before { content: ""; display: inline-block; width: 24px; height: 1px;
                            background: rgba(219,147,56,0.6); }
  .panel h2 { font-size: 24px; margin-top: 12px; }
  .panel__sub { font-size: 14px; color: var(--muted-fg); margin: 6px 0 24px; }
  .field { margin-bottom: 14px; }
  .field label { display: block; font-size: 13px; font-weight: 500; color: var(--muted-fg); margin-bottom: 6px; }
  .field input, .field select, .field textarea {
    width: 100%; font-family: inherit; font-size: 15px; color: var(--foreground);
    height: 44px; padding: 0 14px; border: 1px solid var(--border); border-radius: var(--r-md);
    background: var(--card); outline: none; transition: border-color .18s, box-shadow .18s; }
  /* A native <select> draws its own arrow and ignores padding-right, so the
     chevron sat hard against the border -- and at a different inset in the
     narrow .split field than in the full-width one, because the UA places it
     relative to the control, not the text box. appearance:none hands the
     drawing back to us: one chevron, same 16px inset in every field, and
     padding that keeps the text clear of it. */
  .field select {
    appearance: none; -webkit-appearance: none; -moz-appearance: none;
    padding-right: 42px; cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23a75c00' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 16px center;
    background-size: 16px 16px; }
  /* Firefox keeps a focus ring inside the control; this removes the second
     outline without removing ours. */
  .field select:-moz-focusring { color: transparent; text-shadow: 0 0 0 var(--foreground); }
  .field textarea { height: auto; padding: 12px 14px; resize: vertical; }
  .field input::placeholder, .field textarea::placeholder { color: #a79684; }
  .field :is(input,select,textarea):focus { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(219,147,56,0.15); }
  .split { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
  .panel .btn--brand { width: 100%; margin-top: 24px; box-shadow: var(--shadow-brand-sm); }
  .panel__foot { display: flex; justify-content: space-between; align-items: center; gap: 12px;
                 margin-top: 16px; font-size: 13px; color: var(--muted-fg); flex-wrap: wrap; }
  .panel__foot div { display: inline-flex; align-items: center; gap: 7px; }
  .panel__foot svg { width: 14px; height: 14px; color: var(--brand); }

  /* ---- marquee ---- */
  /* Ported from the reference's marquee.tsx rather than eyeballed. Their
     values, converted from Tailwind: section bg-background + border-y
     border-border/60, inner max-w-7xl px-8 py-10, caption text-xs/500/
     tracking-[0.2em], track mt-6 gap-10, items font-display text-2xl/600
     tracking-tight at foreground/35, 38s linear. */
  .brands { background: var(--background);
            border-block: 1px solid rgba(230,222,212,0.6); padding: 40px 0; }
  .brands__in { max-width: 1280px; margin: 0 auto; padding: 0 32px; }
  .brands__cap { text-align: center; font-size: 12px; font-weight: 500;
                 letter-spacing: 0.2em; text-transform: uppercase;
                 color: var(--muted-fg); margin-bottom: 24px; }
  /* The fade at both ends. Without it the names are guillotined mid-letter at
     the container edge, which is what made the row look broken. The mask is
     what the reference calls [mask-image:linear-gradient(to_right,transparent,
     black_8%,black_92%,transparent)]; -webkit- first for Safari. */
  .brands__win { position: relative; overflow: hidden;
    -webkit-mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent);
            mask-image: linear-gradient(to right, transparent, #000 8%, #000 92%, transparent); }
  .track { display: flex; align-items: center; gap: 40px; width: max-content;
           animation: slide 38s linear infinite; will-change: transform; }
  .brand { font-family: 'Sora', sans-serif; font-weight: 600; font-size: 24px;
           letter-spacing: -0.025em; color: rgba(44,32,23,0.35);
           white-space: nowrap; transition: color .2s; }
  .brand:hover { color: var(--brand); }
  @keyframes slide { to { transform: translateX(-50%); } }
  @media (max-width: 640px) {
    .brands__in { padding: 0 20px; }
    .brand { font-size: 20px; }
  }
  @media (prefers-reduced-motion: reduce) {
    .track { animation: none; flex-wrap: wrap; width: auto; justify-content: center; gap: 14px 30px; }
    .brands__win { -webkit-mask-image: none; mask-image: none; }
    .hdr__dot { animation: none; }
    *, header { transition: none !important; }
  }

  /* ---- sections ---- */
  .sec { padding: 96px 0; }
  .sec--muted { background: var(--muted); }
  /* The heading gets room for two lines at the larger size; the lede stays
     narrow, because a 50rem measure is too wide to read comfortably. */
  .sec__head { max-width: 50rem; margin-bottom: 52px; }
  .sec__head .lede { max-width: 42rem; }
  .sec__head h2 { margin: 18px 0 16px; }

  .grid3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: 22px; }
  /* A flex column so the CTA can sit on the bottom edge. Grid rows stretch
     every card to the tallest in the row, so a card with three bullets
     beside one with five was ending in a block of empty white. */
  .svc { scroll-margin-top: calc(var(--header-h) + 20px);
         position: relative; display: flex; flex-direction: column;
         background: var(--card); border: 1px solid rgba(230,222,212,0.7);
         border-radius: var(--r-3xl); padding: 28px; }
  /* The plate itself does nothing: no hover state, and no full-card link
     overlay. Seventeen plates lifting and shadowing as the pointer crossed
     them was most of the motion on the page, and a card-sized invisible
     anchor over the paragraphs put a click target under copy that is there
     to be read. The title and the button are the links. Focus rings stay --
     those are not decoration. */
  .svc h3 { font-size: 21px; line-height: 1.25; letter-spacing: -0.015em; }
  .svc h3 a { color: inherit; text-decoration: none; transition: color .2s; }
  .svc h3 a:hover { color: var(--brand-deep); }
  .svc h3 a:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; }
  .svc__icon { width: 48px; height: 48px; border-radius: var(--r-2xl);
               background: rgba(219,147,56,0.1); color: var(--brand);
               display: flex; align-items: center; justify-content: center; margin-bottom: 20px; }
  .svc__icon svg { width: 22px; height: 22px; }
  .svc__sub { font-size: 12.5px; color: var(--brand-deep); font-weight: 600; margin: 8px 0 13px; }
  .svc__body { font-size: 14.5px; line-height: 1.65; color: var(--muted-fg); }
  .svc__list { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
  .svc__list li { font-size: 13.5px; color: var(--muted-fg); padding-left: 20px; position: relative; margin-bottom: 7px; }
  .svc__list li::before { content: ""; position: absolute; left: 0; top: 8px;
                          width: 6px; height: 6px; border-radius: 50%; background: var(--brand); }
  /* margin-top:auto is what pins the wrapper to the card's bottom edge, so
     a card with three bullets ends level with one that has five. */
  /* A real button rather than a text link. margin-top:auto is what pins the
     wrapper to the bottom edge; z-index lifts it above the heading link's
     full-card ::after overlay, which would otherwise swallow its hover and
     its focus ring. The outline fills copper when the card is hovered, so
     the whole card reads as one target without the button disappearing
     into the body text when it is not. */
  .svc__foot { position: relative; z-index: 1; margin-top: auto; padding-top: 22px;
               display: flex; }
  .svc__cta { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
              width: 100%; height: 46px; padding: 0 20px; border-radius: var(--pill);
              border: 1px solid rgba(219,147,56,0.45); background: transparent;
              font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
              font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em;
              color: var(--brand-deep); text-decoration: none;
              transition: background .2s, color .2s, border-color .2s, box-shadow .2s; }
  .svc__cta svg { width: 16px; height: 16px; transition: transform .2s; }
  .svc__cta:hover { background: var(--brand); border-color: var(--brand);
                    color: var(--on-brand); box-shadow: var(--shadow-brand-sm); }
  .svc__cta:hover svg { transform: translateX(3px); }
  .svc__cta:focus-visible { outline: 2px solid var(--brand); outline-offset: 3px; }

  /* ---- why: ported from why-us.tsx ----
     Two columns at [0.9fr 1.1fr], photograph left, points right in a 2-up
     grid with a hairline over each. What was here before was a flat 3-up grid
     of copper dashes, built from a screenshot before the source arrived. */
  .why { position: relative; overflow: hidden;
         background: var(--foreground); color: var(--background); }
  .why h2, .why h3 { color: var(--background); }
  .why .lede, .why p { color: rgba(252,250,244,0.75); }
  /* Their bg-grain is foreground-coloured dots, which on this dark section
     are invisible. Same 4px dot grid, inverted so the texture actually shows. */
  .why__grain { position: absolute; inset: 0; pointer-events: none;
                background-image: radial-gradient(rgba(252,250,244,0.035) 1px, transparent 1px);
                background-size: 4px 4px; }
  .why__glow { position: absolute; top: 0; right: -80px; width: 40rem; height: 40rem;
               pointer-events: none; border-radius: 50%; opacity: 0.3; filter: blur(64px);
               background: radial-gradient(circle, rgba(219,147,56,0.4), transparent 70%); }
  .why__in { position: relative; display: grid; grid-template-columns: 0.9fr 1.1fr;
             gap: 64px; align-items: stretch; }
  /* The left column stretches to the row and the figure takes whatever height
     is left after the chips, so the photograph's bottom edge always lands with
     the last point on the right. A fixed aspect-ratio could not do that: it
     made the image 4/5 of its own width regardless of what the right column
     did, which is why the two ends disagreed by ~250px. */
  .why__left { display: flex; flex-direction: column; }

  .why__fig { position: relative; margin: 0; overflow: hidden; flex: 1;
              min-height: 420px;
              border-radius: 2rem; border: 1px solid rgba(252,250,244,0.15); }
  .why__fig img { display: block; width: 100%; height: 100%; object-fit: cover; }
  /* THE WIDE VARIANT, for a page's own landscape photograph.
     The portrait slot is `flex: 1` with `min-height: 420px`, so it absorbs
     whatever height the Why column has spare -- which on desktop is a lot.
     Dropping a 4:3 photo into that and letting object-fit:cover sort it out
     crops away the half of the frame the prompt specifically asked for ("wide
     shot showing the technician and the full appliance in the room"). So the
     wide figure sizes itself from its own aspect, drops the min-height that
     would re-stretch it, and the grid stops stretching the column. */
  .why__fig--wide { flex: none; aspect-ratio: 4 / 3; min-height: 0; }
  .why__in--wide { align-items: start; }
  .why__fig::after { content: ""; position: absolute; inset: 0;
    background: linear-gradient(to top, rgba(37,23,13,0.7), transparent 55%); }
  .why__cap { position: absolute; z-index: 1; left: 24px; right: 24px; bottom: 24px; }
  .why__cap b { display: block; font-family: 'Sora', sans-serif; font-size: 18px;
                font-weight: 600; color: var(--background); }
  .why__cap span { display: block; margin-top: 4px; font-size: 14px;
                   color: rgba(252,250,244,0.7); }
  .why__chips { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
                margin-top: 20px; flex: none; }
  .why__chips div { text-align: center; padding: 16px; border-radius: var(--r-2xl);
                    border: 1px solid rgba(252,250,244,0.15);
                    background: rgba(252,250,244,0.05);
                    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
  .why__chips b { display: block; font-family: 'Sora', sans-serif; font-size: 20px;
                  font-weight: 600; color: var(--brand-glow); }
  .why__chips small { display: block; margin-top: 2px; font-size: 11.2px;
                      letter-spacing: 0.04em; text-transform: uppercase;
                      color: rgba(252,250,244,0.6); }

  .why__head .eyebrow { color: var(--brand-glow); }
  .why__head h2 { margin: 12px 0 16px; }
  .why__head .lede { max-width: 36rem; }
  /* The why band's heading sits in a ~30rem column, which is half the width
     the section headings get. At the full h2 size a hyphenated brand name
     broke across lines -- "What makes a Sub-" / "Zero repair hold." Capped
     here rather than hyphen-hacking the brand name: replacing the ASCII
     hyphen with U+2011 would stop the break and also stop the name matching
     an exact-phrase search or a copy-paste. */
  .why__head h2 { font-size: clamp(28px, 3.1vw, 38px); }
  .why__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 28px 32px;
               margin-top: 36px; }
  .why__item { border-top: 1px solid rgba(252,250,244,0.15); padding-top: 20px; }
  /* Icon inline before the heading, not a chip above it: the grid is dense and
     a 32px chip per item would add ~300px to the column for no extra meaning.
     flex-start so a two-line heading keeps the mark on the first line. */
  .why__item h3 { display: flex; align-items: flex-start; gap: 10px;
                  font-size: 16px; font-weight: 600; }
  .why__item h3 svg { width: 18px; height: 18px; flex: none; margin-top: 2px;
                      color: var(--brand-glow); }
  .why__item p { font-size: 14px; line-height: 1.65; margin-top: 8px;
                 color: rgba(252,250,244,0.65); }

  /* ---- process: ported from process.tsx ----
     The numeral is the design: 48px, weight 700, copper at 25%, with a
     hairline running off it. It was a 13px label over a 2px top border. */
  .steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px;
           margin-top: 56px; list-style: none; }
  .step__top { display: flex; align-items: center; gap: 16px; }
  .step__n { font-family: 'Sora', sans-serif; font-weight: 700; font-size: 48px;
             line-height: 1; letter-spacing: -0.03em; color: rgba(219,147,56,0.25); }
  .step__rule { height: 1px; flex: 1; background: var(--border); }
  .step h3 { margin-top: 20px; font-size: 18px; font-weight: 600; }
  .step p { font-size: 14px; line-height: 1.65; color: var(--muted-fg); margin-top: 8px; }

  /* ---- areas: ported from service-area.tsx ----
     Two columns, copy left and a 3-up grid of pinned tiles right. It was a
     full-width wrap of pill chips with no pins and no call to action. */
  .areas { background: var(--muted); }
  .areas__in { display: grid; grid-template-columns: 0.9fr 1.1fr; gap: 64px;
               align-items: stretch; }
  .areas__copy h2 { margin: 12px 0 16px; }
  .areas__copy .lede { max-width: 28rem; }
  .areas__cta { display: flex; flex-wrap: wrap; align-items: center; gap: 16px;
                margin-top: 32px; }
  .areas__cta .btn--dark { display: inline-flex; align-items: center; gap: 8px;
                           border-radius: var(--pill); background: var(--foreground);
                           color: var(--background); padding: 12px 20px;
                           font-size: 14px; font-weight: 500; transition: opacity .2s; }
  .areas__cta .btn--dark:hover { opacity: 0.9; }
  .areas__cta .btn--dark svg { width: 16px; height: 16px; }
  .areas__cta span { font-size: 14px; color: var(--muted-fg); }
  /* Coverage map. No marker on it -- see region.map_embed_url(). The iframe is
     lazy and sits in a fixed 3:2 box so it costs nothing until it scrolls into
     view and shifts nothing when it arrives. */
  .areas__map { margin-top: 30px; border: 1px solid rgba(230,222,212,0.8);
                border-radius: var(--r-3xl); overflow: hidden; background: var(--card); }
  .areas__map iframe { display: block; width: 100%; aspect-ratio: 3 / 2;
                       border: 0; filter: saturate(0.82); }
  .areas__cap { display: flex; align-items: flex-start; gap: 9px;
                padding: 13px 18px; border-top: 1px solid rgba(230,222,212,0.7);
                font-size: 12.5px; line-height: 1.55; color: var(--muted-fg); }
  .areas__cap svg { width: 15px; height: 15px; flex: none; margin-top: 1px;
                    color: var(--brand); }

  /* The tile grid fills the row and spreads its 11 rows to match the column
     beside it, which ends lower because of the map. space-between on
     align-content distributes the surplus into the row gaps rather than
     leaving it all in one hole at the bottom -- and it self-corrects if the
     roster or the map height ever changes. */
  .areas__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px;
                 height: 100%; align-content: space-between;
                 list-style: none; }
  .chip { scroll-margin-top: calc(var(--header-h) + 20px);
          display: flex; align-items: center; gap: 8px; border-radius: var(--r-2xl);
          border: 1px solid rgba(230,222,212,0.7); background: var(--card);
          padding: 12px 16px; font-size: 14px; font-weight: 500;
          color: rgba(44,32,23,0.8); transition: border-color .2s, color .2s; }
  .chip:hover { border-color: rgba(219,147,56,0.4); color: var(--foreground); }
  .chip svg { width: 16px; height: 16px; flex: none; color: var(--brand); }

  /* ---- reviews: ported from testimonials.tsx ---- */
  .revs__head { display: flex; flex-wrap: wrap; align-items: flex-end;
                justify-content: space-between; gap: 24px; }
  .revs__head > div:first-child { max-width: 42rem; }
  .revs__head h2 { margin-top: 12px; }
  /* Unlike the hero, this one DOES link out. By the time someone has read
     three reviews, letting them verify on Google is worth more than keeping
     them on the page -- the hero is where a ready-to-call visitor must not be
     sent elsewhere, not here. */
  .revs__score { display: inline-flex; align-items: center; gap: 12px;
                 border-radius: var(--r-2xl); border: 1px solid rgba(230,222,212,0.7);
                 background: var(--card); padding: 12px 20px; font-size: 14px;
                 transition: border-color .2s, box-shadow .2s; }
  a.revs__score:hover { border-color: rgba(219,147,56,0.5);
                        box-shadow: 0 8px 22px -12px rgba(44,32,23,0.3); }
  .revs__more { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px;
                margin-top: 36px; }
  .revs__more a { display: inline-flex; align-items: center; gap: 9px;
                  border: 1px solid rgba(230,222,212,0.9); background: var(--card);
                  border-radius: var(--pill); padding: 9px 20px 9px 9px;
                  font-size: 14px; font-weight: 500; color: var(--foreground);
                  transition: border-color .2s, box-shadow .2s, color .2s; }
  .revs__more a:hover { border-color: rgba(219,147,56,0.55); color: var(--brand-deep);
                        box-shadow: 0 8px 22px -12px rgba(44,32,23,0.3); }
  .revs__more svg:last-child { width: 14px; height: 14px; }
  .revs__score .s { display: flex; }
  .revs__score svg { width: 20px; height: 20px; color: var(--brand); fill: var(--brand); }
  .revs__score b { font-weight: 600; color: var(--foreground); }
  .revs__score i { font-style: normal; color: var(--muted-fg); }
  .revs__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px;
                margin-top: 48px; }
  .rev { display: flex; flex-direction: column; margin: 0; padding: 28px;
         border-radius: var(--r-3xl); border: 1px solid rgba(230,222,212,0.7);
         background: var(--card); }
  /* A review card reads as a person, not a pull-quote: avatar, name, stars and
     the source mark across the top, the way the Google card itself is laid
     out. The lone quote glyph that was here made three cards of plain text. */
  .rev__top { display: flex; align-items: center; gap: 12px; }
  .rev__av { width: 40px; height: 40px; flex: none; border-radius: 50%;
             display: flex; align-items: center; justify-content: center;
             background: var(--gradient-brand); color: var(--on-brand);
             font-family: 'Sora', sans-serif; font-weight: 600; font-size: 16px;
             line-height: 1; }
  .rev__who { flex: 1; min-width: 0; }
  .rev__who b { display: block; font-family: 'Sora', sans-serif; font-size: 15px;
                font-weight: 600; color: var(--foreground); line-height: 1.25;
                overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .rev__stars { display: flex; gap: 1px; margin-top: 3px; }
  .rev__stars svg { width: 13px; height: 13px; color: var(--brand); fill: var(--brand); }
  .rev blockquote { flex: 1; margin: 18px 0 0; font-size: 15.2px; line-height: 1.7;
                    color: rgba(44,32,23,0.85); }
  .rev figcaption { display: flex; align-items: center; gap: 8px;
                    margin-top: 22px; padding-top: 18px;
                    border-top: 1px solid rgba(230,222,212,0.6);
                    font-size: 12.5px; color: var(--muted-fg); }
  .rev figcaption svg { width: 15px; height: 15px; flex: none; color: var(--brand); }

  /* ---- brand cards ---- */
  .bcard { scroll-margin-top: calc(var(--header-h) + 20px);
           padding: 24px;
           position: relative; display: flex; flex-direction: column;
           background: var(--card); border: 1px solid rgba(230,222,212,0.7);
           border-radius: var(--r-3xl);
           transition: border-color .2s; }
  /* Nothing on hover here either. A plate that lights up under the pointer
     but is only clickable on its title is worse than one that does nothing. */
  /* Four across, so sixteen cards make four clean rows. At ~280px a card
     cannot hold the name and a label like "Refrigeration & dishwashing" on
     one line, so the category sits under the name -- consistently, rather
     than wrapping on some cards and not others. */
  .grid4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
  /* The brands a type page services without carding. Set as a sentence,
     not as more chips: it is a footnote to the grid above it. */
  .alsoline { margin: 26px 0 0; max-width: 60ch; font-size: 15px;
              line-height: 1.7; color: var(--muted-fg); }
  .bcard__top { margin-bottom: 13px; }
  /* The mark before a brand title.
     DRAWN, not typed: content:"" with a rotated square, never a "C6"
     character. A pseudo-element carrying real text is read aloud by some
     screen readers and lands in the accessible name of the heading, which
     would make the anchor text "diamond Sub-Zero Repair". A shape has no
     text to leak.
     A DIAMOND and not a chevron or an asterisk: "A" is already the mark on
     every footer nav link and would make this grid read as a list of links;
     "2" is already the card bullet; "*" reads as a footnote on a page that
     has genuine legal fine print at the bottom. The diamond is the one
     shape in the vocabulary that is not spoken for. */
  .bcard h3::before { content: ""; display: inline-block; width: 7px; height: 7px;
                      margin-right: 11px; vertical-align: 0.22em;
                      background: var(--brand); transform: rotate(45deg); }
  .bcard h3 { font-family: 'Sora', sans-serif; font-size: 19px; font-weight: 600;
              letter-spacing: -0.02em; line-height: 1.2; }
  .bcard h3 a { color: inherit; text-decoration: none; }
  .bcard h3 a:hover { color: var(--brand-deep); }
  .bcard h3 a:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; }
  .bcard__cat { display: block; margin-top: 5px;
                font-size: 10.5px; font-weight: 600; letter-spacing: 0.1em;
                text-transform: uppercase; color: var(--brand-deep); }
  .bcard p { font-size: 14px; line-height: 1.62; color: var(--muted-fg); flex: 1; }
  .bcard__tags { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 18px;
                 padding-top: 16px; border-top: 1px solid var(--border); }
  .bcard__tags span { border: 1px solid rgba(230,222,212,0.9); border-radius: var(--pill);
                      padding: 5px 12px; font-size: 12px; color: var(--muted-fg); }

  /* The date input has to sit level with the select beside it. Safari and
     Chrome size date fields from their own internal text, not from the box,
     so without an explicit height the two halves of the row disagree. */
  .field__date { -webkit-appearance: none; appearance: none; }
  .field__date::-webkit-date-and-time-value { text-align: left; }
  .field__date::-webkit-calendar-picker-indicator { cursor: pointer; opacity: .55;
                                                    filter: sepia(1) saturate(4) hue-rotate(-12deg); }
  .field__date:hover::-webkit-calendar-picker-indicator { opacity: .9; }
  .field__hint { display: block; margin-top: 7px; font-size: 12.5px;
                 line-height: 1.45; color: var(--muted-fg); }

  /* The hub photo band. One figure, one caption, no overlay -- see
     photo_band() for why this one reads rather than decorates. */
  .pfig { margin: 0; }
  .pfig img { display: block; width: 100%; height: auto; border-radius: 2rem;
              border: 1px solid var(--border); }
  .pfig__cap { margin-top: 14px; font-size: 14.5px; line-height: 1.6;
               color: var(--muted-fg); max-width: 72ch; }
  .pfig__cap b { font-weight: 600; color: var(--foreground); }

  /* The sprite host element. It carries no viewBox of its own -- that lives
     on the <symbol> -- so without an explicit size it would collapse to
     zero. Every existing rule that sizes an icon still applies, because
     they all target `svg`. */
  .ic { width: 1em; height: 1em; fill: none; stroke: currentColor;
        stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

  /* The honeypot. Off-screen rather than display:none, because some bots
     skip hidden fields but fill positioned ones. A human never sees it and a
     submission that fills it is dropped without reaching the CRM. */
  .hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
  .formmsg { margin: 14px 0 0; font-size: 14.5px; line-height: 1.6; }
  .formmsg--ok { color: var(--brand-deep); font-weight: 600; }
  .formmsg--err { color: #b3261e; }
  form[data-busy="1"] button[type="submit"] { opacity: .6; pointer-events: none; }

  /* ---- legal prose ----
     Terms and privacy are read differently from the rest of the site:
     somebody is hunting one clause, not reading top to bottom. The headings
     carry the weight and the measure stays narrow enough to scan. One column
     deliberately -- a clause split across a column break is how people miss
     the half that mattered. */
  .legal { display: grid; gap: 34px; max-width: 46rem; }
  .legal__item h3 { font-family: 'Sora', sans-serif; font-size: 19px; font-weight: 600;
                    letter-spacing: -0.015em; margin: 0 0 10px; color: var(--foreground); }
  .legal__item p { margin: 0 0 12px; font-size: 16px; line-height: 1.75;
                   color: var(--muted-fg); max-width: 62ch; }
  .legal__item p:last-child { margin-bottom: 0; }
  .legal__item a { color: var(--brand-deep); text-decoration: underline;
                   text-underline-offset: 3px; }

  /* ---- FAQ ----
     WAS: nine white cards in two columns. Three things were wrong with it.
     Nine identical bordered boxes are nine competing objects, and a stack of
     them flattens the hierarchy rather than building one -- the list is the
     object, not each row. An odd count cannot balance across two columns, so
     the ninth question left a card-sized hole at the bottom right. And
     opening an accordion in a two-column grid pushes only its own column
     down, which jolts the page asymmetrically.

     NOW: the heading sits in its own column beside the list, the way the why
     and areas bands already do, and the questions are hairline rows -- the
     same treatment as the faults list and the roster. One object, no hole,
     and the full width earns its keep. */
  .faq__in { display: grid; grid-template-columns: 0.82fr 1.18fr; gap: 64px;
             align-items: start; }
  /* Sticky, because the list is long and the question "who do I call if mine
     is not here" should still have an answer in view at the bottom of it. */
  .faq__head { position: sticky; top: calc(var(--header-h) + 24px); }
  .faq__head h2 { margin: 18px 0 16px; }
  .faq__head .lede { margin: 0; }
  .faq__call { display: inline-flex; align-items: center; gap: 9px; margin-top: 26px;
               font-family: 'Sora', sans-serif; font-size: 17px; font-weight: 600;
               letter-spacing: -0.01em; color: var(--brand-deep); text-decoration: none; }
  .faq__call svg { width: 17px; height: 17px; }
  .faq__call:hover { color: var(--foreground); }

  .faq__grid { display: block; border-top: 1px solid var(--border); }
  .faq__q { border-bottom: 1px solid var(--border); background: none; }
  .faq__q summary { list-style: none; cursor: pointer;
                    display: flex; align-items: flex-start; justify-content: space-between;
                    gap: 24px; padding: 21px 0;
                    font-family: 'Sora', sans-serif; font-size: 17px; font-weight: 600;
                    line-height: 1.4; color: var(--foreground);
                    transition: color .18s; }
  .faq__q summary:hover { color: var(--brand-deep); }
  .faq__q[open] summary { color: var(--brand-deep); }
  .faq__q summary::-webkit-details-marker { display: none; }
  .faq__q summary:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; }
  /* A drawn chevron rather than a glyph: "+" rotates to a convincing "x", but
     a chevron rotating to point up is what a reader expects from an accordion. */
  .faq__q summary::after { content: ""; flex: none; width: 9px; height: 9px;
    margin-top: 6px; border-right: 2px solid var(--brand);
    border-bottom: 2px solid var(--brand); transform: rotate(45deg);
    transition: transform .2s; }
  .faq__q[open] summary::after { transform: rotate(-135deg); margin-top: 10px; }
  /* 62ch, not the full column: an answer set across 900px is a ribbon nobody
     finishes. The chevron column keeps the right gutter honest. */
  .faq__a { padding: 0 44px 24px 0; max-width: 62ch;
            font-size: 15.5px; line-height: 1.75; color: var(--muted-fg); }

  /* ---- closing CTA: ported from cta.tsx ----
     A dark CARD on the light page, not a full-bleed copper band. The band
     version put a second large block of copper directly above the espresso
     footer and the page ended on two heavy slabs; the card leaves the ivory
     margin around it and reads as the last object rather than another floor. */
  .cta { background: var(--background); }
  .cta__card { position: relative; overflow: hidden;
               border-radius: 2rem; background: var(--foreground);
               color: var(--background); padding: 56px;
               display: grid; grid-template-columns: 1.15fr 0.85fr;
               gap: 40px; align-items: center; }
  /* The same copper bloom the Why section uses, so the two dark blocks on the
     page are lit the same way. */
  .cta__card::before { content: ""; position: absolute; top: -120px; right: -120px;
    width: 30rem; height: 30rem; border-radius: 50%; pointer-events: none;
    opacity: 0.3; filter: blur(64px);
    background: radial-gradient(circle, rgba(219,147,56,0.4), transparent 70%); }
  .cta__in { position: relative; }
  .cta .eyebrow { color: var(--brand-glow); }
  .cta h2 { color: var(--background); margin: 14px 0 0; }
  .cta p { color: rgba(252,250,244,0.75); font-size: 17px; margin: 16px 0 32px;
           max-width: 34rem; }
  .cta__chips { position: relative; display: flex; flex-direction: column;
                align-items: flex-end; gap: 12px; }
  .cta__chips div { display: inline-flex; align-items: center; gap: 10px;
                    border-radius: var(--pill);
                    border: 1px solid rgba(252,250,244,0.15);
                    background: rgba(252,250,244,0.05);
                    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
                    padding: 13px 22px; font-size: 14.5px; font-weight: 500;
                    color: rgba(252,250,244,0.92); }
  .cta__chips svg { width: 17px; height: 17px; flex: none; color: var(--brand-glow); }
  .cta .btn--glass { border-color: rgba(252,250,244,0.3);
                     background: rgba(252,250,244,0.06); color: var(--background); }
  .cta .btn--glass:hover { background: rgba(252,250,244,0.14); }

  footer { background: var(--foreground); color: rgba(252,250,244,0.6); padding: 72px 0 32px; font-size: 14px; }
  /* Five columns: identity, then Services / Brands / Areas / Company. The
     three middle ones each show six entries and an "all" link, which is the
     shape both reference footers use -- a footer is a sitemap for crawlers as
     much as a nav for people, and four generic hash links were neither. */
  .foot { display: grid; grid-template-columns: 1.7fr 1fr 1fr 1fr 0.85fr; gap: 44px 36px; }
  .foot__all { display: inline-flex; align-items: center; gap: 6px; margin-top: 4px;
               color: var(--brand-glow); font-weight: 600; }
  .foot__all svg { width: 13px; height: 13px; }
  /* The chevron before each link, as in both references. It is a ::before on
     the anchor rather than an inline SVG per row: 19 copies of the same path
     is a kilobyte of markup for a decoration. */
  .foot__links--nav a { position: relative; padding-left: 15px; }
  .foot__links--nav a::before { content: ""; position: absolute; left: 0; top: 50%;
    width: 5px; height: 5px; margin-top: -3px; border-right: 1.5px solid var(--brand);
    border-top: 1.5px solid var(--brand); transform: rotate(45deg); }
  .foot__links--nav .foot__all { padding-left: 0; }
  .foot__links--nav .foot__all::before { display: none; }
  .foot__tel { display: block; font-family: 'Sora', sans-serif; font-size: 19px;
               font-weight: 600; color: var(--brand-glow); margin: 18px 0 10px; }
  .foot__nap { font-size: 13.5px; line-height: 1.7; }
  /* The additional number. Deliberately small and deliberately labelled: it
     is published so the Google listing and this site share a number, not so
     anyone rings it in preference to the main one. See
     region.PHONE_SECONDARY for why it is here and when it comes out. */
  .foot__tel2 { display: block; margin-top: 6px; font-size: 12.5px;
                line-height: 1.6; color: var(--muted-fg); text-decoration: none; }
  .foot__tel2 b { font-weight: 600; color: rgba(252,250,244,0.72); }
  .foot__tel2:hover b { color: var(--brand-glow); }
  /* The independence statement. It is set apart in its own band because it is
     a legal notice, not footer copy, and it names the marks it disclaims. */
  .foot__legal { margin-top: 44px; padding-top: 26px;
                 border-top: 1px solid rgba(252,250,244,0.15);
                 font-size: 12.5px; line-height: 1.65; color: rgba(252,250,244,0.6); }
  /* .foot__h, and an h2 not an h4: the document went h2 -> h4 here, skipping a
     level, which is the one heading-outline mistake assistive tech and
     outline-based parsers both trip on. The size is a role, not a level. */
  .foot__h { font-family: 'Sora', sans-serif; font-size: 12.5px; letter-spacing: 0.13em;
             text-transform: uppercase; color: var(--background); margin: 0 0 18px;
             font-weight: 600; line-height: 1.3; }
  footer a:hover { color: var(--brand-glow); }
  .foot__links { display: flex; flex-direction: column; gap: 10px; }
  .hours__row { display: flex; justify-content: space-between; gap: 14px; margin-bottom: 9px; }
  .hours__row span:last-child { color: rgba(252,250,244,0.85); }
  .foot__bot { display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap;
               margin-top: 52px; padding-top: 26px; border-top: 1px solid rgba(252,250,244,0.15); font-size: 12.5px; }
  /* Profile links. These are not navigation -- they belong with the identity,
     under the blurb, the way social links sit on every other site. */
  .social { display: flex; gap: 10px; margin: 20px 0 18px; }
  .social a { display: inline-flex; align-items: center; gap: 9px;
              border: 1px solid rgba(252,250,244,0.16); border-radius: var(--pill);
              padding: 6px 17px 6px 7px; font-size: 13.5px; font-weight: 500;
              color: rgba(252,250,244,0.8); transition: border-color .2s, color .2s, background .2s; }
  .social a:hover { border-color: var(--brand); color: var(--background); background: rgba(219,147,56,0.12); }
  .bchip { width: 26px; height: 26px; border-radius: var(--pill); background: #fff;
           display: inline-flex; align-items: center; justify-content: center;
           box-shadow: 0 1px 3px rgba(0,0,0,0.18); flex-shrink: 0; }
  .bchip svg { width: 15px; height: 15px; }

  .badge { display: inline-block; border: 1px solid rgba(250,181,73,0.35); border-radius: var(--pill);
           padding: 7px 16px; color: var(--brand-glow); font-weight: 600; font-size: 12.5px; }
  /* The verified variant only needs the shield to sit on the text baseline.
     No hover and no focus ring: it is not a link and must not look like one. */
  .badge--verified { display: inline-flex; align-items: center; gap: 7px; }
  .badge--verified svg { width: 14px; height: 14px; flex: none; }

  /* [data-tbd] marks the placeholder phone number. It is an ATTRIBUTE and not
     a class because a second class="" on an element that already has one is
     silently dropped by the parser. It deliberately has NO styling: the dashed
     ring it used to draw was a build-time marker that had no business being
     visible to visitors. Find the placeholders with a grep for data-tbd, not
     by looking at the page. */

  @media (max-width: 1023px) {
    .nav, .hdr__tel { display: none; }
    .burger { display: flex; }
    .callbar { display: block; }
    body { padding-bottom: 76px; }
    .hdr__live span { display: none; }
    .why__in, .areas__in { grid-template-columns: 1fr; gap: 44px; }
    /* One column: there is no neighbouring column to match, so the tiles go
       back to their natural height and an even 12px gap. */
    .areas__grid { height: auto; align-content: start; }
    /* Stacked: the heading column goes back on top and stops sticking,
       because a sticky block that is as tall as the viewport pins the
       list off the bottom of the screen. */
    .faq__in { grid-template-columns: 1fr; gap: 36px; }
    .faq__head { position: static; }
    .grid3 { grid-template-columns: 1fr; }
    .cta__card { grid-template-columns: 1fr; gap: 32px; padding: 40px; }
    .cta__chips { align-items: flex-start; }
    .why__fig { flex: none; aspect-ratio: 4 / 5; }
    .steps { grid-template-columns: repeat(2, 1fr); gap: 32px 24px; }
    .revs__grid { grid-template-columns: 1fr; }
    /* Two across between 641 and 1023. Below that it goes to one: at 390px
       a half-width card is ~165px of text, which broke "Sub-Zero
       Refrigerator Repair" over three lines and wrapped every chip. */
    .grid4 { grid-template-columns: repeat(2, 1fr); }
    .hero__grid { grid-template-columns: 1fr; gap: 48px; }
    .hero__in { padding: calc(var(--header-h) + 22px) 32px 48px; }
    .foot { grid-template-columns: 1fr 1fr 1fr; }
    .foot > div:first-child { grid-column: 1 / -1; }
  }
  @media (max-width: 640px) {
    .wrap, .hdr, .hero__in { padding-left: 20px; padding-right: 20px; }
    /* The strip's left item wrapped to a second line and overflowed the fixed
       114px header. Below 640 the strip carries the rating only, the header
       collapses to one 68px row, and --header-h follows so the hero's top
       padding is not computed from a height the header no longer has. */
    :root { --header-h: 102px; }
    .strip { height: 34px; }
    /* Two items, pushed apart: the rating on the left, the hours on the
       right. It used to be the rating alone, centred, with the licence
       hidden -- which left a 34px band carrying one short phrase and a lot
       of nothing either side of it. */
    .strip__in { justify-content: space-between; padding: 0 20px; gap: 10px; }
    .strip__in div:first-child { display: none; }
    .strip__hours { display: inline-flex !important; white-space: nowrap; }
    .strip__hours svg { width: 12px; height: 12px; }
    header { height: var(--header-h); }
    header.stuck { height: 68px; }
    .hdr { height: 68px; gap: 10px; }
    .hdr__right { gap: 8px; }
    .hdr__live { display: none; }
    /* Nothing in the bar may wrap: that is what put the logo and the phone
       number on two lines each. */
    .logo__mk { font-size: 19px; }
    .logo__sv { font-size: 16px; white-space: nowrap; }
    .hdr__right .btn--brand { height: 40px; padding: 0 14px; font-size: 14px;
                              white-space: nowrap; }
    .hdr__right .btn--brand svg { width: 15px; height: 15px; }
    .sec { padding: 64px 0; }
    .panel { padding: 24px; }
    .foot { grid-template-columns: 1fr 1fr; gap: 32px 24px; }
    .split { grid-template-columns: 1fr; }
    .hero__cta .btn { width: 100%; }
    .cta__card { padding: 28px 22px; border-radius: var(--radius-panel); }
    .cta__chips div { width: 100%; }
    /* Three tiles, one row, always. Left to wrap they broke 2 + 1, and the
       orphan on the second row kept its left divider -- a hairline hanging
       in space under the gap between the two above it. A three-column grid
       cannot produce that; it just gets narrower. */
    .hproof__terms { display: grid; grid-template-columns: repeat(3, 1fr); }
    .hproof__terms > div { padding: 0 14px; }
    .hproof__terms b { font-size: 19px; }
    .hproof__terms small { font-size: 10.5px; letter-spacing: 0.08em; }
    .steps { grid-template-columns: 1fr; }
    .grid4 { grid-template-columns: 1fr; }
    /* 28px of padding either side of a 350px card leaves the body text in a
       narrow ribbon. One column does not need that much air. */
    .svc, .bcard { padding: 22px; }
    .why__grid { grid-template-columns: 1fr; gap: 22px; }
    .areas__grid { grid-template-columns: repeat(2, 1fr); }
    .step__n { font-size: 40px; }
  }

  /* =====================================================================
     SUB-PAGE BLOCKS
     Appended after every existing rule and scoped to class names used
     nowhere above, because the recurring bug on this site has been a new
     descendant selector quietly outranking an older single-class one.
     Nothing here restyles a shared component; it only adds blocks the
     type, brand and city pages need.
     ===================================================================== */

  /* The sub-page hero is the same hero with less air above and below: the
     homepage opener has to carry the whole proposition, a sub-page opener
     only has to say what the page is and offer the form. */
  /* 24px, not 56px: the trail is orientation and belongs under the nav it
     continues, not floating a third of the way down the hero. */
  /* The sub-page hero no longer overrides the spacing: --hero-gap is 40px
     and --hero-gap-b is 72px for every hero on the site. 56px floated the
     breadcrumb trail a third of the way down; 24px put it hard under the nav
     with nothing between them; 40 is the settled value. */
  /* .hero--page used to set align-items:start on its own; the base grid now
     does it for every hero, for the same reason. */
  /* The floor was 32px while the BASE h1 floor is 36 -- a sub-page headline
     was coming out smaller than an ordinary one, which is backwards: on a
     phone the h1 is most of what is on screen. 40px is as large as the
     longest place name on the roster goes without overflowing 390px:
     "Flintridge" is the longest unbreakable word at ten characters. */
  .hero--page h1 { font-size: clamp(40px, 4.2vw, 52px); margin-top: 18px; }
  .hero--page .hero__lede { margin: 20px 0 30px; }

  /* The trail is orientation, not navigation furniture: it should be read
     once and then disappear. The underline on every link made three items
     read as three buttons stacked on the eyebrow pill directly below, and
     with no margin under it the two rows ran together. */
  .crumbs { display: flex; flex-wrap: wrap; align-items: center;
            margin-bottom: 22px; font-size: 13px; line-height: 1.5;
            letter-spacing: 0.01em; }
  .crumbs__up { color: rgba(252,250,244,0.66); text-decoration: none;
                transition: color .18s; }
  .crumbs__up:hover { color: var(--brand-glow); text-decoration: underline;
                      text-underline-offset: 3px;
                      text-decoration-thickness: 1px; }
  .crumbs__sep { margin: 0 9px; color: rgba(252,250,244,0.28); }
  .crumbs__here { color: rgba(252,250,244,0.92); font-weight: 600; }

  /* The independence line on a brand page. It sits directly under the CTAs,
     above the fold, at body size -- not shrunk into fine print. */
  .hero__note { margin: 22px 0 0; max-width: 34rem; padding: 12px 16px;
                border: 1px solid rgba(252,250,244,0.22); border-radius: var(--radius);
                background: rgba(252,250,244,0.07); font-size: 14px; line-height: 1.6;
                color: rgba(252,250,244,0.82); }
  .hero__note b { color: rgba(252,250,244,0.95); font-weight: 600; }

  /* ---- the problems block ----
     Rows are cards, not table rows. The block sits on the beige band, and
     white cards on beige is the same figure/ground the FAQ uses two
     sections further down, so it reads as part of the system instead of a
     spreadsheet dropped into it. Hairline rules on a flat ground did the
     opposite: ten of them stacked read as a price list.

     Every selector here is a class. The last time a block in this file used
     a descendant element selector (.hproof__marks span) it matched a nested
     span it was never meant to reach and repainted it. */
  /* Compacted: the rows were carrying card padding on all four sides plus a
     12px gutter between them, which turned ten short exchanges into a metre
     of page. Tighter padding, a tighter gutter and a narrower symptom column
     put roughly a third of the height back. */
  .flt { display: grid; gap: 8px; margin: 0; }
  .flt__row { position: relative; overflow: hidden;
              display: grid; grid-template-columns: 0.78fr 1.52fr;
              /* stretch, not start: the divider is the right column's own
                 left border, so anything less than full height left a stub
                 of rule floating beside the shorter answers. */
              align-items: stretch;
              background: var(--card);
              border: 1px solid rgba(230,222,212,0.85);
              border-radius: var(--radius); padding: 17px 24px;
              transition: border-color .2s, box-shadow .2s; }
  .flt__row:hover { border-color: rgba(219,147,56,0.45);
                    box-shadow: 0 16px 34px -24px rgba(44,32,23,0.45); }
  /* A copper rail that arrives on hover. One accent, spent once per row. */
  .flt__row::before { content: ""; position: absolute; left: 0; top: 11px; bottom: 11px;
                      width: 3px; border-radius: 0 3px 3px 0;
                      background: var(--gradient-brand);
                      opacity: 0; transition: opacity .2s; }
  .flt__row:hover::before { opacity: 1; }
  .flt__sym { margin: 0; padding-right: 26px;
              font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
              font-size: 15.5px; font-weight: 600; line-height: 1.4;
              letter-spacing: -0.01em; color: var(--foreground); }
  .flt__why { margin: 0; padding-left: 26px;
              border-left: 1px solid var(--border);
              color: var(--muted-fg); font-size: 15px; line-height: 1.62; }

  /* ---- roster ----
     One component for every long list of links on the site: appliance
     types, brands, service areas. It replaced three different walls -- 17
     pills, 16 pills and 33 chips -- which between them ate most of the
     height of a page and said nothing about how the items related.

     Set as text on rules rather than as a field of pills: a pill is a
     control, and seventeen of them in a block reads as seventeen buttons
     nobody is going to press. The group label carries the structure, and
     the hairline carries the separation that the pill outlines were doing
     far more loudly. */
  .roster { display: grid; }
  .roster__row { display: grid; grid-template-columns: 14rem 1fr; gap: 40px;
                 align-items: start; padding: 24px 0;
                 border-top: 1px solid var(--border); }
  .roster__row:last-child { border-bottom: 1px solid var(--border); }
  .roster__label { display: flex; align-items: center; gap: 10px; margin: 6px 0 0;
                   font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
                   font-size: 12px; font-weight: 600; letter-spacing: 0.14em;
                   text-transform: uppercase; color: var(--muted-fg); }
  /* The count is derived from the list beside it, so it is information, not
     decoration -- it tells you how long the column is before you read it. */
  .roster__label span { display: inline-flex; align-items: center; justify-content: center;
                        min-width: 22px; height: 20px; padding: 0 6px;
                        border-radius: var(--pill); background: var(--secondary);
                        font-size: 11px; letter-spacing: 0.04em; color: var(--brand-deep); }
  .roster__list { display: flex; flex-wrap: wrap; margin: 0; padding: 0; list-style: none; }
  .roster__list li { display: flex; align-items: center; }
  /* The separator rides on the item BEFORE the gap, never after it: as a
     ::before on the next item it could wrap onto a new line and start that
     line with a floating dot. */
  .roster__list li::after { content: ""; width: 3px; height: 3px; border-radius: 50%;
                            background: var(--border); margin: 0 14px; }
  .roster__list li:last-child::after { display: none; }
  .roster__list a { padding: 5px 0; font-size: 15.5px; font-weight: 500;
                    color: var(--foreground); text-decoration: none;
                    border-bottom: 1px solid transparent;
                    transition: color .18s, border-color .18s; }
  .roster__list a:hover { color: var(--brand-deep); border-bottom-color: var(--brand); }

  .chip--link { text-decoration: none;
                transition: border-color .18s, background .18s, color .18s; }
  .chip--link:hover { border-color: var(--brand); background: var(--card);
                      color: var(--brand-deep); }
  /* The city you are already on. Marked, not linked. */
  .chip--here { border-color: rgba(219,147,56,0.55); background: var(--secondary);
                color: var(--foreground); font-weight: 600; }


  /* Two-column editorial band: running copy on the left, a short list of
     facts on the right. Used for the local detail on a city page and the
     parts/warranty note on a brand page. */
  .two { display: grid; grid-template-columns: 1.25fr 0.75fr; gap: 56px; align-items: start; }
  .two__body > p { margin: 0 0 18px; font-size: 16.5px; line-height: 1.8; color: var(--muted-fg); }
  .two__body > p:last-child { margin-bottom: 0; }
  .two__body strong { color: var(--foreground); font-weight: 600; }
  .side { border: 1px solid var(--border); border-radius: var(--r-xl);
          background: var(--card); padding: 26px 24px; box-shadow: var(--shadow-panel); }
  .side h3 { margin: 0 0 16px; font-size: 16px; letter-spacing: -0.01em; }
  .side dl { display: grid; gap: 14px; margin: 0; }
  .side dt { font-size: 12px; font-weight: 600; letter-spacing: 0.12em;
             text-transform: uppercase; color: var(--muted-fg); }
  .side dd { margin: 2px 0 0; font-size: 15.5px; line-height: 1.6; color: var(--foreground); }

  /* ---- facts ----
     The terms, laid across instead of stacked in a tall card beside the
     copy. One object holding four related numbers, which is what it is. */
  .facts { display: grid; grid-template-columns: repeat(4, 1fr);
           border: 1px solid var(--border); border-radius: var(--r-xl);
           background: var(--card); overflow: hidden; margin-bottom: 56px; }
  .facts > div { padding: 22px 26px; border-left: 1px solid var(--border); }
  .facts > div:first-child { border-left: 0; }
  .facts__k { display: block; font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
              font-size: 11px; font-weight: 600; letter-spacing: 0.14em;
              text-transform: uppercase; color: var(--muted-fg); }
  .facts__v { display: block; margin-top: 8px;
              font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
              font-size: 15.5px; font-weight: 600; line-height: 1.45;
              letter-spacing: -0.01em; color: var(--foreground); }

  /* ---- split ----
     Heading, copy and the terms down one side; the page's photograph down
     the other.

     /contact shipped the photo in a band of its own directly under the
     breadcrumb -- a picture with no sentence anywhere near it -- and then
     ran a half-width lede in the band below with the right half of the
     band empty. One block answers both: the photograph becomes the thing
     that fills that half, and it arrives with a heading beside it.

     Declared AFTER .facts on purpose. .facts--pair has the same specificity
     as .facts, so defined earlier it would lose the grid-template-columns
     to the four-across base rule and silently do nothing. */
  .split { display: grid; grid-template-columns: 1fr 0.84fr; gap: 56px;
           align-items: start; }
  /* The head's bottom margin is the gap down to the facts here rather than
     the gap to the next band, and the facts stop reserving the trailing
     56px they need when they end a full-width band. */
  .split .sec__head { max-width: none; margin-bottom: 36px; }
  .split .facts { margin-bottom: 0; }
  .split__fig { margin: 0; }
  .split__fig img { display: block; width: 100%; height: auto;
                    border-radius: 2rem; border: 1px solid var(--border); }
  .split__cap { margin-top: 14px; font-size: 14.5px; line-height: 1.6;
                color: var(--muted-fg); }
  .split__cap b { font-weight: 600; color: var(--foreground); }
  /* The base rule only clears the left border on the first cell, which is
     right for one row and wrong for two, so the dividers are re-drawn. */
  .facts--pair { grid-template-columns: repeat(2, 1fr); }
  .facts--pair > div:nth-child(2n+1) { border-left: 0; }
  .facts--pair > div:nth-child(n+3) { border-top: 1px solid var(--border); }

  /* ---- points ----
     Three ideas that used to be three paragraphs. No card and no icon: a
     short copper rule is enough of a marker, and it is the one place the
     accent is spent in this band. */
  .pts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; }
  .pt__rule { display: block; width: 34px; height: 3px; border-radius: 3px;
              background: var(--gradient-brand); }
  .pt h3 { margin: 18px 0 12px; font-size: 22px; line-height: 1.2;
           letter-spacing: -0.02em; }
  .pt p { margin: 0; font-size: 15.5px; line-height: 1.7; color: var(--muted-fg); }

  @media (max-width: 1023px) {
    /* .hero--page: nothing to override, the base is already 22/48 here. */
    .two { grid-template-columns: 1fr; gap: 32px; }
    .split { grid-template-columns: 1fr; gap: 36px; }
    .pts { grid-template-columns: 1fr 1fr; gap: 32px; }
    .facts { grid-template-columns: repeat(2, 1fr); }
    .facts > div:nth-child(2n+1) { border-left: 0; }
    .facts > div:nth-child(n+3) { border-top: 1px solid var(--border); }
    .roster__row { grid-template-columns: 11rem 1fr; gap: 28px; }
  }
  @media (max-width: 760px) {
    .pts { grid-template-columns: 1fr; gap: 28px; }
    .facts { grid-template-columns: 1fr; margin-bottom: 40px; }
    .facts > div { border-left: 0; }
    .facts > div + div { border-top: 1px solid var(--border); }
    /* The label sits above its list rather than beside it; at this width a
       14rem gutter leaves the names in a four-word-wide ribbon. */
    .roster__row { grid-template-columns: 1fr; gap: 12px; padding: 20px 0; }
    .roster__label { margin-top: 0; }
    /* Stacked, the vertical divider becomes a horizontal one -- the two
       halves still have to read as a question and its answer. */
    .flt__row { grid-template-columns: 1fr; padding: 16px 18px; }
    .flt__sym { padding-right: 0; }
    .flt__why { margin-top: 12px; padding: 12px 0 0;
                border-left: 0; border-top: 1px solid var(--border); }
    .crumbs { margin-bottom: 18px; }
    .hero__note { max-width: none; }
  }

  /* =====================================================================
     VARIANT B BLOCKS
     Used only by build_brand_page_alt.py, which lays the same content out
     the way highendrepairtechs.com does: a centred hero with no form, a
     badge rail, an availability strip, named faults as a link grid, and an
     explicit contact block. Same tokens, same type, different page.
     ===================================================================== */

  .vhero { position: relative; overflow: hidden; background: var(--foreground); }
  .vhero__bg { position: absolute; inset: 0; }
  .vhero__bg img { width: 100%; height: 100%; object-fit: cover; }
  .vhero__bg::after { content: ""; position: absolute; inset: 0;
    background: linear-gradient(to bottom, rgba(var(--scrim),0.62) 0%,
                rgba(var(--scrim),0.80) 55%, rgba(var(--scrim),0.94) 100%); }
  .vhero__in { position: relative; max-width: 980px; margin: 0 auto;
               padding: calc(var(--header-h) + 72px) 32px 64px; text-align: center;
               color: var(--background); }
  .vhero__pin { display: inline-flex; align-items: center; gap: 8px;
                border: 1px solid rgba(252,250,244,0.25); border-radius: var(--pill);
                padding: 7px 16px; font-size: 12px; font-weight: 600;
                letter-spacing: 0.14em; text-transform: uppercase;
                color: rgba(252,250,244,0.88); }
  .vhero__pin svg { width: 15px; height: 15px; color: var(--brand-glow); }
  .vhero h1 { margin: 24px 0 0; font-size: clamp(34px, 5vw, 58px); }
  .vhero__rate { display: inline-flex; align-items: center; gap: 12px; margin-top: 22px;
                 font-size: 15px; color: rgba(252,250,244,0.86); }
  /* fill, not just color: the icon set draws with stroke by default, so a
     star that only sets `color` renders as an outline. Every other star on
     the site sets both; this one had not. */
  .vhero__rate .s { display: inline-flex; gap: 2px; }
  .vhero__rate .s svg { width: 17px; height: 17px;
                        color: var(--brand-glow); fill: var(--brand-glow); }
  .vhero__rate b { color: var(--background); font-weight: 700; }
  .vhero__sub { margin: 20px auto 0; max-width: 40rem; font-size: 18px; line-height: 1.7;
                color: rgba(252,250,244,0.8); }
  .vhero__cta { display: flex; justify-content: center; flex-wrap: wrap; gap: 12px;
                margin-top: 32px; }

  /* The badge rail. Four promises, equal weight, no card -- they sit on the
     hero's own ground with hairlines between them. */
  .badges { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0;
            margin-top: 48px; border-top: 1px solid rgba(252,250,244,0.16);
            border-bottom: 1px solid rgba(252,250,244,0.16); }
  .badges > div { padding: 22px 18px; text-align: center;
                  border-left: 1px solid rgba(252,250,244,0.12); }
  .badges > div:first-child { border-left: 0; }
  .badges svg { width: 20px; height: 20px; color: var(--brand-glow); margin: 0 auto 10px; }
  .badges b { display: block; font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
              font-size: 14.5px; font-weight: 600; color: var(--background);
              letter-spacing: -0.01em; }
  .badges small { display: block; margin-top: 5px; font-size: 12px;
                  color: rgba(252,250,244,0.6); }

  /* Availability strip. One job: make the next step obvious at the exact
     point someone has finished reading the hero. */
  .avail { background: var(--secondary); border-bottom: 1px solid var(--border); }
  .avail__in { max-width: 1280px; margin: 0 auto; padding: 20px 32px;
               display: flex; flex-wrap: wrap; align-items: center;
               justify-content: center; gap: 14px 22px; text-align: center; }
  .avail__dot { width: 9px; height: 9px; border-radius: 50%; background: #2f9e55;
                box-shadow: 0 0 0 4px rgba(47,158,85,0.18); flex: none; }
  .avail b { font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
             font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
  .avail span { color: var(--muted-fg); font-size: 15px; }

  /* Breadcrumb on a light ground -- the hero version is tuned for the dark. */
  .crumbs--light { margin: 0; padding: 18px 0; }
  .crumbs--light .crumbs__up { color: var(--muted-fg); }
  .crumbs--light .crumbs__up:hover { color: var(--brand-deep); }
  .crumbs--light .crumbs__sep { color: rgba(44,32,23,0.25); }
  .crumbs--light .crumbs__here { color: var(--foreground); }
  /* Cream, and deliberately borderless: the services band directly below
     is the same ground, so a rule here would draw a line across the page
     for no reason other than that the markup changed. */
  .crumbrail { background: var(--background); }
  .crumbrail .wrap { padding-top: 26px; }

  .vhero__h2 { margin: 44px 0 0; font-size: clamp(20px, 2.2vw, 26px);
               color: var(--background); }
  .vhero__kicker { margin: 10px 0 0; font-size: 15px;
                   color: rgba(252,250,244,0.72); }
  .avail__h { margin: 0; font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
              font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }

  /* The ZIP block. Real data out of region.ZIPS_BY_AREA, so the count in the
     heading is derived from the list beneath it and cannot drift. */
  .zips { margin-top: 44px; padding-top: 32px; border-top: 1px solid var(--border); }
  .zips__h { display: flex; align-items: center; gap: 10px; margin: 0 0 18px;
             font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
             font-size: 12px; font-weight: 600; letter-spacing: 0.14em;
             text-transform: uppercase; color: var(--muted-fg); }
  .zips__h span { display: inline-flex; align-items: center; justify-content: center;
                  min-width: 24px; height: 20px; padding: 0 7px;
                  border-radius: var(--pill); background: var(--card);
                  border: 1px solid var(--border);
                  font-size: 11px; letter-spacing: 0.04em; color: var(--brand-deep); }
  .zips__grid { display: flex; flex-wrap: wrap; gap: 7px; }
  .zips__grid span { padding: 6px 11px; border-radius: var(--r-md);
                     background: var(--card); border: 1px solid var(--border);
                     font-size: 13px; font-variant-numeric: tabular-nums;
                     color: var(--muted-fg); }

  .bookfacts { display: grid; gap: 12px; margin-top: 30px; padding-top: 26px;
               border-top: 1px solid var(--border); }
  .bookfacts div { display: flex; align-items: center; gap: 10px;
                   font-size: 14.5px; color: var(--muted-fg); }
  .bookfacts svg { width: 18px; height: 18px; color: var(--brand-deep); }

  /* ---- the content shell ----
     The reference runs its local content in two columns: a sticky rail
     carrying the availability card, and the content beside it. The rail is
     the reason that page always has a phone number on screen while you read
     the faults, which is the whole point of it. Only the local sections sit
     in the shell; the why / steps / contact / FAQ bands below stay
     full-bleed, so the page still has its rhythm. */
  .shellwrap { background: var(--background); }
  .shell { display: grid; grid-template-columns: 300px 1fr; gap: 40px;
           align-items: start; padding: 44px 0 64px; }
  .rail { position: sticky; top: calc(var(--header-h) + 20px); }
  .rail__card { border: 1px solid var(--border); border-radius: var(--r-xl);
                background: var(--card); padding: 28px 24px; text-align: center;
                box-shadow: var(--shadow-panel); }
  .rail__av { position: relative; width: 86px; height: 86px; margin: 0 auto 18px; }
  /* A copper disc, not a photograph. We have no headshot, and generating a
     stranger's face to label "your technician" is the same class of thing as
     an invented review. The live dot carries the meaning on its own. */
  .rail__disc { display: flex; align-items: center; justify-content: center;
                width: 100%; height: 100%; border-radius: 50%;
                background: var(--gradient-brand); color: var(--on-brand);
                box-shadow: var(--shadow-brand-sm); }
  .rail__disc svg { width: 32px; height: 32px; }
  .rail__dot { position: absolute; right: 4px; bottom: 4px; width: 16px; height: 16px;
               border-radius: 50%; background: #2f9e55; border: 3px solid var(--card); }
  .rail__card h3 { margin: 0 0 10px; font-size: 19px; line-height: 1.25; }
  .rail__card p { margin: 0 0 18px; font-size: 14.5px; line-height: 1.6;
                  color: var(--muted-fg); }
  .rail__card .btn { width: 100%; justify-content: center; }
  .rail__facts { display: grid; gap: 10px; margin-top: 20px; padding-top: 18px;
                 border-top: 1px solid var(--border); text-align: left; }
  .rail__facts div { display: flex; align-items: center; gap: 9px; font-size: 13.5px;
                     color: var(--muted-fg); }
  .rail__facts svg { width: 16px; height: 16px; color: var(--brand-deep); }

  /* A block inside the shell. Bordered rather than full-bleed, because at
     this width a band would read as a stripe instead of a section. */
  /* No border. The blocks are separated by their ground and by space; a
     hairline around each one turned the column into a stack of boxes. */
  .blk { border-radius: var(--r-xl); background: transparent;
         padding: 8px 0 44px; margin-bottom: 8px; }
  /* Same ground as its neighbours. A beige fill on one of three blocks made
     it a box inside a column that has no other boxes in it. */
  .blk--muted { background: transparent; padding: 8px 0 44px; margin-bottom: 8px; }
  .blk h2 { font-size: clamp(26px, 2.8vw, 34px); margin-bottom: 14px; }
  .blk__lede { margin: 0 0 28px; font-size: 16px; line-height: 1.75;
               color: var(--muted-fg); }

  /* Compact appliance cards: icon, name, one line. The whole card is the
     link, so there is no separate CTA to repeat eight times. */
  .mini { display: grid; grid-template-columns: repeat(2, 1fr); gap: 14px; }
  .mini a, .mini > div { display: block; border: 1px solid var(--border);
            border-radius: var(--radius); background: var(--background);
            padding: 22px 22px 20px; text-decoration: none; color: inherit;
            transition: border-color .2s; }
  .mini a:hover { border-color: rgba(219,147,56,0.55); }
  .mini svg { width: 22px; height: 22px; color: var(--brand); }
  .mini h3 { margin: 16px 0 8px; font-size: 17px; }
  .mini a:hover h3 { color: var(--brand-deep); }
  .mini p { margin: 0; font-size: 14px; line-height: 1.6; color: var(--muted-fg); }

  /* Faults as chevron rows on hairlines, two across. Quieter than a field
     of bordered pills, and it reads as a list rather than as controls. */
  .frows { display: grid; grid-template-columns: repeat(2, 1fr); gap: 0 36px; }
  .frows > * { display: flex; align-items: flex-start; gap: 12px; padding: 14px 2px;
               border-bottom: 1px solid var(--border); font-size: 15.5px;
               line-height: 1.45; color: var(--foreground); }
  .frows svg { width: 15px; height: 15px; margin-top: 3px; color: var(--brand); }

  /* Areas as a three-across pin list. */
  .pins { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px 28px; }
  .pins > * { display: flex; align-items: flex-start; gap: 10px; padding: 9px 2px;
              font-size: 15px; line-height: 1.45; color: var(--foreground);
              text-decoration: none; }
  .pins svg { width: 15px; height: 15px; margin-top: 3px; color: var(--brand); }
  /* A live city page looks different from one that is not built yet --
     otherwise the two are indistinguishable until you hover, and only one
     of them does anything. */
  .pins a { font-weight: 600; }
  .pins a span { border-bottom: 1px solid rgba(219,147,56,0.45); }
  .pins a:hover, .pins a:hover svg { color: var(--brand-deep); }
  .pins a:hover span { border-bottom-color: var(--brand-deep); }

  /* The "call us and we will check" box that closes each block. */
  .callout { margin-top: 28px; padding: 20px 24px; border-radius: var(--radius);
             background: var(--secondary); border: 1px solid rgba(230,222,212,0.9);
             font-size: 15px; line-height: 1.7; color: var(--foreground); }

  /* The city-page coverage column: three labelled groups instead of one
     grid of thirty-three chips. */
  .loc { display: grid; gap: 34px; align-content: start; }
  .loc__grp .zips__h { margin-bottom: 14px; }
  .loc__all { display: inline-block; margin-top: 16px; font-size: 14.5px; }
  .areas__grid--near { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; }
  @media (max-width: 760px) { .areas__grid--near { grid-template-columns: 1fr; } }

  .ziphead { margin: 34px 0 14px; font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
             font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }

  @media (max-width: 1023px) {
    .shell { grid-template-columns: 1fr; gap: 28px; padding-top: 28px; }
    /* Unstuck and first: on a phone a 300px rail below the content is a
       phone number nobody scrolls back up to. */
    .rail { position: static; }
    .pins { grid-template-columns: repeat(2, 1fr); }
  }
  @media (max-width: 760px) {
    .blk { padding: 4px 0 32px; }
    .mini { grid-template-columns: 1fr; }
    .frows { grid-template-columns: 1fr; }
    .pins { grid-template-columns: 1fr; }
  }

  /* Named faults as a grid of links. This is the other way to build the
     block: the symptom-to-cause table explains, this one enumerates. It is
     what someone who already knows their fault name is scanning for. */
  .faults { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
  .faults a, .faults span { display: flex; align-items: center; gap: 12px;
            padding: 16px 18px; border: 1px solid var(--border);
            border-radius: var(--radius); background: var(--card);
            font-size: 15px; line-height: 1.4; color: var(--foreground);
            text-decoration: none; transition: border-color .18s, color .18s; }
  .faults a:hover { border-color: var(--brand); color: var(--brand-deep); }
  .faults i { width: 7px; height: 7px; border-radius: 50%; flex: none;
              background: var(--brand); }

  /* Four reasons across, no photograph. The main page spends a tall dark
     band on this; here it is a quiet row. */
  .pts--4 { grid-template-columns: repeat(4, 1fr); gap: 32px; }

  .contact { display: grid; grid-template-columns: repeat(3, 1fr);
             border: 1px solid var(--border); border-radius: var(--r-xl);
             background: var(--card); overflow: hidden; }
  .contact > div { padding: 26px 28px; border-left: 1px solid var(--border); }
  .contact > div:first-child { border-left: 0; }
  .contact__k { display: block; font-family: 'Sora', ui-sans-serif, system-ui, sans-serif;
                font-size: 11px; font-weight: 600; letter-spacing: 0.14em;
                text-transform: uppercase; color: var(--muted-fg); margin-bottom: 10px; }
  .contact__v { font-size: 15.5px; line-height: 1.6; color: var(--foreground); }
  .contact__v a { font-weight: 600; color: var(--brand-deep); }
  .contact__note { margin-top: 22px; font-size: 14.5px; line-height: 1.7;
                   color: var(--muted-fg); }

  .crosslinks { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 28px; }

  @media (max-width: 1023px) {
    .faults { grid-template-columns: repeat(2, 1fr); }
    .pts--4 { grid-template-columns: repeat(2, 1fr); }
    .badges { grid-template-columns: repeat(2, 1fr); }
    .badges > div:nth-child(2n+1) { border-left: 0; }
    .badges > div:nth-child(n+3) { border-top: 1px solid rgba(252,250,244,0.12); }
    .contact { grid-template-columns: 1fr; }
    .contact > div { border-left: 0; }
    .contact > div + div { border-top: 1px solid var(--border); }
  }
  @media (max-width: 760px) {
    .vhero__in { padding-top: calc(var(--header-h) + 36px); padding-bottom: 44px; }
    .faults { grid-template-columns: 1fr; }
    .pts--4 { grid-template-columns: 1fr; }
    .vhero__cta .btn { width: 100%; }
  }
