/* ==========================================================================
   KITCHEN HEARTH — shared tokens + components
   Extracted from kitchentuneup.com (captured 2026-08-28; Optimizely/Episerver
   CMS, one 478 KB theme stylesheet plus a customised Bootstrap 4.1.3 and
   EPiServerForms.css). Kitchen Tune-Up, a Home Franchise Concepts brand:
   one national site, ~162 franchise microsites, two locale mirrors.

   PHASE 2 CORRECTIONS, three of them, all from the gap between declared CSS
   and rendered pixels.

   1. THE THIRD, FOURTH AND FIFTH COLOURS BY DECLARATION COUNT DO NOT EXIST.
      #336972 (725 declarations), #223e42 (725), #2d5b60 (599) and #1a2e30
      (599) are the fills of a decorative inline SVG that ships in the markup
      of 408 of 411 crawled pages inside a group whose own class sets
      display:none. The live probe renders ZERO elements of any of them on
      five page templates, and none appears in a single rule of the theme
      stylesheet. The first read of this site named the kit for that teal.
      The system that actually paints is warm: amber CTA, burnt-orange link,
      warm-taupe ink, warm off-white bands.

   2. THE DISPLAY FACE IS DECLARED AND NEVER LOADED. Every heading names
      "Source Serif Pro"; there is no @font-face for it anywhere in the corpus
      and it is absent from the site's Google Fonts request, so every heading
      on the live site renders in Times. Source Serif 4 is the current release
      of the same family and free on Google Fonts, so the substitute IS the
      declared intent. Metrics are re-tuned to it (see --lead-display).

   3. THE GOOGLE FONTS REQUEST LOADS NINE FAMILIES AND RENDERS ONE. Cormorant,
      DM Serif Display, Lexend Deca, Lora, Merriweather, Open Sans, Oswald and
      Roboto are the shared Home Franchise Concepts multi-brand payload. Only
      Nunito Sans paints. Reading the head would have produced a nine-family
      system.

   THE IDENTITY is warmth and proportion, not geometry. The signature-shape
   sweep returned only vendor widgets: no clip-path, no mask, no hard-stop
   gradient, no pill. 130 of 143 painted boxes render at 0px radius. What
   carries the brand is a 3px hard border, a square corner, a soft grey
   shadow, a full-bleed photo band, and a body leading of 2em.

   TWO COLOUR DEPARTURES, both declared. (1) The source's primary CTA is white
   on #f7921e at 2.31:1; this kit ships ink #292929 on the same orange at
   6.29:1, which is what the probe already measures on the rendered buttons.
   (2) The hero teaser and the standalone generic-hero headline carry white
   plus the source's own black halo where the source paints #8b827a, because
   #8b827a is the ink this kit reserves for 38px and above and those two render
   below it. Both recorded in brand-spec.md section 5, transcribe-don't-clone.

   ONE KNOWN AA FAILURE, declared, not fixed. .btn-deep is white on #de4e12 at
   4.035:1 on an 18px/700 label, which WCAG counts as normal text. The pair is
   the source's own and no ink clears 4.5:1 on that fill. Open decision, stated
   in brand-spec.md section 14. The QC contrast gate cannot see it: it scores
   only below 3.0.

   ONE INVENTION, declared. The source ships no distinct focus ring. An
   accessible one is authored below. Nothing else in this file is invented.
   Two more inventions were found here later and removed rather than declared:
   a hairline #d8d4d0 that exists in none of the 424 crawled files (now the
   source's own #cccac6), and a white recolour of the wordmark, which existed
   only to sit on a dark footer the source does not have.

   THE PACKET IS AN INVENTORY, NOT A CONSTRUCTION SPEC. Five of this file's
   worst defects came from transcribing the Gate A packet's prose instead of
   the source rule: an "orange panel" that is really a white card with a 12px
   orange rule; a hero "scrim" that is really a black ground the photo covers;
   a footer built on #312e2b, a hex the corpus declares as a background zero
   times, where the source's footer is white with one #edebea row; a portfolio
   card that dimmed the PHOTOGRAPH to .72 and welded a dark caption over it,
   where the source puts .7 on a white-ground caption BELOW the image; and a
   warm-band ink correction written for <p> alone that left every <li> and the
   arrow link on the failing pair. Every one of them is settled by a grep.
   Open the rule in _crawl/css/ before you write the component.
   ========================================================================== */

@import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600;700;800&family=Source+Serif+4:opsz,wght@8..60,400;8..60,600&display=swap');

:root {
  /* COLOR — ink. Four registers, all rendered, each with a job.
     --ink is the default UI text (81 to 129 elements per template).
     --ink-deep is the button label ink and the contrast fix on orange.
     --ink-espresso is the deepest ink and the heading colour below 38px.
     --body is the real body-copy ink, set as the colour of every p across
     the whole site: 80 elements, rank 1 by element count. */
  --ink: #3a3a3a;
  --ink-deep: #292929;
  --ink-espresso: #312e2b;
  --body: #736c64;
  --ink-quiet: #8b827a;        /* doc chrome only, never body copy */

  /* COLOR — display ink. #8b827a paints every h1 to h6 on the source and
     measures 3.77:1 on white: sound for the 38px and 50px display sizes,
     not for anything smaller. Reserved for >= 38px here; --ink-espresso
     (13.49:1) carries every heading below that. */
  --display-ink: #8b827a;

  /* COLOR — brand. #f7921e is the primary CTA fill and the social icon fill;
     #f8981d is the rendered button fill and the exact orange of the logo
     mark; #de4e12 is the secondary fill, every button border and every
     button hover label; #cb4810 is the body link and the arrow-link. */
  --accent: #f7921e;
  --accent-alt: #f8981d;
  --accent-deep: #de4e12;
  --link: #cb4810;
  --accent-soft: rgba(247, 146, 30, .14);

  /* COLOR — grounds. --band-warm is rank 2 by painted area (933,924 px2):
     the alternating section band, the card header and the accordion header.
     --slate is the promo band. --scrim is the hero photo ground, rank 3 by
     painted area at 576,000 px2. */
  --paper: #ffffff;
  --band-warm: #edebea;
  --band-cool: #f3f3f3;
  --stone: #d6d2c4;
  --slate: #4f5c7e;
  --navy: #283f5d;
  /* The source's own hero ground, background-color #000 on .slider-hero. It
     sits UNDER an opaque background-size:cover photograph, so on the live site
     it paints nothing; it is the load-time and letterbox ground, and the ground
     the contrast walker resolves for the white hero copy. It is NOT a wash over
     the photo, and this kit does not use it as one.
     NO BRACES IN THIS BLOCK: palette-audit reads :root with a non-greedy regex
     that stops at the first close brace, so a brace inside a comment here hides
     every token below it from the gate. Quote source rules without them. */
  --scrim: #000000;
  /* The consultation card's notch: border-top 50px solid #7b716b on
     .form-offer-ihc .arrow. One declaration on the site, one use here. */
  --notch: #7b716b;

  /* COLOR — on-dark text */
  --on-dark: #ffffff;
  --on-dark-muted: rgba(255, 255, 255, .88);
  --on-dark-quiet: rgba(255, 255, 255, .72);

  /* COLOR — rules. #cccac6 is the source's own 1px hairline: it draws the
     site header's bottom edge, the search and form-offer field borders, the
     project-gallery filter chips and the review-modal separator. It was
     briefly shipped here as #d8d4d0, a value that appears in ZERO of the 424
     crawled files in any notation, which made a hairline the kit's second
     invention without declaring it. Verify with a grep before changing it. */
  --border: #cccac6;
  --border-soft: rgba(49, 46, 43, .14);

  /* TYPE. Nunito Sans is the source's own family, already free and already
     loaded. Source Serif 4 substitutes for the declared, never-loaded Source
     Serif Pro; the fallback stack keeps Times last so the substitution is
     visible rather than silent. */
  --font-display: 'Source Serif 4', 'Source Serif Pro', Georgia, 'Times New Roman', serif;
  --font-body: 'Nunito Sans', system-ui, -apple-system, 'Helvetica Neue', sans-serif;

  /* TYPE — fluid ramp. Desktop targets measured at 1440:
     hero 50 / h2 38 / h3 24 / h4 18 / lede 18 / body 16 / small 13.
     LEADING RE-TUNED to Source Serif 4, which has a taller x-height and
     looser sidebearings than the Times the source actually renders in:
     hero 1.06 -> 1.12, h2 1.26 -> 1.22. Logged in brand-spec.md. */
  --text-display: clamp(2rem, 2.9vw + 1.1rem, 3.125rem);
  --text-h2: clamp(1.6rem, 1.9vw + 1rem, 2.375rem);
  --text-h3: clamp(1.25rem, .6vw + 1.05rem, 1.5rem);
  --text-h4: 1.125rem;
  --text-lede: clamp(1.0625rem, .35vw + .98rem, 1.1875rem);
  --text-small: .875rem;
  --text-fine: .8125rem;
  --lead-display: 1.12;
  --lead-h2: 1.22;
  --lead-body: 2;              /* the source's single most distinctive choice */

  /* SPACE */
  --gap: 24px;
  --gutter: 2rem;
  --section: 84px;
  --section-sm: 52px;
  --section-lg: 112px;
  --maxw: 1280px;             /* the source's own module wrapper max-width */

  /* SHAPE — the system is square. 130 painted boxes at 0px, pillCount 0.
     The one non-zero register is the 2px the source puts on form fields. */
  --radius: 0;
  --radius-sm: 2px;
  --radius-disc: 50%;

  /* The source's button and card shadow, soft and low, never coloured. */
  --shadow: 0 3px 6px rgba(0, 0, 0, .16);
  --shadow-soft: 0 1px 9px rgba(0, 0, 0, .16);
  --shadow-panel: 0 8px 16px rgba(0, 0, 0, .15);

  --t-fast: 150ms;            /* the source's transition: all .15s linear */
  --ease: linear;
}

/* ==== base ============================================================== */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: var(--lead-body);
  color: var(--body);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, .h1, .h2, .h3, .h4, .display {
  font-family: var(--font-display);
  color: var(--ink-espresso);
  font-weight: 400;
  margin: 0 0 .5em;
  line-height: var(--lead-h2);
  overflow-wrap: break-word;
}

h1, .h1, .display {
  font-size: var(--text-display);
  line-height: var(--lead-display);
}
h2, .h2 { font-size: var(--text-h2); }
h3, .h3 { font-size: var(--text-h3); }
h4, .h4 { font-size: var(--text-h4); font-weight: 600; }

/* THE DISPLAY TAUPE IS A SIZE RULE, NOT A TAG RULE. #8b827a measures 3.77:1
   on white, which is sound at display scale and fails AA below it. Every
   heading therefore starts on --ink-espresso (13.49:1, set on the shared rule
   above) and the taupe is handed BACK only at widths where the heading is
   certainly 38px or larger.

   TWO RAMPS DECIDE THE RENDERED SIZE, not one. ../mobile-responsive.css is
   linked after this file and retunes headings at <=768px, so the arithmetic
   has to cover both regimes:

     <=768px   h1 clamp(34px, 9vw, 52px)             38px from 422.2px
               h2 clamp(26px, 7vw, 38px)             38px from 542.9px
     >=769px   h1 clamp(32px, 2.9vw + 17.6px, 50px)  39.9px at 769, never less
               h2 clamp(25.6px, 1.9vw + 16px, 38px)  38px from 1157.9px

   So h1 is >=38px everywhere from 423px up, in both regimes: one query, exact.
   h2 is not monotonic across the seam (38px at 543-768, back to 30-37px from
   769 to 1157), and encoding that would both couple this file to another
   file's breakpoint and make the heading colour flip twice on the way out.
   The rule is a RESTRICTION -- taupe at 38px and above only -- so the
   conservative single query satisfies it: h2 is espresso from 543 to 1157
   even where it is briefly 38px. Deliberate. Do not "tidy" it into a second
   query without re-reading this.

   Built as a tag test rather than a size test, this rule shipped #8b827a on
   18px and 20px headings. Any h2 that a component sizes DOWN re-asserts the
   espresso ink locally (.longform, .article, .featured-blog, .share-row), so
   a component override can never re-enter the taupe by inheritance. */
@media (min-width: 423px)  { h1, .h1, .display { color: var(--display-ink); } }
@media (min-width: 1158px) { h2, .h2 { color: var(--display-ink); } }

/* THE ONE h1 THE ARITHMETIC ABOVE CANNOT COVER. ../mobile-responsive.css:492
   sets `.sx-header h1 { font-size: 18px }` inside its <=768px block, so the
   catalog's own page title renders 18px between 423px and 768px, where the
   query above has already handed h1 the taupe: 3.77:1 on an 18px heading.
   It is the same "a component sized this heading DOWN, so it re-asserts the
   espresso ink locally" case as .longform and .share-row; the override just
   has to live here because the size comes from the shared stylesheet rather
   than from a rule in this file. Scoped to the same width band, so the title
   keeps the display taupe from 769px up, where it is 38px or larger. */
@media (max-width: 768px) { .sx-header h1 { color: var(--ink-espresso); } }

p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }
a { color: inherit; }

.lede { font-size: var(--text-lede); line-height: 1.75; color: var(--body); }
.small { font-size: var(--text-small); }
.fine { font-size: var(--text-fine); line-height: 1.7; color: var(--ink); }
.terms-note { font-size: var(--text-fine); line-height: 1.7; color: var(--ink); }

img { max-width: 100%; height: auto; display: block; }

/* Scaffolding copy this kit authors rather than transcribes. Declared in the
   markup so verbatim-audit.py can strip it: see house-format.md. */
.kit-note {
  font-size: var(--text-fine);
  line-height: 1.7;
  color: var(--ink);
  font-style: italic;
}

/* Screen-reader-only label, used on the form and search fields the source
   labels with a placeholder alone. */
.show-for-sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* THE ONE INVENTION. The source ships no distinct focus ring: it reuses the
   hover inversion, and Bootstrap's stock focus blue paints nowhere. */
:focus-visible { outline: 3px solid var(--accent-deep); outline-offset: 2px; }
.on-dark :focus-visible { outline-color: var(--accent); }

/* ==== layout ============================================================ */
.container { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter); }
.container-narrow { width: 100%; max-width: 860px; margin: 0 auto; padding: 0 var(--gutter); }

.section { padding: var(--section) 0; }
.section.tight { padding: var(--section-sm) 0; }
.section.wide { padding: var(--section-lg) 0; }
.section.alt { background: var(--band-warm); }
.section.cool { background: var(--band-cool); }

/* Body copy on the warm band. #736c64 measures 4.35:1 there, just under AA,
   so long-form prose steps up to --ink (9.57:1). Extraction-faithful in
   colour family, corrected in execution.

   THE CORRECTION IS PER-ELEMENT, SO IT HAS TO NAME EVERY ELEMENT THAT CARRIES
   PROSE, not just <p>. Written for p and .lede alone it left 19 list items and
   the uppercase arrow link rendering 4.35:1 on the band: the benefit lists in
   .alt-module, the .info-list rows in the franchise panel, and the "Read More
   Reviews" link in .featured-reviews. Any new prose element that can sit
   directly on .alt / .cool gets added to this selector list. */
.section.alt p, .section.cool p { color: var(--ink); }
.section.alt .lede, .section.cool .lede { color: var(--ink); }
.section.alt li, .section.cool li { color: var(--ink); }
.section.alt .link-arrow, .section.cool .link-arrow { color: var(--ink); }

.section-head { max-width: 860px; margin: 0 auto 2.75rem; text-align: center; }
.section-head.left { margin-left: 0; text-align: left; }

/* Dark register. Used by the promo band and the photo heroes. */
.on-dark { background: var(--ink-espresso); color: var(--on-dark-muted); }
.on-dark h1, .on-dark h2, .on-dark h3, .on-dark h4 { color: var(--on-dark); }
.on-dark p { color: var(--on-dark-muted); }
.on-dark .lede { color: var(--on-dark-muted); }
.on-dark a { color: var(--on-dark); }

/* ==== buttons ===========================================================
   Rendered geometry, straight off the source: height 48, padding 5px 35px,
   3px solid border, Nunito Sans 700 at 1.125rem/24px, transition all .15s
   linear. Three live variants; every dead Bootstrap .btn-* hover is left
   where it was found.

   THE ONE EXECUTION CHANGE: .btn-accent carries --ink-deep, not white. The
   source sets white on #f7921e at 2.31:1. ======================== */
.btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 5px 35px;
  font-family: var(--font-body); font-size: 1.125rem; font-weight: 700;
  line-height: 24px; text-align: center; text-decoration: none;
  border: 3px solid var(--accent-deep); border-radius: var(--radius);
  background: var(--paper); color: var(--ink);
  cursor: pointer; transition: all var(--t-fast) var(--ease);
}
.btn:hover { background: var(--paper); border-color: var(--accent-deep); color: var(--accent-deep); }

.btn-outline { background: var(--paper); border-color: var(--accent-deep); color: var(--ink); }
.btn-outline:hover { color: var(--accent-deep); }

.btn-accent { background: var(--accent); border-color: var(--paper); color: var(--ink-deep); }
.btn-accent:hover { background: var(--paper); border-color: var(--accent-deep); color: var(--accent-deep); }

.btn-deep { background: var(--accent-deep); border-color: var(--paper); color: var(--on-dark); }
.btn-deep:hover { background: var(--paper); border-color: var(--accent-deep); color: var(--accent-deep); }

.btn-sm { min-height: 38px; padding: 4px 20px; font-size: .9375rem; border-width: 2px; }
.btn-block { width: 100%; }

.actions { display: flex; flex-wrap: wrap; gap: 14px; }
.actions.center { justify-content: center; }

/* The source's uppercase arrow link, .875em weight 700 on --body. Kept as a
   text link rather than promoted to a button, which is how it renders. */
.link-arrow {
  display: inline-flex; align-items: center; gap: .45em;
  font-size: .875rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .02em; color: var(--body); text-decoration: none;
}
.link-arrow::after { content: '\203A'; font-size: 1.3em; line-height: 1; }
.link-arrow:hover { color: var(--link); text-decoration: underline; }

.body-link { color: var(--link); text-decoration: underline; }
.body-link:hover { color: var(--accent-deep); }

/* ==== 01 utility bar ==================================================== */
.utility-bar { background: var(--band-cool); border-bottom: 1px solid var(--border); }
.utility-bar > .container {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 10px 22px; padding-top: 8px; padding-bottom: 8px;
}
.utility-bar .u-left, .utility-bar .u-right { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 20px; min-width: 0; }
.utility-bar .u-link { font-size: var(--text-small); font-weight: 700; color: var(--ink); text-decoration: none; }
.utility-bar .u-link:hover { color: var(--link); text-decoration: underline; }
.utility-bar .u-lang { display: flex; gap: 12px; font-size: var(--text-small); color: var(--ink); }
.utility-bar .u-lang a { text-decoration: none; }
.utility-bar .u-lang a:hover { color: var(--link); text-decoration: underline; }
.utility-bar .u-phone {
  font-size: 1.0625rem; font-weight: 800; color: var(--ink-espresso); text-decoration: none;
}
.utility-bar .u-phone:hover { color: var(--link); }

/* ==== 02 primary nav (house Pattern D) ================================== */
.nav { background: var(--paper); border-bottom: 1px solid var(--border); position: relative; }
.nav > .container {
  display: flex; align-items: center; justify-content: space-between; gap: 20px;
  padding-top: 14px; padding-bottom: 14px;
}
.nav .brand-mark { display: flex; align-items: center; flex: 0 0 auto; }
.nav .brand-mark img { width: 190px; }
.nav .links { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 6px; flex: 1; min-width: 0; justify-content: flex-end; }
.nav .links > a {
  padding: 10px 9px; font-size: .8rem; font-weight: 700; letter-spacing: .8px;
  text-transform: uppercase; color: var(--body);
  text-decoration: none; transition: color var(--t-fast) var(--ease);
}
.nav .links > a:hover { color: var(--link); }
.nav .links > a.is-featured { background: var(--accent); color: var(--ink-deep); }
.nav .links > a.is-featured:hover { background: var(--accent-deep); color: var(--on-dark); }
.nav .actions { display: flex; align-items: center; gap: 10px; flex: 0 0 auto; }
@media (max-width: 768px) { .nav .actions { display: none; } }

/* The mega-subnav, transcribed as a static column set so the catalog can
   show what it holds. On the source it opens on hover. */
.subnav { background: var(--band-warm); border-bottom: 1px solid var(--border); }
.subnav > .container { padding-top: 26px; padding-bottom: 26px; }
.subnav .cols {
  display: grid; gap: 8px 32px;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
}
.subnav .cols > * { min-width: 0; }
.subnav ul { list-style: none; margin: 0; padding: 0; }
/* The band is --band-warm, so the row itself carries --ink, not --body: the
   li holds only an anchor today, but an inherited 4.35:1 sitting on the
   element is a defect waiting for the first bare word to be added. */
.subnav li { margin-bottom: .35em; line-height: 1.6; color: var(--ink); }
.subnav a { font-size: .9375rem; color: var(--ink); text-decoration: none; }
.subnav a:hover { color: var(--link); text-decoration: underline; }

/* ==== 03 zip locator ==================================================== */
.zip-locator { background: var(--band-warm); border-bottom: 1px solid var(--border); }
.zip-locator > .container {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px;
  padding-top: 16px; padding-bottom: 16px;
}
.zip-locator .zip-toggle {
  font-size: .9375rem; font-weight: 800; color: var(--ink-espresso);
  background: none; border: 0; padding: 0; cursor: pointer; font-family: var(--font-body);
}
.zip-locator .zip-form { display: flex; flex-wrap: wrap; gap: 10px; flex: 1; min-width: 0; }
.zip-locator input {
  flex: 1 1 200px; min-width: 150px; height: 48px; padding: 0 14px;
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--paper); border: 2px solid var(--navy); border-radius: var(--radius-sm);
}
.zip-locator .zip-note { font-size: var(--text-small); color: var(--ink); margin: 0; }
@media (max-width: 600px) {
  .zip-locator > .container { flex-direction: column; align-items: stretch; }
  .zip-locator .zip-form { flex-direction: column; }
  /* flex-basis is read along the MAIN axis, so `flex: 1 1 200px` becomes a
     200px-tall input the moment this row turns into a column. */
  .zip-locator .zip-form input { flex: 0 0 auto; }
  .zip-locator .zip-form .btn { width: 100%; }
}

/* ==== 04 slider hero ====================================================
   THE PHOTOGRAPH IS NOT DIMMED. The source runs its hero photo at full
   strength — .slider-hero__slide is background-repeat/position/size:cover and
   nothing else, and the theme stylesheet carries no :before or :after on it —
   and makes the white headline hold with a HALO, not a wash:
   .slider-hero__inner .generic-hero__headline{color:#fff;text-shadow:0 0 5px
   #000} and .slider-hero .generic-hero__teaser{text-shadow:0 0 3px #000}.
   That halo is transcribed below. The #000 ground is the source's own
   .slider-hero{background-color:#000}: it sits under an opaque cover photo, so
   it paints nothing, and it is what a slow connection and the contrast walker
   resolve. An earlier build stacked a 62% photo over that ground under a 28%
   flood and an 18->52% gradient, rendering a 212-mean photograph at 67-91.
   Three layers the source does not have. Do not reintroduce them. */
.slider-hero { position: relative; background-color: var(--scrim); overflow: hidden; }
.slider-hero .hero-bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover;
}
.slider-hero > .container {
  position: relative; z-index: 2; text-align: center;
  padding-top: 5.5rem; padding-bottom: 5.5rem;
}
.slider-hero .container h2 {
  color: var(--on-dark); text-shadow: 0 0 5px #000;
  margin-bottom: .35em; font-size: var(--text-display); line-height: var(--lead-display);
}
.slider-hero .container p { color: var(--on-dark); text-shadow: 0 0 3px #000; font-size: var(--text-lede); }
.slider-hero .actions { justify-content: center; margin-top: 1.6rem; }
/* The dots carry the source's own shadow, which is how white dots hold on an
   undimmed photo: .slider-hero .slick-dots li{background:#fff;box-shadow:
   1px 1px 3px rgba(0,0,0,.5)}. */
.slide-dots { display: flex; gap: 10px; justify-content: center; margin-top: 2rem; }
.slide-dots span {
  width: 10px; height: 10px; border-radius: var(--radius-disc);
  background: var(--on-dark-quiet); box-shadow: 1px 1px 3px rgba(0, 0, 0, .5);
}
.slide-dots span.on { background: var(--accent); }

/* ==== 05 generic hero ===================================================
   Same rule as the slider hero: the photograph runs at full strength.
   .generic-hero{background-repeat:no-repeat;background-position:50% 100%;
   background-size:cover} and no overlay layer anywhere in the theme.
   The headline ink is the one declared departure here — see brand-spec.md
   §5, "Photo-hero copy ink". The halo radius is the source's own. */
.generic-hero { position: relative; background-color: var(--scrim); overflow: hidden; }
.generic-hero .hero-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.generic-hero > .container { position: relative; z-index: 2; padding-top: 4.25rem; padding-bottom: 5.5rem; }
.generic-hero .container h1 { color: var(--on-dark); text-shadow: 0 0 5px #000; margin: 0; }

/* ==== 06 page banner (no photo) ========================================= */
.page-banner { background: var(--band-warm); border-bottom: 1px solid var(--border); }
.page-banner > .container { padding-top: 2.75rem; padding-bottom: 2.75rem; }
.page-banner h1 { margin: 0; }

/* ==== 07 breadcrumb ===================================================== */
.breadcrumb { border-bottom: 1px solid var(--border); }
.breadcrumb ol {
  display: flex; flex-wrap: wrap; gap: .4rem; list-style: none;
  margin: 0; padding: .9rem 0; font-size: var(--text-small);
}
.breadcrumb li { display: flex; align-items: center; }
.breadcrumb li + li::before { content: '/'; margin-right: .4rem; color: var(--ink-quiet); }
.breadcrumb a { color: var(--link); text-decoration: underline; }
.breadcrumb a:hover { color: var(--accent-deep); }
.breadcrumb [aria-current] { color: var(--ink); }

/* ==== 08 intro copy block =============================================== */
.intro-block { text-align: center; }
.intro-block .lede { max-width: 900px; margin: 0 auto; }

/* ==== 09 centred prose module =========================================== */
.prose-module { text-align: center; }
.prose-module h2 { margin-bottom: .5em; }
.prose-module p { max-width: 980px; margin-left: auto; margin-right: auto; }

/* ==== 10 long-form rich text ============================================ */
.longform { max-width: 860px; }
.longform h2 { font-size: var(--text-h3); color: var(--ink-espresso); margin-top: 2rem; }
.longform h2:first-child { margin-top: 0; }
.longform ul { padding-left: 1.2rem; }
.longform li { margin-bottom: .35em; }
.longform a { color: var(--link); text-decoration: underline; }
.longform .meta { font-size: var(--text-small); color: var(--ink); margin-bottom: 1.5rem; }

/* ==== 11 in-home consultation form ======================================
   NOT AN ORANGE BAND. The orange is a 12px RULE on a white card, never the
   ground. Straight off the source:

     .form-offer-ihc{position:relative;max-width:970px;z-index:99;
                     padding-top:0;margin-top:-25px}
     .form-offer-ihc .form-offer__inner{background-color:#fff;
                     border-top:#f8981d solid 12px;max-width:890px;
                     padding:40px 18px;box-shadow:0 .5rem 1rem rgba(0,0,0,.15)}
     .form-offer-ihc .arrow{border-left:40px solid transparent;
                     border-right:40px solid transparent;
                     border-top:50px solid #7b716b;
                     position:absolute;top:-10px;left:50%;
                     transform:translateX(-50%)}
     .slider-hero+.form-offer{margin-top:-40px}
     .generic-hero+.form-offer-ihc{margin-top:-60px}

   Five devices, all of them load-bearing: white card, 12px orange top rule,
   drop shadow, negative margin that lifts the card over the hero photo, and
   the grey notch straddling the rule. The overlap is scoped to the two heroes
   exactly as the source scopes it, so the catalog demo sits square. */
.consult-form {
  position: relative; z-index: 2;
  width: 100%; max-width: 970px; margin: 0 auto; padding: 0 var(--gutter);
}
.slider-hero + .consult-form { margin-top: -40px; }
.generic-hero + .consult-form { margin-top: -60px; }
.consult-form > .container {
  position: relative; max-width: 890px; padding: 40px 18px;
  background: var(--paper);
  border-top: 12px solid var(--accent-alt);
  box-shadow: var(--shadow-panel);
}
.consult-form .form-notch {
  position: absolute; top: -10px; left: 50%; transform: translateX(-50%);
  width: 0; height: 0; z-index: 1;
  border-left: 40px solid transparent; border-right: 40px solid transparent;
  border-top: 50px solid var(--notch);
}
.consult-form h2 { color: var(--ink-deep); text-align: center; }
.consult-form .form-lede { color: var(--ink-deep); text-align: center; max-width: 760px; margin: 0 auto 1.75rem; }
.form-grid {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 14px;
  max-width: 860px; margin: 0 auto;
}
.form-grid > * { min-width: 0; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 880px) { .form-grid { grid-template-columns: 1fr; } }
.field { display: flex; flex-direction: column; gap: .3rem; }
.field input, .field select, .field textarea {
  width: 100%; min-width: 150px; height: 48px; padding: 0 14px;
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.field textarea { height: auto; min-height: 120px; padding: 12px 14px; resize: vertical; }
.form-step {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 16px; margin-top: 1.5rem;
}
.form-step .step-label { font-size: .9375rem; font-weight: 700; color: var(--ink-deep); }
.consult-form .terms-note { color: var(--ink-deep); max-width: 860px; margin: 1.4rem auto 0; text-align: center; }
.consult-form .call-now { display: block; text-align: center; margin-top: 1rem; font-weight: 800; color: var(--ink-deep); }

/* ==== 12 field callout row ============================================== */
.callout-field {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  background: var(--band-warm); border: 1px solid var(--border);
  padding: 16px 18px;
}
.callout-field .cf-prompt { font-size: .9375rem; font-weight: 700; color: var(--ink); margin: 0; flex: 0 0 auto; }
.callout-field input {
  flex: 1 1 220px; min-width: 150px; height: 48px; padding: 0 14px;
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--border); border-radius: var(--radius-sm);
}

/* ==== 13 reviews slider ================================================= */
.review-rail {
  display: grid; gap: var(--gap);
  grid-auto-flow: column; grid-auto-columns: min(380px, 82vw);
  overflow-x: auto; scroll-snap-type: x mandatory;
  padding-bottom: 1rem;
}
.review-rail > * { scroll-snap-align: start; min-width: 0; }
.review-card {
  background: var(--paper); border: 1px solid var(--border);
  box-shadow: var(--shadow); padding: 1.9rem 1.7rem;
  display: flex; flex-direction: column;
}
.review-card h3 { font-size: var(--text-h3); margin-bottom: .55em; }
.review-card .quote { color: var(--body); margin-bottom: 1.1rem; line-height: 1.85; }
.review-card .name { font-size: .9375rem; font-weight: 800; color: var(--ink); margin-top: auto; }
.stars { display: flex; gap: 3px; margin-bottom: .9rem; }
.stars svg { width: 18px; height: 18px; fill: var(--accent); }

/* ==== 14 featured reviews rail (warm band) ============================== */
.featured-reviews .fr-head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 12px;
  margin-bottom: 2rem;
}
.featured-reviews .fr-head h2 { margin: 0; }
.fr-grid {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}
.fr-grid > * { min-width: 0; }
.fr-card { background: var(--paper); border: 1px solid var(--border); padding: 1.7rem; }
.fr-card p { color: var(--body); line-height: 1.85; }
.fr-card .name { font-size: .9375rem; font-weight: 800; color: var(--ink); }

/* Light-ground components inside a tinted band re-assert their own ink at
   +1 specificity. Register every new one here as it is written: the comment
   alone has failed before, on guardian-roofing's .judging-note. */
.section.alt .fr-card p, .section.cool .fr-card p { color: var(--body); }
.section.alt .review-card .quote, .section.cool .review-card .quote { color: var(--body); }
.section.alt .rl-card p, .section.cool .rl-card p { color: var(--body); }
.section.alt .swatch-card p, .section.cool .swatch-card p { color: var(--ink); }
.section.alt .svc-card .link-arrow, .section.cool .svc-card .link-arrow { color: var(--body); }
.section.alt .post-card .link-arrow, .section.cool .post-card .link-arrow { color: var(--body); }

/* A BUTTON IS A LIGHT-GROUND COMPONENT TOO, and this is the one that bit here.
   `.on-dark a` (0,1,1) outranks `.btn-accent` (0,1,0), so every filled amber
   button sitting in a photo hero inherited white and rendered at 2.31:1: the
   source's own defect, reintroduced through a section rule rather than a token.
   The QC contrast walker caught it on three pages at both widths. Re-assert the
   button's own ink at +1 specificity; never weaken the section rule. Any new
   light-ground control that lands inside .on-dark gets registered right here. */
.on-dark a.btn { color: var(--ink); }
.on-dark a.btn-accent { color: var(--ink-deep); }
.on-dark a.btn-outline { color: var(--ink); }
.on-dark a.btn-deep { color: var(--on-dark); }
.on-dark a.btn:hover,
.on-dark a.btn-accent:hover,
.on-dark a.btn-outline:hover,
.on-dark a.btn-deep:hover { color: var(--accent-deep); }

/* ==== 15 full review list + load more =================================== */
.rl-grid {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}
.rl-grid > * { min-width: 0; }
.rl-card { background: var(--paper); border: 1px solid var(--border); box-shadow: var(--shadow-soft); padding: 1.7rem; }
.rl-card h3 { font-size: 1.1875rem; }
.rl-card p { color: var(--body); line-height: 1.85; }
.rl-card .name { font-size: .9375rem; font-weight: 800; color: var(--ink); }
.rl-more { display: flex; justify-content: center; margin-top: 2.25rem; }

/* ==== 16 trustpoints slider ============================================= */
.tp-rail {
  display: grid; gap: var(--gap);
  grid-auto-flow: column; grid-auto-columns: min(300px, 82vw);
  overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 1rem;
}
.tp-rail > * { scroll-snap-align: start; min-width: 0; }
.tp-card { background: var(--paper); border: 1px solid var(--border); display: flex; flex-direction: column; }
.tp-card img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; }
.tp-card .body { padding: 1.5rem; text-align: center; }
.tp-card h3 { font-size: var(--text-h3); margin-bottom: .3em; }
.tp-card .claim, .svc-card .claim { font-weight: 800; color: var(--ink); margin-bottom: .6em; }
.tp-card p { font-size: .9375rem; line-height: 1.8; }

/* ==== 17 before / after compare ========================================= */
.before-after { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; }
.before-after > * { min-width: 0; }
.before-after .ba-half { position: relative; }
.before-after .ba-half img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.before-after .ba-half .tag {
  position: absolute; left: 0; bottom: 0;
  background: var(--ink-espresso); color: var(--on-dark);
  font-size: var(--text-small); font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; padding: 7px 14px;
}
@media (max-width: 880px) { .before-after { grid-template-columns: 1fr; } }
.ba-caption { max-width: 980px; margin: 1.75rem auto 0; text-align: center; }

/* ==== 18 services grid ================================================== */
.card-grid {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
}
/* The territory Trustpoints grid is the one grid the source pins to a row
   count: data-items-per-row="5" on <div class="grid__layout">. Every other
   .card-grid runs the default auto-fit. */
@media (min-width: 1100px) { .card-grid.five { grid-template-columns: repeat(5, minmax(0, 1fr)); } }
.card-grid > * { min-width: 0; }
.svc-card {
  background: var(--paper); border: 1px solid var(--border);
  display: flex; flex-direction: column; text-decoration: none;
}
.svc-card img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; }
.svc-card .body { padding: 1.5rem; }
.svc-card h3 { font-size: var(--text-h3); margin-bottom: .45em; }
.svc-card p { font-size: .9375rem; line-height: 1.8; color: var(--body); }
.svc-card .link-arrow { margin-top: 1rem; }
.section.alt .svc-card p, .section.cool .svc-card p { color: var(--body); }

/* ==== 19 alternating image / text module ================================ */
.alt-module { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center; }
.alt-module > * { min-width: 0; }
.alt-module img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.alt-module.flip .alt-media { order: 2; }
.alt-module h2 { margin-bottom: .45em; }
.alt-module .sub { font-weight: 800; color: var(--ink); margin-bottom: .6em; }
@media (max-width: 880px) {
  .alt-module { grid-template-columns: 1fr; gap: 1.75rem; }
  .alt-module.flip .alt-media { order: 0; }
}

/* ==== 20 generic CTA module ============================================= */
.generic-module { text-align: center; }
.generic-module p { max-width: 900px; margin-left: auto; margin-right: auto; }
.generic-module .actions { justify-content: center; margin-top: 1.75rem; }

/* ==== 21 FAQ accordion ================================================== */
.faq-stack { border-top: 1px solid var(--border); max-width: 980px; margin: 0 auto; }
.faq-item { border-bottom: 1px solid var(--border); }
.faq-item summary {
  display: flex; align-items: flex-start; justify-content: space-between; gap: 1.5rem;
  padding: 1.25rem 0; cursor: pointer; list-style: none;
  font-family: var(--font-display); font-size: var(--text-h3); color: var(--ink-espresso);
  line-height: 1.35;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after { content: '+'; font-family: var(--font-body); font-size: 1.6rem; line-height: 1; color: var(--link); }
.faq-item[open] summary::after { content: '\2013'; }
.faq-item .answer { padding-bottom: 1.4rem; }
.section.alt .faq-item .answer p { color: var(--ink); }

/* ==== 22 blog card rail ================================================= */
.post-rail {
  display: grid; gap: var(--gap);
  grid-auto-flow: column; grid-auto-columns: min(340px, 82vw);
  overflow-x: auto; scroll-snap-type: x mandatory; padding-bottom: 1rem;
}
.post-rail > * { scroll-snap-align: start; min-width: 0; }
.post-card { background: var(--paper); border: 1px solid var(--border); display: flex; flex-direction: column; }
.post-card img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }
.post-card .body { padding: 1.4rem; display: flex; flex-direction: column; flex: 1; }
.post-card h3 { font-size: 1.1875rem; margin-bottom: .5em; }
.post-card p { font-size: .9375rem; line-height: 1.8; color: var(--body); }
.post-card .link-arrow { margin-top: auto; padding-top: 1rem; }
.section.alt .post-card p, .section.cool .post-card p { color: var(--body); }

/* ==== 23 featured blog hero card ======================================== */
.featured-blog { display: grid; grid-template-columns: 1.15fr 1fr; gap: 2.5rem; align-items: center; }
.featured-blog > * { min-width: 0; }
.featured-blog img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; }
.featured-blog h2 { font-size: var(--text-h3); color: var(--ink-espresso); margin-bottom: .5em; }
.cat-tag {
  display: inline-block; background: var(--stone); color: var(--ink-espresso);
  font-size: var(--text-small); font-weight: 700; padding: 5px 14px; margin-bottom: 1rem;
}
@media (max-width: 880px) { .featured-blog { grid-template-columns: 1fr; gap: 1.5rem; } }

/* ==== 24 blog listing + category select ================================= */
.listing-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: 14px;
  border-bottom: 1px solid var(--border); padding-bottom: 1.25rem; margin-bottom: 2rem;
}
.listing-bar select {
  height: 48px; min-width: 220px; padding: 0 14px;
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.post-grid {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}
.post-grid > * { min-width: 0; }
.listing-more { display: flex; justify-content: center; margin-top: 2.5rem; }

/* ==== 25 blog detail ==================================================== */
.article { max-width: 860px; }
.article .byline { font-size: var(--text-small); color: var(--ink); margin-bottom: 1.5rem; }
.article h2 { font-size: var(--text-h3); color: var(--ink-espresso); margin-top: 2.2rem; }
.article h3 { font-size: 1.1875rem; margin-top: 1.8rem; }
.article ul { padding-left: 1.2rem; }
.article li { margin-bottom: .35em; }
.article a { color: var(--link); text-decoration: underline; }
.share-row { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; border-top: 1px solid var(--border); margin-top: 2.5rem; padding-top: 1.5rem; }
.share-row h2 { font-size: var(--text-h4); color: var(--ink-espresso); margin: 0; }
.social-row { display: flex; flex-wrap: wrap; gap: 10px; }
.social-row a {
  width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--ink-deep); text-decoration: none;
}
.social-row a:hover { background: var(--accent-deep); color: var(--on-dark); }
.social-row svg { width: 18px; height: 18px; fill: currentColor; }

/* ==== 26 portfolio category grid ========================================
   THE .7 OPACITY IS ON THE CAPTION, NOT ON THE PHOTOGRAPH, and the caption
   sits BELOW the image in normal flow on a white ground. Both facts come
   straight off /portfolio/:

     .col-grid__item-header { position:relative; overflow:hidden }
     .col-grid__item-img    { display:block; width:100%; height:346px;
                              background-size:cover }          <- no dim, no ground
     .col-grid__item-title  { width:100%; margin:0; padding:18px 12px 0;
                              font-family:"Nunito Sans"; font-weight:400;
                              text-align:center; opacity:.7;
                              color:#3a3a3a; background-color:#fff;
                              transition:opacity .25s linear }
     .col-grid__item-link:hover .col-grid__item-title { opacity:1 }

   Built from the packet's prose instead, this shipped as an espresso card
   with the photo dimmed to .72 and the label welded over its bottom edge in
   white: three inventions in one pattern, and #312e2b used as a ground when
   the corpus never once declares it as one.

   GEOMETRY is the source's own: two columns from 0, three from 64em, gaps
   10 / 15 / 20px, image 124 / 320 / 346px tall.

   THE CAPTION KEEPS THE SOURCE'S FONT-FAMILY OVERRIDE. It is an <h2> that
   the source resets to Nunito Sans, so it does not take --font-display, and
   it declares its own #3a3a3a, which also holds it out of the >=1158px
   display-taupe query the way every other sized-down heading does.
   .7 on #3a3a3a over white composites to #757575, 4.61:1. */
.cat-grid { display: grid; gap: 10px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (min-width: 40em) { .cat-grid { gap: 15px; } }
@media (min-width: 64em) { .cat-grid { gap: 20px; grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.cat-grid > * { min-width: 0; }
.cat-card { display: block; text-decoration: none; overflow: hidden; }
.cat-card img { width: 100%; height: 124px; object-fit: cover; }
@media (min-width: 40em) { .cat-card img { height: 320px; } }
@media (min-width: 64em) { .cat-card img { height: 346px; } }
.cat-card h2 {
  width: 100%; margin: 0; padding: 18px 12px 0;
  font-family: var(--font-body); font-weight: 400;
  font-size: .875rem; line-height: 1.07; text-align: center;
  color: var(--ink); background: var(--paper);
  opacity: .7; transition: opacity .25s var(--ease);
}
/* The source's >=40em caption rule is `padding:7x 12px 5px`, a typo the
   browser discards, so the rendered padding stays 18px 12px 0 at every
   width. Size and leading are the only parts of that rule that apply. */
@media (min-width: 40em) { .cat-card h2 { font-size: 1.75rem; line-height: 38px; } }
.cat-card:hover h2, .cat-card:focus-visible h2 { opacity: 1; }

/* ==== 27 project detail gallery ========================================= */
.gallery-main img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }
.gallery-thumbs {
  display: grid; gap: 10px; margin-top: 10px;
  grid-template-columns: repeat(auto-fit, minmax(min(120px, 100%), 1fr));
}
.gallery-thumbs > * { min-width: 0; }
.gallery-thumbs img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; }

/* ==== 28 filterable project gallery ===================================== */
.filter-bar { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 2rem; }
.filter-bar select {
  height: 48px; min-width: 200px; padding: 0 14px;
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.proj-grid {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}
.proj-grid > * { min-width: 0; }
.proj-grid img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* ==== 29 door swatch gallery ============================================ */
.swatch-wall {
  display: grid; gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
}
.swatch-wall > * { min-width: 0; }
.swatch-card { background: var(--paper); border: 1px solid var(--border); text-align: center; }
.swatch-card img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }
.swatch-card .body { padding: .9rem .8rem 1.1rem; }
.swatch-card h3 { font-size: .9375rem; line-height: 1.4; margin-bottom: .3em; }
.swatch-card p { font-size: var(--text-fine); color: var(--ink); margin: 0; }

/* ==== 30 financing promo band ===========================================
   THE UPPERCASE PROMO LABEL, transcribed. Two separate things sit here and
   the CSS sweep is what told them apart.

   The h2 ("FINANCING OPTIONS AVAILABLE! ...") carries NO text-transform in
   the theme: those capitals are the copy the source typed, so they are
   transcribed as written and no uppercase device is being introduced. It is
   also set in Nunito Sans rather than the display serif, which is the one
   place on the site a heading leaves the serif.

   The line above it IS a CSS device: .offer-callout__tagline is uppercase,
   700 weight, letter-spaced .62px, in Nunito Sans. That is an uppercase
   label above a headline, which is the eyebrow family. It is transcribed
   here under the skill's unresolved-conflict carve-out, with no accent dash,
   no stripe and no mono face, and it is deliberately NOT classed
   eyebrow/kicker. The call is recorded in brand-spec.md, including the fact
   that Jarrett has not made this a general house ruling. */
.offer-callout { background: var(--slate); text-align: center; }
.offer-callout > .container { padding-top: 3rem; padding-bottom: 3rem; }
.offer-callout .promo-tagline {
  font-family: var(--font-body); font-size: 1rem; font-weight: 700;
  letter-spacing: .62px; text-transform: uppercase; line-height: 1.6;
  color: var(--on-dark); margin-bottom: 1rem;
}
.offer-callout h2 { font-family: var(--font-body); font-weight: 400; color: var(--on-dark); font-size: var(--text-h3); line-height: 1.4; margin-bottom: .8em; }
.offer-callout .terms-note { color: var(--on-dark-muted); max-width: 900px; margin: 0 auto 1rem; }
.offer-callout a { color: var(--on-dark); text-decoration: underline; font-weight: 700; }

/* ==== 31 franchise info panel =========================================== */
.local-panel { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem; }
.local-panel > * { min-width: 0; }
@media (max-width: 880px) { .local-panel { grid-template-columns: 1fr; gap: 1.75rem; } }
.local-panel h2 { margin-bottom: .4em; }
.local-panel .local-phone { font-size: 1.375rem; font-weight: 800; color: var(--ink-espresso); text-decoration: none; display: inline-block; margin-bottom: .6rem; }
.local-panel .local-phone:hover { color: var(--link); }
.info-list { list-style: none; margin: 0 0 1.5rem; padding: 0; }
.info-list li { display: flex; flex-wrap: wrap; gap: .4rem 1rem; padding: .35rem 0; border-bottom: 1px solid var(--border-soft); font-size: .9375rem; line-height: 1.7; }
.info-list li:last-child { border-bottom: 0; }
.info-list .k { font-weight: 700; color: var(--ink); min-width: 110px; }
.local-panel h3 { font-size: var(--text-h4); margin-bottom: .4em; }
.local-panel .served { font-size: .9375rem; line-height: 1.9; }

/* ==== 32 owner story + team ============================================= */
.owner-story { display: grid; grid-template-columns: 300px 1fr; gap: 2.5rem; align-items: start; }
.owner-story > * { min-width: 0; }
.owner-story img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; }
.owner-story .who { font-weight: 800; color: var(--ink); margin-bottom: .1em; }
.owner-story .role { font-size: .9375rem; color: var(--ink); margin-bottom: 1rem; }
.owner-story .sign { font-weight: 700; color: var(--ink); margin-top: 1rem; }
@media (max-width: 880px) { .owner-story { grid-template-columns: 1fr; gap: 1.5rem; } }

/* ==== 33 site footer ====================================================
   THE SOURCE FOOTER IS LIGHT, TOP TO BOTTOM. Every row of it:

     footer                 { margin-top:10px }        <- no ground at all
     .local-info            { background-color:#f6f5f4 }
     .footer-row--tan       { background-color:#edebea }   <- subscribe + social
     .social-links          { background-color:#fff }      <- white to 64em,
       @media (min-width:64em) .social-links { background-color:transparent }
     .footer-nav__subnav    { background-color:#f3f3f3 }
     .footer-subnav__item   { background-color:#fff }
     .footer-row.footer-local { border-top/bottom:1px solid rgba(105,105,105,.15) }
     .territory-info p, .copyright small { color:#3a3a3a }

   This kit shipped the whole thing on #312e2b instead: 1.08 million px2 of a
   hex the corpus declares as a background ZERO times in 424 files (17 times as
   ink, never as a ground). It was the same defect as the repaired photo hero,
   one component further down, and it is what forced the kit's only invented
   asset, a white recolour of the wordmark for a dark band the source does not
   have. Both are gone: the footer is paper, the tan row is --band-warm, and
   the mark is the extracted logo-source.svg on every page.

   .foot-band is the full-bleed tan row and takes its own .container, the way
   .section.alt does. Do not paint it on .foot-top, which is inside the
   container and would render as an inset panel. */
.footer { background: var(--paper); color: var(--ink); padding: 0 0 2.5rem; }
.footer h2, .footer h3, .footer h4 { color: var(--ink-espresso); }
.footer h2 { font-size: var(--text-h3); }
.footer h3 { font-size: var(--text-h4); margin-bottom: .8em; }
.foot-band { background: var(--band-warm); padding: 35px 0; margin-bottom: 2.5rem; }
.footer .foot-top {
  display: grid; grid-template-columns: 1.1fr 1fr; gap: 2rem;
  align-items: center;
}
.footer .foot-top > * { min-width: 0; }
@media (max-width: 880px) { .footer .foot-top { grid-template-columns: 1fr; } }
.footer .subscribe { display: flex; flex-wrap: wrap; gap: 10px; }
.footer .subscribe input {
  flex: 1 1 240px; min-width: 150px; height: 48px; padding: 0 14px;
  font-family: var(--font-body); font-size: 1rem; color: var(--ink);
  background: var(--paper); border: 1px solid var(--border); border-radius: var(--radius-sm);
}
.footer .cols {
  display: grid; gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
}
.footer .cols > * { min-width: 0; }
.footer ul { list-style: none; margin: 0; padding: 0; }
.footer li { margin-bottom: .5em; line-height: 1.6; color: var(--ink); }
.footer a { color: var(--ink); text-decoration: none; }
.footer a:hover { color: var(--link); text-decoration: underline; }
.footer .foot-logo { width: 230px; margin-bottom: 1.25rem; }
.footer .foot-utility {
  display: flex; flex-wrap: wrap; gap: .5rem 1.5rem; list-style: none;
  margin: 2.5rem 0 1.5rem; padding: 2rem 0 0; border-top: 1px solid var(--border-soft);
  font-size: var(--text-small);
}
.footer .legal { font-size: var(--text-fine); line-height: 1.8; color: var(--ink); }
.footer .legal p { color: var(--ink); }

/* ==== ds chrome ========================================================= */
.ds-nav {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 12px 24px; padding: 1rem var(--gutter);
  background: var(--paper); border-bottom: 1px solid var(--border);
}
.ds-nav .lockup-text {
  font-family: var(--font-display); font-size: 1.25rem; color: var(--ink-espresso); margin: 0;
}
.ds-nav .lockup-text small {
  display: block; font-family: var(--font-body); font-size: .75rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink);
}
.ds-nav .tabs { display: flex; flex-wrap: wrap; gap: .35rem; }
.ds-nav .tab {
  padding: .5rem .95rem; font-size: .875rem; font-weight: 700;
  color: var(--ink); text-decoration: none; border: 1px solid var(--border);
}
.ds-nav .tab:hover { background: var(--band-warm); }
.ds-nav .tab.active { background: var(--ink-espresso); color: var(--on-dark); border-color: var(--ink-espresso); }

.ds-hero { padding: 3.5rem 0 3rem; border-bottom: 1px solid var(--border); }
.ds-hero h1 { margin-bottom: .3em; }
.ds-hero .lede { max-width: 820px; }

.meta-strip {
  display: grid; gap: 1.5rem; margin-top: 2.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
}
.meta-strip > * { min-width: 0; }
.meta-strip .k { display: block; font-size: .75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-quiet); margin-bottom: .3em; }
.meta-strip .v { display: block; font-size: .9375rem; font-weight: 700; color: var(--ink); }

.door-cards {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
}
.door-cards > * { min-width: 0; }
.door { display: block; padding: 1.6rem; border: 1px solid var(--border); text-decoration: none; }
.door:hover { border-color: var(--accent-deep); background: var(--band-warm); }
.door h3 { font-size: 1.1875rem; margin-bottom: .35em; }
.door p { font-size: .9375rem; line-height: 1.75; color: var(--ink); margin: 0; }

.char-grid {
  display: grid; gap: var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
}
.char-grid > * { min-width: 0; }
.anchor-tile { background: var(--paper); border: 1px solid var(--border); padding: 1.6rem; }
.anchor-tile h3 { font-size: 1.125rem; margin-bottom: .45em; }
.anchor-tile p { font-size: .9375rem; line-height: 1.8; color: var(--ink); margin: 0; }

.files-list { display: grid; gap: .1rem; }
.files-list > div {
  display: grid; grid-template-columns: 260px 1fr; gap: 1rem;
  padding: .75rem 0; border-bottom: 1px solid var(--border-soft); align-items: baseline;
}
.files-list > div > * { min-width: 0; }
.files-list code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .8125rem; color: var(--ink-espresso); word-break: break-all; }
.files-list .what { font-size: .875rem; color: var(--ink); }
@media (max-width: 880px) { .files-list > div { grid-template-columns: 1fr; gap: .25rem; } }

.swatch-grid {
  display: grid; gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
}
.swatch-grid > * { min-width: 0; }
.swatch { border: 1px solid var(--border); }
.swatch .chip { height: 92px; }
.swatch .meta { padding: .8rem 1rem; }
.swatch .meta b { display: block; font-size: .875rem; color: var(--ink-espresso); }
.swatch .meta code { font-size: .75rem; color: var(--ink); font-family: ui-monospace, monospace; }

.type-spec { border-bottom: 1px solid var(--border); padding: 1.5rem 0; }
.type-spec .note { font-size: .75rem; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-quiet); margin-bottom: .5rem; }

.chip-row { display: flex; flex-wrap: wrap; gap: 10px; }
.chip-tag {
  display: inline-flex; align-items: center; padding: 6px 14px;
  font-size: .8125rem; font-weight: 700; color: var(--ink-espresso);
  background: var(--band-warm); border: 1px solid var(--border);
}

.asset-grid {
  display: grid; gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(180px, 100%), 1fr));
}
.asset-grid > * { min-width: 0; }
.asset-grid figure { margin: 0; border: 1px solid var(--border); }
.asset-grid img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.asset-grid figcaption { padding: .6rem .8rem; font-size: .75rem; font-family: ui-monospace, monospace; color: var(--ink); word-break: break-all; }

/* sections.html chrome */
.sx-main { display: block; }
.sx-header { padding: 3.25rem 0 2.5rem; border-bottom: 1px solid var(--border); }
.sx-index { padding: 2.25rem 0; border-bottom: 1px solid var(--border); }
.sx-index .grid {
  display: grid; gap: .2rem 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
}
.sx-index .grid > * { min-width: 0; }
.sx-index a { display: block; padding: .25rem 0; font-size: .875rem; color: var(--ink); text-decoration: none; }
.sx-index a:hover { color: var(--link); text-decoration: underline; }

.sx-pattern { border-bottom: 1px solid var(--border); padding: 3rem 0; }
.pattern-meta {
  display: grid; grid-template-columns: 220px 1fr; gap: 1rem 2rem;
  max-width: var(--maxw); margin: 0 auto 1.75rem; padding: 0 var(--gutter);
}
.pattern-meta > * { min-width: 0; }
@media (max-width: 880px) { .pattern-meta { grid-template-columns: 1fr; gap: .5rem; } }
.pattern-meta .id { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; font-family: ui-monospace, monospace; font-size: .75rem; color: var(--ink); }
.pattern-meta .num { font-weight: 700; color: var(--ink-espresso); }
.pattern-meta .signature {
  background: var(--accent); color: var(--ink-deep);
  font-family: var(--font-body); font-size: .625rem; font-weight: 800;
  letter-spacing: .12em; padding: 3px 8px;
}
.pattern-meta .name { font-family: var(--font-display); font-size: 1.25rem; color: var(--ink-espresso); margin: 0 0 .25em; }
.pattern-meta .purpose { font-size: .9375rem; line-height: 1.75; color: var(--ink); margin: 0; }

.sx-demo { position: relative; border-top: 1px solid var(--border); padding-top: 2.25rem; }
.sx-demo .demo-label {
  display: block; max-width: var(--maxw); margin: 0 auto .9rem; padding: 0 var(--gutter);
  font-size: .6875rem; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-quiet);
}

/* The catalog nests each demo inside .sx-pattern > .sx-demo > .container, so
   on a phone a pattern would otherwise render in about 197px of a 305px
   viewport and manufacture overflow that exists nowhere else. Zero the
   horizontal padding under 600px and give it back to the meta block alone.
   The `body` prefix is the +1 specificity that beats ../mobile-responsive.css,
   which is linked after this file. */
@media (max-width: 600px) {
  body .sx-pattern { padding-left: 0; padding-right: 0; }
  body .sx-demo { padding-left: 0; padding-right: 0; }
  body .sx-pattern .pattern-meta { padding-left: 18px; padding-right: 18px; }
  body .sx-demo .demo-label { padding-left: 18px; padding-right: 18px; }
}

/* pages gallery */
.pages-gallery { padding: 3rem 0; }
.pages-gallery .grid {
  display: grid; gap: var(--gap); max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gutter);
  grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr));
}
.pages-gallery .grid > * { min-width: 0; }
.page-card { border: 1px solid var(--border); overflow: hidden; }
.page-card .frame { height: 380px; overflow: hidden; background: var(--band-warm); }
.page-card iframe { width: 1400px; height: 1520px; border: 0; transform: scale(.29); transform-origin: 0 0; }
.page-card .cap { padding: 1.3rem; border-top: 1px solid var(--border); }
.page-card .cap h3 { font-size: 1.0625rem; margin-bottom: .35em; }
.page-card .cap p { font-size: .875rem; color: var(--ink); }
.page-card .cap a { font-size: .875rem; font-weight: 700; color: var(--link); }
