﻿/* Layout DNA preview engine â€” style schools as token sets.
   One school per site (docs/layout-dna.md). Accent comes from demo art. */
* { box-sizing:border-box; margin:0; }
.joblistLayout{display:grid;grid-template-columns:1.25fr 1fr;gap:48px;align-items:start}
.joblistIntro{max-width:680px;margin-bottom:32px}.joblistIntro p{color:var(--dim);margin-top:12px}
.joblist{border:0;padding:0;min-width:0}.joblist legend{font-size:14px;font-weight:600;margin-bottom:12px}
.joblist label{display:flex;align-items:center;gap:14px;min-height:58px;padding:12px 0;border-bottom:1px solid var(--line);cursor:pointer}
.joblist input{width:22px;height:22px;flex:0 0 22px;accent-color:var(--accent)}
.joblistAside{padding:32px;background:var(--bg);border:1px solid var(--line)}
.jobRate strong{display:block;font-size:32px;line-height:1.2;color:var(--ink)}.jobRate span{display:block;margin-top:8px;color:var(--dim)}
.joblistAside p+p{margin-top:24px}.joblistAside .btn{margin-top:28px}.joblistStatus{font-size:14px}
.guideGrid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:24px}.guideNote{color:var(--dim);margin:10px 0 24px}
.guideGrid figure{margin:0}.guideGrid svg{width:100%;height:130px;background:var(--soft);color:var(--accent-text)}
.guideGrid figcaption{padding:16px 0}.guideGrid figcaption p{color:var(--dim);margin-top:6px}
.shot button{min-width:70px;min-height:44px;cursor:pointer}.qsend:disabled{opacity:.65;cursor:wait}
@media(max-width:700px){.joblistLayout{grid-template-columns:1fr;gap:28px}.joblistAside{padding:24px}.guideGrid{grid-template-columns:1fr}.guideGrid figure{display:grid;grid-template-columns:100px 1fr;gap:18px;align-items:center}.guideGrid svg{height:100px}}
img { max-width:100%; display:block; }

:root {
  --ink:#1A2330; --dim:#5C6B7A; --bg:#FFFFFF; --soft:#F5F7FA; --line:#E4E9EF;
  /* --line separates; --edge IDENTIFIES. 1.4.11 wants 3:1 on anything a
     user has to recognise as a control, and --line is 1.22:1 on white —
     right for a rule between cards, wrong as the only thing telling
     somebody a white rectangle is a box they can type in. */
  --edge:#8A97A6;
  /* --accent fills (buttons, bands). --accent-text is the same color used as
     TYPE, and it is not always the same value: a pale client brand color is
     fine behind dark ink and unreadable at 15px on white. dna.js/site.js
     override this with a contrast-corrected version when the accent needs it;
     an already-legible accent comes through untouched. */
  --accent:#1E62D0; --accent-ink:#fff; --accent-text:var(--accent);
  --font:'Inter',-apple-system,"Segoe UI",sans-serif;
  --disp:var(--font); --dispWeight:800; --dispSpace:-0.02em; --dispCase:none;
  --radius:12px; --btnRadius:10px; --pad:88px; --cardBorder:1px solid var(--line);
  --cardShadow:none; --h1:clamp(32px,5vw,50px);
  /* ---- Fluid type scale ----
   * Ported from the Frostline build. Every step is clamp(floor, grows-with-
   * width, ceiling), so type answers to the width it is actually rendered in.
   *
   * That last part matters more here than on an ordinary site: the showcase
   * renders these pages inside an IFRAME, and `vw` inside an iframe is the
   * IFRAME's width. So the same stylesheet reads correctly in a 390px phone
   * frame and a 1000px desktop frame without a media query — which is exactly
   * the case fixed pixels get wrong, because 15px next to a 50px headline is
   * a different relationship than 15px next to a 32px one.
   *
   * Deliberately NOT applied to small UI text — labels, notes, badges. Fluid
   * 12px is a legibility risk for the sake of nothing. */
  --step-0: clamp(15px, 14.4px + 0.25vw, 17px);    /* body */
  --step-1: clamp(16.5px, 15.4px + 0.45vw, 20px);  /* hero tag, lead */
  --step-2: clamp(17.5px, 16.3px + 0.55vw, 22px);  /* card headings */
  --step-3: clamp(24px, 21.5px + 1.15vw, 32px);    /* section headings */

  /* ==== Direction-B design system (ported 2026-08-19, CRAFT_DESIGN.md) ====
   * Three weights per school, every size a scale step, an 8px spacing
   * scale, a 3-shade accent ramp, and a per-school separation budget.
   * The DISCIPLINE propagates to every school; each school keeps its own
   * palette and temperament (bold schools spend it on rules and caps,
   * quiet schools on background shifts and a small shadow ramp). */
  --step--1: 13.5px;               /* the ONE small-UI size (kickers, labels, captions) */
  --step-4: clamp(28px, 24px + 1.6vw, 40px);       /* display step between h2 and h1 */
  --s1:8px; --s2:16px; --s3:24px; --s4:32px; --s5:48px; --s6:64px;
  --w-reg:400; --w-semi:600; --w-disp:var(--dispWeight);
  /* accent ramp: --accent fills, --accent-deep is the dark band/flagship
     step, --accent-wash tints bands. --accent-ink-soft is the hand-picked
     on-accent body shade (a real color, not opacity — same composite the
     old white/.92 had, so the measured contrast is unchanged). */
  --accent-deep: color-mix(in srgb, var(--accent) 62%, #101E2B);
  --accent-wash: color-mix(in srgb, var(--accent) 8%, var(--bg));
  --accent-ink-soft: color-mix(in srgb, var(--accent-ink) 95%, var(--accent));
  --deep-ink-soft: color-mix(in srgb, #fff 86%, var(--accent-deep));
  /* separation modes: bold schools set --rule (the ONE accent-line idiom);
     quiet schools use the shadow ramp instead. */
  --rule: 0;
  --shadow-1: 0 1px 2px rgba(26,35,48,.05), 0 1px 6px rgba(26,35,48,.04);
  --shadow-2: 0 2px 6px rgba(26,35,48,.05), 0 12px 28px rgba(26,35,48,.08);
  --shadow-3: 0 8px 18px rgba(26,35,48,.08), 0 22px 48px rgba(26,35,48,.12);
}

/* ---- schools ---- */
/* Temperaments: calm + warm are QUIET (separation = background shift +
   shadow ramp; no accent lines). trade is BOLD (line + space; a thick
   accent top-rule is the one accent-line idiom; no shadows). editorial is
   BOLD-refined (line + space at hairline weight; a thin rule). darkpremium
   is QUIET-dark (background shift + hairline; shadows don't read on
   near-black, so its ramp is flat). */
[data-school="calm"] {
  --radius:18px; --btnRadius:999px; --pad:96px; --dispWeight:700;
  --cardBorder:0; --cardShadow:var(--shadow-2);
}
[data-school="trade"] {
  --radius:6px; --btnRadius:6px; --pad:80px; --dispWeight:850; --dispSpace:-0.02em;
  --disp:'Archivo','Inter',sans-serif; --w-semi:700;
  --cardBorder:0; --cardShadow:none;
  --h1:clamp(40px, 30px + 4.6vw, 88px);
  --step-4:clamp(30px, 25px + 2vw, 44px);
  --rule:4px solid var(--accent);
  --accent-deep:var(--band, #182A3A);
}
[data-school="warm"] {
  --edge:#A79470;
  --bg:#FDFAF3; --soft:#F5EEE0; --line:#E8DFCC; --ink:#2E2820; --dim:#6E6353;
  --disp:'Source Serif 4',Georgia,serif; --dispWeight:640; --dispSpace:-0.01em;
  --radius:10px; --btnRadius:8px; --pad:100px;
  --cardBorder:0; --cardShadow:var(--shadow-2);
  --shadow-1: 0 1px 2px rgba(70,55,30,.06), 0 1px 6px rgba(70,55,30,.05);
  --shadow-2: 0 2px 6px rgba(70,55,30,.06), 0 12px 28px rgba(70,55,30,.10);
  --shadow-3: 0 8px 18px rgba(70,55,30,.09), 0 22px 48px rgba(70,55,30,.13);
}
[data-school="editorial"] {
  --radius:0; --btnRadius:0; --pad:128px; --line:#D9DEE5; --edge:#7D8896;
  --disp:'Source Serif 4',Georgia,serif; --dispWeight:480; --dispSpace:-0.015em;
  --cardBorder:0; --cardShadow:none; --h1:clamp(44px,7.2vw,84px);
  --rule:2px solid var(--accent);
}
[data-school="darkpremium"] {
  --edge:#6B6257;
  --bg:#12100E; --soft:#1C1916; --line:#2E2A25; --ink:#F2EDE6; --dim:#A79E92;
  --radius:2px; --btnRadius:2px; --pad:110px; --dispWeight:560;
  --disp:'Source Serif 4',Georgia,serif;
  --cardBorder:1px solid var(--line); --cardShadow:none;
  --rule:2px solid var(--accent);
}

body { font-family:var(--font); color:var(--ink); background:var(--bg); line-height:1.65; font-size:var(--step-0); }
.wrap { max-width:1040px; margin:0 auto; padding:0 22px; }
.hand { font-family:'Caveat',cursive; font-weight:600; }

/* ---- header ---- */
header.top { position:sticky; top:0; background:var(--bg); border-bottom:1px solid var(--line); z-index:10; }
/* padding-block, NOT the shorthand — see the note in styles.css */
.topRow { display:flex; align-items:center; justify-content:space-between; padding-top:15px; padding-bottom:15px; gap:12px; }
.logo { font-family:var(--disp); font-weight:var(--dispWeight); font-size:20px; color:var(--ink); text-decoration:none; letter-spacing:var(--dispSpace); }
nav.mainNav { display:flex; gap:20px; align-items:center; }
nav.mainNav a { color:var(--ink); text-decoration:none; font-weight:var(--w-semi); font-size:15px; }
nav.mainNav a.navCta { background:var(--accent); color:var(--accent-ink); padding:10px 20px; border-radius:var(--btnRadius); font-weight:var(--w-semi); }
nav.mainNav .navPhone { font-weight:var(--w-semi); color:var(--accent-text); }

.btn { display:inline-block; padding:14px 28px; border-radius:var(--btnRadius); font-weight:var(--w-semi); text-decoration:none; font-size:var(--step-0); }
.btn.primary { background:var(--accent); color:var(--accent-ink); }
.btn.ghost { border:1.5px solid currentColor; color:var(--ink); }
.btn.arrow { padding:14px 0; color:var(--ink); border-bottom:2px solid var(--accent); border-radius:0; }
.btn.arrow::after { content:' \2192'; }

h2 { font-family:var(--disp); font-weight:var(--dispWeight); letter-spacing:var(--dispSpace); font-size:var(--step-3); margin-bottom:var(--s2); }
section { padding:calc(var(--pad) * .62) 0; }
.kicker { font-size:var(--step--1); font-weight:var(--w-semi); letter-spacing:.14em; text-transform:uppercase; color:var(--accent-text); margin-bottom:10px; }

/* ---- heroes ---- */
.heroForm { padding:calc(var(--pad) * .7) 0; }
.heroForm .cols { display:grid; grid-template-columns:1.05fr .95fr; gap:44px; align-items:start; }
.heroForm h1 { font-family:var(--disp); font-weight:var(--dispWeight); letter-spacing:var(--dispSpace); font-size:var(--h1); line-height:1.08; }
.heroForm .tag { margin-top:16px; font-size:var(--step-1); color:var(--dim); max-width:520px; }
.heroForm .heroSnap { margin-top:26px; border-radius:var(--radius); overflow:hidden; aspect-ratio:16/8; background-size:cover; background-position:center; }

.heroFormOv { position:relative; }
.heroFormOv .bgimg { position:absolute; inset:0; background-size:cover; background-position:center; }
.heroFormOv .scrim { position:absolute; inset:0; background:linear-gradient(105deg, rgba(8,20,18,.88) 0%, rgba(8,20,18,.62) 55%, rgba(8,20,18,.38) 100%); }
.heroFormOv .inner { position:relative; padding:88px 0 72px; }
.heroFormOv .cols { display:grid; grid-template-columns:1.05fr .95fr; gap:48px; align-items:center; }
.heroFormOv h1 { font-family:var(--disp); font-weight:var(--dispWeight); letter-spacing:var(--dispSpace); color:#fff; font-size:var(--h1); line-height:1.07; }
.heroFormOv .tag { color:rgba(255,255,255,.88); margin-top:16px; font-size:var(--step-1); max-width:480px; }
.heroFormOv .ctaRow .btn.ghost { color:#fff; border-color:rgba(255,255,255,.75); }
.heroFormOv .calcAnno { color:#fff; text-shadow:0 1px 10px rgba(0,0,0,.6); }

.tintband { background:var(--accent-wash); }

.heroOverlay { position:relative; min-height:74vh; display:flex; align-items:flex-end; }
.heroOverlay .bgimg { position:absolute; inset:0; background-size:cover; background-position:center; }
.heroOverlay .scrim { position:absolute; inset:0; background:linear-gradient(160deg, rgba(8,10,13,.78) 8%, rgba(8,10,13,.38) 55%, rgba(8,10,13,.55) 100%); }
[data-school="warm"] .heroOverlay .scrim { background:linear-gradient(165deg, rgba(46,32,12,.72) 5%, rgba(46,32,12,.28) 60%, rgba(46,32,12,.5) 100%); }
.heroOverlay .inner { position:relative; padding:120px 0 64px; width:100%; }
.heroOverlay h1 { font-family:var(--disp); font-weight:var(--dispWeight); letter-spacing:var(--dispSpace); color:#fff; font-size:var(--h1); line-height:1.06; max-width:640px; }
.heroOverlay .tag { color:rgba(255,255,255,.9); margin-top:16px; font-size:var(--step-1); max-width:540px; }
.heroOverlay .ctaRow .btn.ghost { color:#fff; border-color:#fff; }

.heroEditorial { padding:calc(var(--pad) * .9) 0 calc(var(--pad) * .55); }
.heroEditorial .edCols { display:grid; grid-template-columns:1fr; }
.heroEditorial.hasPhoto .edCols { grid-template-columns:1.1fr .9fr; gap:52px; align-items:center; }
.edPhoto { border-radius:var(--radius); min-height:400px; background-size:cover; background-position:center;
  box-shadow:var(--shadow-3); }
@media (max-width:900px) { .heroEditorial.hasPhoto .edCols { grid-template-columns:1fr; } .edPhoto { display:none; } }
.heroEditorial .rule { height:1px; background:var(--ink); opacity:.25; margin-bottom:34px; }
.heroEditorial h1 { font-family:var(--disp); font-weight:var(--dispWeight); letter-spacing:var(--dispSpace); font-size:var(--h1); line-height:1.04; max-width:15ch; }
.heroEditorial .tag { margin-top:22px; font-size:var(--step-1); color:var(--dim); max-width:52ch; }
/* These three are the trust strip — the proof sitting directly under the CTA,
   and for a trade with no reviews yet they are the entire case. At 14.5px dim
   they read as a footnote, which is the opposite of their job. The Denver
   competitors give this line real weight (Grandma's puts "Licensed & Insured"
   and its rates above the fold at body size or larger). The number leads, the
   label supports. */
.heroEditorial .metaRow { display:flex; gap:var(--s4); margin-top:var(--s5); border-top:0; color:var(--dim); font-size:var(--step--1); flex-wrap:wrap; }
.heroEditorial .metaRow div { display:flex; flex-direction:column; gap:1px; }
.heroEditorial .metaRow b { color:var(--ink); font-family:var(--disp); font-size:var(--step-2); line-height:1.15; font-weight:var(--w-disp); letter-spacing:-0.01em; }

.heroBand { padding:calc(var(--pad) * .8) 0 0; text-align:center; }
.heroBand h1 { font-family:var(--disp); font-weight:var(--dispWeight); letter-spacing:var(--dispSpace); font-size:var(--h1); line-height:1.08; max-width:22ch; margin:0 auto; }
.heroBand .tag { margin:16px auto 0; font-size:var(--step-1); color:var(--dim); max-width:56ch; }
.heroBand .ctaRow { justify-content:center; }
.ctaRow { margin-top:var(--s4); display:flex; gap:var(--s2); flex-wrap:wrap; align-items:center; }

/* ---- proof ---- */
.proofStrip { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--s2); padding:var(--s4) 0; border-top:1px solid var(--line); border-bottom:1px solid var(--line); }
.proofStrip .stat { text-align:center; }
.proofStrip b { display:block; font-family:var(--disp); font-size:var(--step-3); font-weight:var(--w-disp); color:var(--accent-text); }
.proofStrip span { color:var(--dim); font-size:var(--step--1); }
.darkband { background:var(--band, #141A22); color:#EAF0F6; padding:52px 0; }
[data-school="darkpremium"] .darkband { background:var(--soft); }
.darkband .cols { display:grid; grid-template-columns:repeat(auto-fit,minmax(170px,1fr)); gap:var(--s3); }
.darkband b { display:block; font-family:var(--disp); font-size:clamp(34px,4.5vw,52px); font-weight:var(--w-disp); color:var(--accent); line-height:1; }
.darkband span { color:#93A1B0; font-size:var(--step--1); }

/* ---- services variants ---- */
.svcGrid { display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:var(--s2); }
.svcGrid.four { grid-template-columns:1fr 1fr; }
.card { background:var(--soft); border:var(--cardBorder); box-shadow:var(--cardShadow); border-radius:var(--radius); padding:var(--s3); }
.card h3 { font-family:var(--disp); font-size:var(--step-2); margin-bottom:var(--s1); font-weight:var(--w-disp); }
.card p { color:var(--ink); font-size:var(--step-0); }
.card .price { margin-top:14px; font-weight:var(--w-semi); color:var(--accent-text); }

.featRest { display:grid; grid-template-columns:1.25fr 1fr; gap:var(--s3); align-items:start; }
/* the flagship fills its column instead of leaving dead white under itself */
@media (min-width:761px) {
  .featRest { align-items:stretch; }
  .featRest .featured { display:flex; flex-direction:column; justify-content:center; }
}
.featRest .featured { background:var(--accent); color:var(--accent-ink); border-radius:var(--radius); padding:var(--s4); }
.featRest .featured h3 { font-family:var(--disp); font-size:var(--step-2); font-weight:var(--w-disp); margin-bottom:10px; }
.featRest .featured p { opacity:1; color:var(--accent-ink-soft); font-size:var(--step-0); }
.featRest .featured .price { margin-top:18px; font-weight:var(--w-semi); font-size:var(--step-1); }
/* rows are soft cards now — background shift, not hairlines; bold schools
   add their accent top-rule (--rule; 0 on quiet schools). */
.featRest .rest { display:flex; flex-direction:column; gap:var(--s2); }
.featRest .rest .row, .featRest .rest .row:first-child { padding:20px 22px; background:var(--soft);
  border-radius:var(--radius); border-top:var(--rule); }
.featRest .row h3 { font-size:var(--step-0); font-weight:var(--w-semi); display:flex; justify-content:space-between; gap:14px; }
.featRest .row h3 span { color:var(--accent-text); white-space:nowrap; font-weight:var(--w-semi); }
.featRest .row p { color:var(--ink); font-size:var(--step-0); margin-top:4px; }

.numList .item { display:grid; grid-template-columns:110px 1fr auto; gap:var(--s3); padding:var(--s4) 0; border-top:1px solid var(--line); align-items:baseline; }
.numList .n { font-family:var(--disp); font-size:clamp(38px,5vw,58px); font-weight:var(--w-reg); color:var(--dim); line-height:1; }
.numList h3 { font-family:var(--disp); font-size:var(--step-2); font-weight:var(--w-semi); }
.numList p { color:var(--ink); font-size:var(--step-0); margin-top:6px; max-width:52ch; }
.numList .price { font-weight:var(--w-semi); color:var(--ink); white-space:nowrap; }

.menuRows .row { display:flex; align-items:baseline; gap:10px; padding:var(--s2) 0; }
.menuRows h3 { font-family:var(--disp); font-size:var(--step-2); font-weight:var(--w-semi); white-space:nowrap; }
.menuRows .dots { flex:1; border-bottom:2px dotted var(--line); transform:translateY(-4px); }
.menuRows .price { font-weight:var(--w-semi); color:var(--accent-text); white-space:nowrap; }
.menuRows p { color:var(--ink); font-size:var(--step-0); margin:-8px 0 6px; max-width:60ch; }

.tiers { display:grid; grid-template-columns:repeat(3,1fr); gap:0; align-items:center; }
.tiers .card { text-align:left; }
.tiers .card.mid { transform:scale(1.06); position:relative; z-index:2; border:2px solid var(--accent); box-shadow:var(--shadow-3); }
.tiers .card.mid .tag { display:inline-block; background:var(--accent); color:var(--accent-ink); font-size:var(--step--1); font-weight:var(--w-semi); padding:3px 10px; border-radius:999px; margin-bottom:10px; }

/* ---- offers / emergency ---- */
.offers { display:grid; grid-template-columns:1fr 1fr; gap:var(--s2); }
.coupon { border:2px dashed var(--accent); border-radius:var(--radius); padding:var(--s3) 26px; display:flex; justify-content:space-between; gap:var(--s2); align-items:center; flex-wrap:wrap; }
.coupon h3 { font-family:var(--disp); font-size:var(--step-2); }
.coupon .exp { color:var(--dim); font-size:var(--step--1); margin-top:4px; }
.emergency { background:var(--accent); color:var(--accent-ink); padding:18px 0; }
.emergency .row { display:flex; justify-content:space-between; align-items:center; gap:var(--s2); flex-wrap:wrap; }
.emergency b { font-size:var(--step-1); }
.emergency a { color:inherit; font-weight:var(--w-semi); text-decoration:none; font-size:var(--step-1); border-bottom:2px solid currentColor; }

/* ---- gallery / quote / pullquote ---- */
.tiles { display:grid; grid-template-columns:1fr 1fr; gap:14px; }
.gtile { position:relative; border-radius:var(--radius); overflow:hidden; aspect-ratio:4/3; display:flex; align-items:flex-end; }
.tiles .gtile:first-child { grid-column:span 2; aspect-ratio:21/8; }
.gtile .cap { position:relative; width:100%; padding:12px 14px; color:#fff; font-weight:var(--w-semi); font-size:var(--step--1); background:linear-gradient(transparent, rgba(0,0,0,.55)); }
.galNote { margin-top:12px; font-size:var(--step--1); color:var(--dim); }

.spotlight { max-width:760px; }
.spotlight .mark { font-family:var(--disp); font-size:88px; line-height:.4; color:var(--accent-text); display:block; margin-bottom:18px; }
.spotlight p { font-family:var(--disp); font-size:var(--step-3); font-weight:var(--w-reg); line-height:1.45; }
.spotlight .who { margin-top:16px; color:var(--dim); font-weight:var(--w-semi); font-size:var(--step--1); }

.pullquote { border-top:1px solid var(--line); border-bottom:1px solid var(--line); }
.pullquote p { font-family:var(--disp); font-style:italic; font-weight:var(--w-reg); font-size:var(--step-4); line-height:1.3; max-width:24ch; }
.pullquote .sig { margin-top:18px; font-size:var(--step-3); color:var(--dim); }

/* ---- signature moments (one custom element per page) ---- */
.polaroids { display:flex; gap:30px; flex-wrap:wrap; align-items:flex-start; margin-top:8px; }
.pol { background:#FFFDF8; padding:12px 12px 44px; box-shadow:0 16px 36px rgba(0,0,0,.35); position:relative; flex:1 1 240px; max-width:300px; transform:rotate(-2.2deg); }
.pol:nth-child(2) { transform:rotate(1.6deg) translateY(14px); }
.pol:nth-child(3) { transform:rotate(-0.8deg) translateY(4px); }
.pol::before { content:''; position:absolute; top:-13px; left:50%; transform:translateX(-50%) rotate(-3deg); width:92px; height:26px; background:rgba(255,252,235,.7); border:1px solid rgba(0,0,0,.06); box-shadow:0 1px 3px rgba(0,0,0,.12); }
.pol .ph { aspect-ratio:1/1; background-size:cover; background-position:center; }
.pol .cap { position:absolute; left:12px; right:12px; bottom:10px; font-family:'Caveat',cursive; font-weight:600; font-size:20px; color:#3A342C; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }

/* Shared by the checklist and the oven/lawn board: both are a signature
   card that maxes out around 460-520px, so alone in a full-width section
   they leave half of it empty and read as a missing picture. */
.checkWrap, .boardWrap { display:flex; gap:44px; align-items:center; flex-wrap:wrap; }
/* .checklist sets its own flex basis and so grows to fill; .ovenboard did
   not, and shrank to its content (363px of a 996px row). Same basis, same
   balance - its own max-width:460px still caps it. */
.boardWrap .ovenboard { flex:1 1 320px; }
.checkPhoto { flex:1 1 240px; max-width:320px; aspect-ratio:1/1; background-size:cover; background-position:center; border:12px solid #fff; box-shadow:0 16px 36px rgba(26,35,48,.2); transform:rotate(1.8deg); }
.checklist { background:#FFFDF6; color:#2B2823; border-radius:4px; padding:30px 34px 64px; flex:1 1 320px; max-width:520px; box-shadow:0 14px 34px rgba(26,35,48,.16); transform:rotate(-0.6deg); position:relative; }
.checklist h3 { font-family:'Caveat',cursive; font-weight:600; font-size:26px; margin-bottom:14px; }
.checklist .item { display:flex; gap:12px; padding:7px 0; border-bottom:1px dashed #E5DFCF; font-size:15.5px; align-items:center; }
.checklist .item:last-child { border-bottom:0; }
.checklist .tick { font-family:'Caveat',cursive; font-weight:600; font-size:22px; color:var(--accent-text); line-height:1; }
.checklist .item.circled span:last-child { border:2.5px solid var(--accent); border-radius:50% / 42%; padding:2px 12px; transform:rotate(-1.5deg); }
.checklist .note { position:absolute; right:-14px; bottom:-20px; transform:rotate(-4deg); font-family:'Caveat',cursive; font-weight:600; font-size:23px; color:var(--accent-text); }

.ovenboard { background:#233128; color:#F2EFE4; border-radius:8px; padding:34px 38px; max-width:460px; transform:rotate(-0.5deg); box-shadow:0 16px 38px rgba(20,30,20,.35); border:10px solid #17211B; }
.ovenboard h3 { font-family:'Caveat',cursive; font-weight:600; font-size:30px; margin-bottom:12px; color:#FFF9E8; }
.ovenboard .row { display:flex; justify-content:space-between; gap:14px; font-family:'Caveat',cursive; font-weight:600; font-size:24px; padding:5px 0; border-bottom:1px solid rgba(242,239,228,.14); }
.ovenboard .row:last-of-type { border-bottom:0; }
.ovenboard .bnote { margin-top:14px; font-family:'Caveat',cursive; font-size:20px; color:rgba(242,239,228,.75); }

.bigstat { max-width:720px; }
.bigstat b { display:block; font-family:var(--disp); font-weight:var(--w-disp); font-size:clamp(56px,9vw,110px); line-height:1; letter-spacing:-0.02em; }
.bigstat svg { display:block; margin-top:6px; }
.bigstat .lbl { margin-top:10px; font-size:var(--step-1); color:var(--dim); }
.bigstat .snote { margin-top:6px; font-family:'Caveat',cursive; font-weight:600; font-size:22px; color:var(--accent-text); }

.gtile .anno { position:absolute; right:16px; bottom:44px; font-family:'Caveat',cursive; font-weight:600; font-size:23px; color:#fff; text-shadow:0 2px 10px rgba(0,0,0,.65); transform:rotate(-2.5deg); }

/* ---- about / area / calc ---- */
.aboutSplit { display:grid; grid-template-columns:1.15fr .85fr; gap:44px; align-items:center; }
.aboutSplit .photo { border-radius:var(--radius); overflow:hidden; aspect-ratio:4/3.4; background-size:cover; background-position:center; }
/* Paragraphs, not a slab. There was no margin between them, so a
   three-paragraph owner bio — the most persuasive thing on the site and
   the reason anybody hires a one-man shop — rendered as one fifteen-line
   block of light grey. A visual judge called it the most obvious CSS miss
   on the build, and it had been that way on every client. */
.aboutProse p { color:var(--ink); max-width:52ch; font-size:var(--step-1); }
.aboutProse p + p { margin-top:1.05em; }
.aboutProse h2 + p, .aboutSplit h2 + p { margin-top:6px; }

.reviews { display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:var(--s2); margin-top:18px; }
.rev { background:var(--soft); border:1px solid var(--line); border-radius:var(--radius); padding:18px 20px; }
.rev .stars { color:var(--accent-text); letter-spacing:2.5px; font-size:var(--step--1); }
.rev p { margin-top:8px; font-size:var(--step-0); line-height:1.55; }
.rev .rwho { margin-top:10px; font-size:var(--step--1); color:var(--dim); font-weight:var(--w-semi); }
.rev .rwho span { font-weight:var(--w-reg); }
.dfaq { max-width:720px; margin-top:6px; }
.dfaq dt { font-weight:var(--w-semi); margin-top:var(--s3); font-size:var(--step-0); }
.dfaq dd { margin:6px 0 0; color:var(--ink); font-size:var(--step-0); }
footer.bottom .credit { margin-top:14px; font-size:var(--step--1); }
footer.bottom .credit a { color:inherit; text-decoration:none; }
footer.bottom .credit a:hover { text-decoration:underline; }
footer.bottom .generatedTerm { white-space:nowrap; }
.callbar { display:none; }
@media (max-width:640px) {
  /* The number is already in the sticky call bar at the bottom of this same
     breakpoint — dna.js adds both from one condition (dna.navPhone). Keeping
     it in the header too meant three items fighting over ~350px, and on a
     real customer's phone every one of them wrapped: the business name onto
     two lines, the number onto two, the button onto two. A 101px header of
     broken text. The bar is the better home for it: thumb-height, always
     visible, one tap.
     Measured on an iPhone-width viewport 2026-08-03 against a live client. */
  nav.mainNav .navPhone { display:none; }
  /* a long name stacks to two lines here; tight leading makes that read as
     a wordmark rather than as text that broke */
  .logo { font-size:17px; line-height:1.12; }
  nav.mainNav a.navCta { padding:9px 15px; font-size:14px; white-space:nowrap; }

  /* NAVIGATION MUST SURVIVE THE PHONE.
   *
   * The 760px rule hides every nav link except the CTA and the phone. Once the
   * phone number moved to the call bar, a phone visitor was left with a logo
   * and one button — Services and About were unreachable from the homepage on
   * the device most of his customers use. Hiding the number fixed the header
   * and quietly removed the site's navigation.
   *
   * Links come back on their own line: CTA ordered first so it stays beside
   * the logo, the rest wrapping beneath it. No hamburger for two links. */
  nav.mainNav { flex-wrap:nowrap; justify-content:flex-end; gap:18px; }
  /* The header CTA goes on phones. The hero carries "Get an estimate" a
     screen-inch below, and the call bar is pinned to the thumb — three copies
     of the same ask, and the third was the one shoving the nav links onto a
     second line. What the header owes a phone visitor is somewhere to GO. */
  nav.mainNav a.navCta { display:none; }
  /* higher specificity than the 760px rule that hides these — that block sits
     LATER in the file, so at phone width it was winning and the links stayed
     hidden even after this one was added */
  /* ~24px with no padding: legal under the 2.5.8 spacing exception, and
     still the smallest thing an older visitor on a phone has to hit. */
  header.top nav.mainNav a:not(.navCta):not(.navPhone) {
    display:inline-block; font-size:14.5px; padding:10px 2px; }
  /* padding-block only — see the note in styles.css */
  .topRow { align-items:flex-start; padding-top:12px; padding-bottom:12px; }
  .logo { padding-top:3px; }

  /* Both hero buttons on one line. Stacked, the second sits below the fold on
     a short screen and reads as an afterthought; side by side they are a
     choice. Equal widths, no wrap. */
  .ctaRow { flex-wrap:nowrap; gap:8px; }
  .ctaRow .btn { flex:1 1 0; min-width:0; text-align:center; padding-left:10px; padding-right:10px; font-size:15px; }

  /* The signature card's arrow points at the photo BESIDE it. Stacked on a
     phone the photo is underneath, so the arrow points into empty space —
     a leftover pointing at nothing reads as a broken layout. */
  .noteArrow { display:none; }

  /* Stacked under the card, the square crop is 320px of stock tools before the
     next real section. Landscape keeps the picture and gives the height back. */
  .checkPhoto { aspect-ratio:16/10; max-width:100%; }

  /* PHONE-FIRST SPACING.
   *
   * --pad is 88-128px depending on school and it was applied at full desktop
   * scale on a 390px screen: section padding alone ate 176px+ between blocks,
   * and .heroEditorial's 90%-of-pad top margin left an 86px band of nothing
   * between the header and the first word. Measured on a live client site the
   * headline sat at 225px and the call button at 434px of a ~700px first view
   * — a third of the screen spent before the page said anything.
   *
   * Desktop is unchanged; this only applies where the screen is small enough
   * that vertical space is the scarce resource. */
  [data-school] { --pad:46px; }
  .heroEditorial { padding-top:26px; }
  .heroEditorial .rule { margin-bottom:20px; }
  .heroEditorial .tag { margin-top:14px; font-size:17px; }
  /* Three stats, one line. Flex-wrapped they broke 2+1 at phone width, which
     reads as a fourth stat missing rather than a tidy pair. A 3-column grid
     forces the row; equal auto-rows keep the cells the same height when one
     label wraps and another doesn't. */
  .heroEditorial .metaRow { display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:10px;
    grid-auto-rows:1fr; margin-top:24px; padding-top:16px; }
  .heroEditorial .metaRow b { font-size:18px; overflow-wrap:anywhere; }
  .heroEditorial .metaRow div { font-size:12.5px; line-height:1.35; }
  .heroBand, .heroForm, .heroOverlay, .heroFormOv { padding-top:26px; }
  .ctaRow { margin-top:20px; gap:10px; }

  /* A service name cannot be nowrap inside a 340px frame — it pushes the price
     off the edge and the whole page slides. Let the name fold instead. */
  .menuRows .row { flex-wrap:wrap; }
  .menuRows h3 { white-space:normal; min-width:0; }

  /* Once the call bar is on screen the phone number is on the page twice, and
     the header cannot afford it: name + number + button at 390px wrapped all
     three onto two lines each — a business name broken as "My Guy / Repair"
     above a broken phone number above a broken button. The bar keeps the
     number one thumb away, so the nav gives its copy up. */
  nav.mainNav .navPhone { display:none; }
  .callbar { display:block; position:fixed; left:0; right:0; bottom:0; z-index:40; background:var(--accent); text-align:center; box-shadow:0 -8px 24px rgba(0,0,0,.18); }
  /* The bar carries the fast pair (call + text), so a hero button doing
     either is the SAME action twice on one screen — an interaction judge
     counted four asks in every phone hero, two of them one phone number
     in different words, and the quote page at 100% redundancy. The hero
     keeps the considered ask; the bar owns the fast ones. Desktop — no
     bar — is untouched, and so is any page that turns the bar off. */
  .heroEditorial .ctaRow a[href^="tel:"],
  .heroEditorial .ctaRow a[href^="sms:"] { display:none; }
  /* Padding lives on the LINK, not the bar. With it on the bar the anchor was
     an inline 20px box inside a 46px strip, so most of the thing that looks
     tappable did nothing â€” on the one control a phone visitor is meant to hit. */
  .callbar a { display:block; padding:13px 16px; color:var(--accent-ink); font-weight:var(--w-semi); font-size:16.5px; text-decoration:none; letter-spacing:.02em; }
  body.hasCallbar { padding-bottom:54px; }
}

.chips { display:flex; flex-wrap:wrap; gap:9px; }
.chip { border:1px solid var(--line); background:var(--soft); border-radius:999px; padding:7px 15px; font-size:var(--step--1); font-weight:var(--w-semi); }
.areaProse { color:var(--ink); font-size:var(--step-0); max-width:60ch; }
.areaProse b { color:var(--ink); font-weight:var(--w-semi); }

.calcBand { padding:36px 0 8px; }
.calcBand .calcCard { max-width:600px; margin:0 auto; }
.calcCard { background:var(--bg); border:var(--cardBorder); box-shadow:var(--shadow-3); border-radius:var(--radius); padding:26px 28px; position:relative; }
[data-school="darkpremium"] .calcCard { background:var(--soft); }
.calcCard .calcTitle { font-family:var(--disp); font-weight:var(--w-disp); font-size:var(--step-2); margin-bottom:14px; }
.calcRow { display:flex; gap:16px; flex-wrap:wrap; align-items:center; }
.calcRow label { font-weight:var(--w-semi); font-size:var(--step--1); }
.calcCard select { margin-left:8px; padding:8px 12px; border:1.5px solid var(--line); border-radius:8px; font:inherit; background:var(--bg); color:var(--ink); }
.calcFreq { display:flex; gap:8px; flex-wrap:wrap; margin-top:16px; }
.freqBtn { padding:8px 14px; border:1.5px solid var(--line); border-radius:999px; background:transparent; color:var(--ink); font:inherit; font-weight:var(--w-semi); font-size:var(--step--1); cursor:pointer; }
.freqBtn.on { background:var(--accent); border-color:var(--accent-text); color:var(--accent-ink); }
.freqBtn em { font-style:normal; opacity:.75; font-weight:var(--w-semi); }
.calcAdd { display:flex; gap:13px; flex-wrap:wrap; margin-top:14px; font-size:var(--step--1); }
.calcAdd label { display:flex; gap:6px; align-items:center; font-weight:var(--w-semi); }
.calcAdd span { color:var(--dim); }
.calcOut { display:flex; align-items:center; justify-content:space-between; gap:14px; margin-top:18px; padding-top:16px; border-top:1px solid var(--line); flex-wrap:wrap; }
.calcPrice { font-family:var(--disp); font-size:var(--step-4); font-weight:var(--w-disp); }
.calcPer { color:var(--dim); font-size:var(--step--1); margin-left:6px; }
.calcNote { margin-top:10px; font-size:var(--step--1); color:var(--dim); }
.calcAnno { position:absolute; top:-14px; right:18px; transform:rotate(-3deg); font-size:21px; color:var(--accent-text); }

/* quote form (non-calculator form heroes) */
.qform label { display:block; font-weight:var(--w-semi); font-size:var(--step--1); margin:13px 0 5px; }
.qform input, .qform select, .qform textarea { width:100%; border:1.5px solid var(--line); border-radius:8px; padding:11px 12px; font:inherit; background:var(--bg); color:var(--ink); }
.qform button { margin-top:16px; width:100%; background:var(--accent); color:var(--accent-ink); border:0; font-weight:var(--w-semi); font-size:16px; padding:13px; border-radius:var(--btnRadius); cursor:pointer; }

footer.bottom { border-top:1px solid var(--line); padding:var(--s4) 0 46px; color:var(--dim); font-size:var(--step--1); }
/* baseline: the contact links are 44px tap targets, which made their line
   taller and set its text lower than the name-and-towns line beside it
   (Jason, 2026-10-29: "a bit crooked") */
footer.bottom .row { display:flex; justify-content:space-between; gap:14px; flex-wrap:wrap; align-items:baseline; }
footer.bottom a { color:var(--dim); }

@media (max-width:760px) {
  nav.mainNav a:not(.navCta):not(.navPhone) { display:none; }
  .heroForm .cols, .heroFormOv .cols, .featRest, .aboutSplit, .offers { grid-template-columns:1fr; }
  .tiers { grid-template-columns:1fr; gap:14px; }
  .tiers .card.mid { transform:none; }
  .tiles { grid-template-columns:1fr 1fr; }
  .tiles .gtile:first-child { grid-column:span 2; aspect-ratio:16/9; }
  .numList .item { grid-template-columns:64px 1fr; }
  .numList .price { grid-column:2; }
  .heroOverlay { min-height:60vh; }
  /* The handwritten margin note hangs off the card corner by design. On a
     phone the card is nearly the full width, so hanging it right:-14px ran
     the line into the screen edge with no margin. In flow under the list it
     still reads as a note in his hand, and it stays on the page. */
  .checklist .note { position:static; right:auto; bottom:auto; display:block;
    margin-top:16px; transform:rotate(-1.5deg); }
}

/* Strengths — three short answers to "what is he like to deal with".
   Bold schools box them with the accent top-rule (see the design-pass layer);
   quiet schools keep them as open text columns — space is the separator. */
.strengthRow { display:grid; grid-template-columns:repeat(3,1fr); gap:var(--s3); }
.strength h3 { font-size:var(--step-0); font-weight:var(--w-semi); margin-bottom:var(--s1); }
.strength p { color:var(--ink); font-size:var(--step-0); line-height:1.6; }
@media (max-width:760px) { .strengthRow { grid-template-columns:1fr; gap:20px; } }

/* ---- booking widget (assets/booking.js) ---- */
.bookBox { max-width:620px; }
.bookLoad { color:var(--dim); font-size:var(--step-0); }
.bookSlots { display:flex; flex-wrap:wrap; gap:10px; margin-bottom:18px; }
.bookSlot { flex:0 0 auto; background:var(--panel,#fff); border:1.5px solid var(--line); border-radius:10px;
  padding:12px 16px; font:var(--w-semi) 15px inherit; color:inherit; cursor:pointer; line-height:1.2; }
.bookSlot:hover { border-color:var(--accent); }
.bookSlot.on { background:var(--accent); border-color:var(--accent); color:#fff; }
.bookForm { display:flex; flex-wrap:wrap; gap:10px; align-items:center; }
.bookForm input { flex:1 1 200px; min-width:0; border:1.5px solid var(--line); border-radius:10px;
  padding:13px 14px; font:inherit; font-size:16px; background:var(--bg,#fff); color:inherit; }
.bookForm button { flex:0 0 auto; background:var(--accent); color:#fff; border:0; border-radius:10px;
  padding:14px 24px; font:var(--w-semi) 15px inherit; cursor:pointer; }
.bookForm button:disabled { opacity:.6; cursor:default; }
.bookFine { flex:1 1 100%; margin:0; color:var(--dim); font-size:var(--step--1); }
.bookMsg { margin-top:10px; font-weight:var(--w-semi); font-size:var(--step--1); color:var(--accent); min-height:20px; }
.bookNote { color:var(--dim); font-size:var(--step--1); margin-top:12px; max-width:56ch; }
.bookDone { border:1.5px solid var(--accent); border-radius:12px; padding:18px 20px; }
.bookDone p { margin-top:6px; color:var(--dim); font-size:var(--step-0); }
@media (max-width:640px) {
  /* One tap target per row beats two half-width ones a thumb keeps missing. */
  .bookSlots { flex-direction:column; }
  .bookSlot { width:100%; text-align:left; }
  .bookForm input, .bookForm button { flex:1 1 100%; }
}

/* ---------- Range estimator (assets/estimator.js) ----------
 * Trade-agnostic, data-driven, and it prints its own arithmetic. The working
 * panel is the point: a number a customer can check is worth more than a
 * number they have to believe, and it is the thing a low bid cannot survive. */
.estTitle { font-weight:var(--w-semi); font-size:var(--step-1); }
.estLabel { display:block; font-weight:var(--w-semi); font-size:var(--step--1); margin-top:14px; color:var(--dim); }
.estArea { display:flex; align-items:center; gap:8px; margin-top:6px; }
.estArea input { flex:1 1 auto; min-width:0; border:1.5px solid var(--line); border-radius:9px;
  padding:11px 13px; font:inherit; font-size:17px; background:var(--bg); color:var(--ink); }
.estArea span { color:var(--dim); font-size:var(--step--1); font-weight:var(--w-semi); }
.estPresets, .estBands { display:flex; flex-wrap:wrap; gap:7px; margin-top:10px; }
.estChip { border:1.5px solid var(--line); background:transparent; color:var(--ink);
  border-radius:999px; padding:6px 13px; font:var(--w-semi) 13px inherit; cursor:pointer; }
.estChip.on { border-color:var(--accent); background:var(--accent); color:var(--accent-ink,#fff); }
.estBands { flex-direction:column; gap:8px; }
.estBand { display:block; width:100%; text-align:left; border:1.5px solid var(--line);
  background:transparent; border-radius:11px; padding:11px 14px; cursor:pointer; color:var(--ink); }
.estBand.on { border-color:var(--accent); box-shadow:inset 0 0 0 1px var(--accent); }
.estBand b { display:block; font-size:var(--step-0); }
.estBand span { display:block; color:var(--dim); font-size:var(--step--1); margin-top:3px; }
.estMods { margin-top:12px; display:flex; flex-direction:column; gap:9px; }
.estMod { display:flex; gap:10px; align-items:flex-start; font-size:var(--step--1); cursor:pointer; }
.estMod input { margin-top:3px; flex:0 0 auto; }
.estMod b { font-weight:var(--w-semi); }
.estMod em { display:block; font-style:normal; color:var(--dim); font-size:var(--step--1); margin-top:2px; }
.estOut { display:flex; flex-wrap:wrap; gap:12px; align-items:center; justify-content:space-between;
  margin-top:16px; padding-top:14px; border-top:1px solid var(--line); }
.estRange b { font-family:var(--disp); font-size:var(--step-3); font-weight:var(--w-disp); letter-spacing:-.01em; }
.estToggle { background:none; border:0; padding:8px 0 0; color:var(--accent-text,var(--accent));
  font:var(--w-semi) var(--step--1) inherit; cursor:pointer; }
.estWork { margin-top:8px; border-top:1px dashed var(--line); padding-top:10px; }
.estTable { width:100%; border-collapse:collapse; font-size:var(--step--1); }
.estTable th { text-align:left; font-weight:var(--w-semi); padding:6px 10px 6px 0; vertical-align:top; width:40%; }
.estTable td { color:var(--dim); padding:6px 0; vertical-align:top; }
.estAssume { margin-top:10px; font-size:var(--step--1); color:var(--dim); }
.estAssume b { color:var(--ink); display:block; margin-bottom:4px; }
.estAssume ul { margin:0; padding-left:18px; }
.estAssume li { margin-top:3px; }
.estNote { color:var(--dim); font-size:var(--step--1); margin-top:12px; }
@media (max-width:560px) { .estOut { flex-direction:column; align-items:stretch; }
  .estOut .btn { text-align:center; } .estTable th { width:46%; } }

/* ---------- Failure catalog ----------
 * The trade research, on the CLIENT's site rather than only on ours. Cause on
 * the left, prevention on the right — the competitor cannot copy it without
 * conceding the same point. */
.failGrid { display:grid; grid-template-columns:1fr; gap:0; margin-top:22px; border-top:1px solid var(--line); }
.failRow { display:grid; grid-template-columns:1fr 1fr; gap:26px; padding:18px 0; border-bottom:1px solid var(--line); }
.failRow .cause b, .failRow .fix b { display:block; font-size:11px; letter-spacing:.1em; text-transform:uppercase;
  color:var(--dim); margin-bottom:5px; }
.failRow .fix { border-left:2px solid var(--accent); padding-left:16px; }
.failRow p { font-size:var(--step-0); }
.failNote { margin-top:18px; color:var(--dim); font-size:var(--step--1); max-width:62ch; }
@media (max-width:640px) { .failRow { grid-template-columns:1fr; gap:12px; } }

/* The estimator's option rows are flex, and the text block was left at
   min-width:auto — so it could not shrink below its own min-content and shoved
   the row past the card on a phone. Fence overflowed by 31px, landscaping by
   47px, on the only two trade pages carrying an estimator. */
.estMod { flex-wrap:wrap; }
.estMod > span { min-width:0; flex:1 1 auto; }

/* Room for the handwritten note.
   It is positioned bottom:-20px so it hangs off the corner like a margin
   scribble, but the card reserved no space for it — so at every width above
   640px the two lines of it rose back up and printed across the last item on
   the list. The extra bottom padding is the space it hangs into. */

/* THE EDITORIAL HERO ON A LAPTOP (2026-08-05)
 *
 * Two faults, both only visible between about 950px and 1500px — the width
 * most people actually browse at, and the one nobody had measured.
 *
 * The three proof stats were a flex row with a 34px gap inside a ~519px
 * column. Any nine-character value — a license number — pushed the third onto
 * a second row, so real estate showed "Weekly / 2 towns" above a lonely
 * "201245781". A three-column grid with minmax(0,…) cannot wrap, and the
 * long-value shrink now applies at every width rather than only on a phone.
 *
 * And the photo was a fixed 400px beside an 816px column of text, centered, so
 * the hero carried 400px of empty white down its right-hand side. It stretches
 * to the column now, capped so a short column cannot make it absurd.
 */
.heroEditorial .metaRow { display:grid; grid-template-columns:repeat(3,minmax(0,1fr));
  gap:var(--s3); align-items:start; }
.heroEditorial .metaRow b.long { font-size:17px; letter-spacing:-0.02em; }
.heroEditorial.hasPhoto .edCols { align-items:stretch; }
.edPhoto { height:100%; max-height:620px; }

/* THE HANDWRITTEN NOTE, FOR GOOD.
 *
 * I fixed this once today by reserving 64px of bottom padding for it. That
 * held for a two-line note and failed on the first three-line one — real
 * estate's runs to three lines and printed straight through "Final
 * walkthrough, then closing".
 *
 * Reserving a fixed amount of space for a variable amount of text is the bug,
 * not the number. It sits in normal flow now and pushes the card taller by
 * exactly its own height, so it can never overlap, whatever its length. The
 * negative right margin keeps it hanging off the corner, which was the point
 * of the effect in the first place.
 */
.checklist { padding-bottom:30px; }
.checklist .note { position:static; display:block; margin:20px -14px 0 auto;
  max-width:340px; text-align:right; }

/* What a service includes. The list is the trust moment on the page, so it
   gets room rather than being squeezed under the paragraph. Ticks are drawn
   with a pseudo-element so the markup stays a plain <ul> for screen readers. */
.svcInc { list-style:none; margin:12px 0 0; padding:0; display:grid; gap:7px; }
.svcInc li { position:relative; padding-left:20px; color:var(--dim);
  font-size:var(--step--1); line-height:1.5; }
.svcInc li::before { content:''; position:absolute; left:2px; top:.5em;
  width:9px; height:5px; border-left:2px solid var(--accent);
  border-bottom:2px solid var(--accent); transform:rotate(-45deg); }
.card .svcInc + .price, .featured .svcInc + .price { margin-top:14px; }
.menuRows .svcInc { margin:0 0 14px; }
.rest .svcInc { margin-top:8px; }

/* The featured card is filled with the accent color, so the list inherits
   dim body text on a dark ground and ticks drawn in the same color as the
   background behind them. Both were invisible. */
.featRest .featured .svcInc li { color:var(--accent-ink-soft); }
.featRest .featured .svcInc li::before { border-color:var(--accent-ink); }

/* The asterisk on a services heading, pointing at the note under the section.
   Superscript and lighter, so it reads as a footnote marker rather than as
   part of the heading. */
h2 .ast { font-size:.5em; vertical-align:super; margin-left:.15em;
  color:var(--dim); font-weight:400; }
.featRest .featured .svcInc + .price { margin-top:14px; }

/* story-latest — the homepage's ONE job story (dna.js SEC['story-latest']).
   Photo is the proof, so it gets the bigger column; the phone stacks photo
   first because that is what a homeowner actually judges. */
.storyFeat { display:grid; grid-template-columns:1.15fr 1fr; gap:26px; align-items:center; }
.storyFeat .sfPhoto { display:block; min-height:300px; border-radius:12px;
  background-size:cover; background-position:center; }
.storyFeat .sfMeta { font-size:var(--step--1); letter-spacing:.08em; text-transform:uppercase;
  color:var(--dim); margin-bottom:8px; }
.storyFeat h3 { font-size:var(--step-2); margin:0 0 10px; }
.storyFeat p { color:var(--ink); margin:0 0 16px; }
.storyFeat .sfMore { font-weight:var(--w-semi); text-decoration:none; color:var(--ink);
  border-bottom:2px solid var(--accent); padding-bottom:2px; }
.storyFeat .sfMore.quiet { border-bottom-color:transparent; color:var(--dim); margin-left:14px; }
@media (max-width:700px) {
  .storyFeat { grid-template-columns:1fr; gap:16px; }
  .storyFeat .sfPhoto { min-height:220px; }
}

/* ============================================================
   Sorting question · how it works · final CTA
   Ported from the demo stylesheet (site/showcase/preview/assets/dna.css)
   alongside the three renderers in dna.js. Appended rather than woven in:
   every selector here is a new class, so nothing above it changes, and the
   media queries travel with the rules they modify instead of being filed
   into breakpoint blocks two hundred lines apart.
   ============================================================ */

/* Anything using class="lead" used to render as plain body text flush
   against its heading. Dim, a step up from body, capped at a readable
   measure. */
p.lead { color:var(--dim); font-size:var(--step-1); max-width:62ch; margin-bottom:6px; }

/* ---- the sorting question ----
   Doors, not cards: each one is a situation the reader either is or is not
   in, so they stop at theirs and skip the rest. The accent edge on top is
   the only ornament — a door that competes with the services section below
   it makes the reader choose twice. */
.sortDoors { display:grid; grid-template-columns:repeat(auto-fit,minmax(228px,1fr)); gap:var(--s2); margin-top:22px; }
/* Bold schools head each door with the accent top-rule (--rule); quiet
   schools carry the doors on a background shift + the shadow ramp instead
   (see the design-pass layer at the end of this file). */
.sortDoor { background:var(--soft); border:var(--cardBorder); border-top:var(--rule); border-radius:var(--radius);
  padding:20px 20px 22px; display:flex; flex-direction:column; }
.sortDoor h3 { font-family:var(--disp); font-weight:var(--w-semi); font-size:var(--step-2); letter-spacing:var(--dispSpace); margin-bottom:7px; }
.sortDoor p { color:var(--ink); font-size:var(--step-0); line-height:1.6; }
/* The routing line sits at the foot of every door on the same baseline,
   whatever length the body above it ran to. */
.sortDoor p.sortNext { color:var(--ink); font-weight:var(--w-semi); font-size:var(--step--1); margin-top:auto; padding-top:11px;
  border-top:1px solid var(--line); }
.sortDoor p.sortNext + p { margin-top:0; }
.sortNote { margin-top:16px; font-size:var(--step-0); color:var(--dim); max-width:62ch; }
/* A door that links to its page is an <a>, so it needs the anchor styling
   undone and a state that says it is clickable. Without this the whole door
   inherits link color and underline and stops reading as a panel. */
a.sortDoor { text-decoration:none; color:inherit; transition:border-color .15s, transform .15s; }
/* A door that goes somewhere has to LOOK like it goes somewhere. Hover is
   not an affordance on a phone, where most of this traffic is, so the
   routing line carries the arrow — a reader who has just recognized
   themselves needs to see that recognizing was the click. */
a.sortDoor .sortNext::after { content:" →"; color:var(--accent-text,var(--accent)); font-weight:var(--w-semi); }
a.sortDoor:hover { border-color:var(--accent); transform:translateY(-2px); }
a.sortDoor:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }

/* ---- how it works ----
   Four beats across. Stacked vertically it reads as a second copy of
   whatever numbered flow is already on the page. */
.howSteps { list-style:none; margin:var(--s3) 0 0; padding:0; display:grid; grid-template-columns:repeat(4,1fr); gap:var(--s3); }
.howStep { position:relative; padding-top:var(--s2); border-top:2px solid var(--line); }
.howStep:first-child { border-top-color:var(--accent); }
.howNum { display:block; font-family:var(--disp); font-weight:var(--dispWeight); font-size:var(--step-3); line-height:1;
  color:var(--accent-text, var(--accent)); margin-bottom:9px; }
.howStep b { display:block; font-size:var(--step-0); font-weight:var(--w-semi); line-height:1.4; }
.howStep p { margin-top:6px; color:var(--ink); font-size:var(--step-0); line-height:1.6; }
.howNote { margin-top:20px; font-size:var(--step--1); color:var(--dim); max-width:62ch; }

/* ---- the last thing on the page ---- */
.finalCta { background:var(--accent-wash); border-top:0; padding:56px 0 60px; }
.finalCta h2 { font-size:var(--step-4); max-width:20ch; }
.finalCta p { margin-top:12px; color:var(--dim); font-size:var(--step-1); max-width:56ch; }
.finalCta .ctaRow { margin-top:var(--s3); }

/* Four beats across needs roughly 190px a column to hold a five-word line. */
@media (max-width:760px) {
  .howSteps { grid-template-columns:1fr 1fr; gap:22px; }
}
/* One beat per row, numeral inline beside it — stacked above, a 30px
   numeral on its own line costs more height than the beat it counts. */
@media (max-width:560px) {
  .howSteps { grid-template-columns:1fr; gap:15px; }
  .howStep { display:grid; grid-template-columns:24px 1fr; column-gap:12px; padding-top:12px; }
  .howNum { grid-row:1 / span 2; font-size:22px; margin-bottom:0; }
  .howStep b { font-size:16px; }
  .finalCta { padding:44px 0 48px; }
  .finalCta h2 { max-width:none; }
}

/* ---- the photo ask ----
   Ranked by friction, so the first way in is visually the loudest. The rest
   are available without competing: a reader who wants the form should find
   it, not be sold it. */
.photoAsk .askWays { display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:var(--s2); margin-top:20px; }
.askWay { display:block; text-decoration:none; color:inherit; background:var(--soft); border:var(--cardBorder);
  border-radius:var(--radius); padding:18px 18px 20px; transition:border-color .15s, transform .15s; }
.askWay b { display:block; font-family:var(--disp); font-weight:var(--w-semi); font-size:var(--step-1); letter-spacing:var(--dispSpace); }
.askWay span { display:block; margin-top:6px; color:var(--ink); font-size:var(--step-0); line-height:1.6; }
.askWay.first { background:var(--accent); border-color:var(--accent); }
.askWay.first b, .askWay.first span { color:var(--accent-ink,#fff); }
/* hand-picked on-accent shade, not opacity — same composite the old .9 had */
.askWay.first span { color:var(--accent-ink-soft); }
.askWay:hover { border-color:var(--accent); transform:translateY(-2px); }
.askWay:focus-visible { outline:2px solid var(--accent); outline-offset:3px; }
.askNote { margin-top:14px; font-size:var(--step--1); color:var(--dim); max-width:62ch; }

/* ---- a spec list, folded away ---- */
.specs { border:var(--cardBorder); border-radius:var(--radius); background:var(--soft); padding:0 18px; }
.specs summary { cursor:pointer; padding:16px 0; font-weight:var(--w-semi); font-size:var(--step-0); list-style:none; }
.specs summary::-webkit-details-marker { display:none; }
/* The caret is the only thing telling a reader this opens, so it is drawn
   rather than left to the browser default, which differs per platform and
   disappears entirely on some. */
.specs summary::before { content:"+"; display:inline-block; width:1.1em; color:var(--accent-text,var(--accent)); font-weight:var(--w-semi); }
.specs[open] summary::before { content:"−"; }
.specs[open] summary { border-bottom:1px solid var(--line); }
.specIntro { padding-top:14px; color:var(--dim); font-size:var(--step-0); line-height:1.65; max-width:62ch; }
.specItems { margin:12px 0 0; padding:0 0 4px; list-style:none; display:grid;
  grid-template-columns:repeat(auto-fit,minmax(210px,1fr)); gap:6px 22px; }
.specItems li { font-size:var(--step--1); color:var(--dim); padding-left:14px; position:relative; }
.specItems li::before { content:""; position:absolute; left:0; top:.62em; width:6px; height:1px; background:var(--accent); }
.specNote { padding:12px 0 18px; font-size:var(--step--1); color:var(--dim); max-width:62ch; }

/* ---- the quote form ----
   The one section that has to work rather than read well, so it is built to
   be filled in on a phone with one thumb: full-width controls, a target big
   enough to hit, and no field that punishes not knowing the answer. */
.quoteSec .qbig { margin-top:22px; max-width:760px; }
.laneRow { display:flex; flex-wrap:wrap; gap:8px; margin-bottom:20px; }
.laneBtn { border-color:var(--edge); font:inherit; font-weight:var(--w-semi); font-size:var(--step-0); padding:11px 16px; cursor:pointer;
  background:var(--soft); color:var(--ink); border:var(--cardBorder); border-radius:var(--radius); }
.laneBtn:hover { border-color:var(--accent); }
.laneBtn.on { background:var(--accent); border-color:var(--accent); color:var(--accent-ink,#fff);
  font-weight:var(--w-semi); }
/* Colour was the ONLY signal that a lane was chosen — on the control that
   rewrites the rest of the form. Generated content is read by NVDA and
   JAWS, so the tick carries the state into audio as well as into hue. */
.laneBtn.on::before { content:"\2713\00a0"; font-weight:900; }
.laneBtn:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
.qgrid { display:grid; grid-template-columns:1fr 1fr; gap:14px 18px; margin-bottom:18px; }
.qgrid[hidden] { display:none; }
label.qf { display:flex; flex-direction:column; gap:6px; font-size:var(--step--1); font-weight:var(--w-semi); color:var(--ink); }
label.qf.wide { grid-column:1 / -1; }
label.qf input, label.qf textarea { font:inherit; font-weight:400; font-size:16px; /* 16px or iOS zooms on focus */
  padding:11px 12px; border:1px solid var(--edge); border-radius:calc(var(--radius) - 2px);
  background:var(--bg); color:var(--ink); width:100%; }
label.qf input:focus, label.qf textarea:focus { outline:2px solid var(--accent); outline-offset:1px; border-color:var(--accent); }

/* The photo picker. The native file input is hidden behind its own label,
   because "Choose files / no file chosen" is the least inviting control on
   the web and this is the thing we most want pressed. */
.shotBox { margin:4px 0 20px; }
.shotBox input[type=file] { position:absolute; width:1px; height:1px; opacity:0; }
.shotPick { display:block; cursor:pointer; padding:18px; text-align:center;
  border:2px dashed var(--line); border-radius:var(--radius); background:var(--soft); }
.shotPick:hover { border-color:var(--accent); }
/* Deleted: `input:focus-visible ~ .shotPick` can never match — .shotPick is
   the input’s PRECEDING sibling and ~ only looks forward. Its partner
   `+ .shots` was cancelled by an outline:none 100 lines below. So both
   rules written for this control’s focus ring did nothing, and the ring
   you actually see comes from .shotBox:focus-within, written for something
   else. Two dead rules made a real indicator look deliberate. */
.shotPick b { display:block; font-family:var(--disp); font-weight:var(--w-semi); font-size:var(--step-1); letter-spacing:var(--dispSpace); }
.shotPick span { display:block; margin-top:5px; color:var(--dim); font-size:var(--step--1); line-height:1.55; }
.shots { display:flex; flex-wrap:wrap; gap:8px; margin-top:10px; }
.shot { display:flex; gap:8px; align-items:baseline; font-size:var(--step--1); padding:7px 11px;
  border:1px solid var(--line); border-radius:999px; background:var(--bg); }
.shot span { font-weight:var(--w-semi); max-width:22ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.shot em { font-style:normal; color:var(--dim); }
.shot.ok { border-color:var(--accent); }
.shot.ok em { color:var(--accent-text,var(--accent)); font-weight:var(--w-semi); }
/* A failed upload has to look failed. Silent is indistinguishable from fine,
   and the reader needs to know the picture did not arrive while they are
   still on the page and can do something about it. */
.shot.bad { border-color:#c0392b; }
.shot.bad em { color:#c0392b; font-weight:var(--w-semi); }
.qbig .qsend { margin-top:2px; }
.qbig .formMsg { margin-top:12px; font-size:var(--step-0); color:var(--dim); }

@media (max-width:620px) {
  .qgrid { grid-template-columns:1fr; gap:14px; }
  .laneBtn { flex:1 1 100%; text-align:left; }
}

/* ---- gallery captions on a phone ----
   At 390px the two-column grid gives each tile about 170px of width, and a
   four-line caption laid over it stops being a caption and becomes a lid —
   measured at 55% to 127% of the image area across three different client
   sites. The photograph is the evidence; the caption is the footnote, and
   the footnote was winning.

   One column, and the caption sits BELOW the frame rather than on it. Found
   by phone-check.mjs, which exists because every other gate we own was green
   while this shipped. */
/* ONE COLUMN, and that is the whole fix.
   The fault was never the overlay — it was two columns at 390px giving each
   tile ~170px of width, so a four-line caption covered up to 127% of its own
   photograph. At full width the overlay is fine and it is what the desktop
   already does well.
   The first attempt also moved the caption below the frame, which broke it
   worse: the tile's background covers whatever the tile contains, so the
   caption sat on the image with no scrim behind it, in dark ink, and the
   first tile — which kept a fixed aspect ratio — clipped its caption away
   entirely. Four captions unreadable, three missing. Reverted to the shape
   that works, at a width where it works. */
@media (max-width:560px) {
  .tiles { grid-template-columns:1fr; }
  .tiles .gtile:first-child { grid-column:auto; aspect-ratio:4/3; }
  .gtile .cap { font-size:14px; padding:30px 14px 12px; }
  .gtile .anno { display:none; }
}

/* ---- the phone masthead, and buttons that split a phone number ----
   Both found by phone-check.mjs after a visual judge saw them in five
   seconds on a device every other gate had been "checking" all week.

   THE MASTHEAD. "Innovative Welding Solutions" wrapped onto THREE lines at
   390px on all five pages, eating ~175px before anything else and reading as
   a page that failed to load. The name is the client's and cannot be
   shortened, so the type comes down and the row is allowed two lines with
   the nav beneath it, which is what a masthead does on a phone anyway.

   THE BUTTONS. A two-up .ctaRow at 390px gives each button ~170px, and
   "Call (720) 309-7976" does not fit — so the primary conversion control on
   the closing block rendered as "Call (720) 309- / 7976", a phone number
   hyphenated in half. Full width, one per row, and nothing breaks. */
@media (max-width:560px) {
  .topRow { flex-wrap:wrap; row-gap:10px; padding-top:12px; padding-bottom:12px; }
  .logo { font-size:15.5px; line-height:1.15; max-width:64%; }
  nav.mainNav { gap:10px; }
  nav.mainNav a { font-size:14px; }

  .ctaRow { flex-direction:column; align-items:stretch; gap:10px; }
  .ctaRow .btn { width:100%; text-align:center; white-space:nowrap; }
  /* The sticky bar is already full width; this stops the label breaking if a
     business has a longer number or a longer verb in front of it. */
  .callbar a { white-space:nowrap; }
}

/* ---- metal in the phone hero ----
   The editorial hero HID its photograph below 900px (`.edPhoto { display:none }`),
   so the first screen of a metal fabricator's site on a phone contained no
   metal: eyebrow, headline, paragraph, two buttons, nothing.

   The first fix showed it again and earned a second finding: the comment here
   claimed "grid order puts it between the text and the CTA row", and no order
   property existed -- the photo is the LAST child, so it rendered after the
   paragraph, both buttons and the stat row: a sliver at the bottom of the
   first screen with the sticky bar across it. A judge measured it at y~776 of
   844.

   Now the order is real. The text column becomes display:contents at phone
   width, which makes its children grid items alongside the photo, and every
   item is placed explicitly: headline, THEN the photograph, then the
   paragraph and the buttons. The visitor gets the words and the metal in the
   same screenful. */
@media (max-width:900px) {
  .heroEditorial.hasPhoto .edCols > div:first-child { display:contents; }
  .heroEditorial.hasPhoto .kicker { order:1; }
  .heroEditorial.hasPhoto .rule { order:2; }
  .heroEditorial.hasPhoto h1 { order:3; }
  .heroEditorial.hasPhoto .edPhoto { order:4; display:block; min-height:0; height:190px; margin:18px 0 2px; }
  .heroEditorial.hasPhoto .tag { order:5; }
  .heroEditorial.hasPhoto .ctaRow { order:6; }
  .heroEditorial.hasPhoto .metaRow { order:7; }
}
@media (max-width:560px) {
  .heroEditorial.hasPhoto .edPhoto { height:168px; }
}

/* One page, one leading. Hero and CTA headings were set tight (~1.05) while
   section h2s inherited loose line-height, so two-line section headings
   drifted apart while two-line hero headings locked up -- same typeface,
   same page. */
section > h2, .band h2 { line-height:1.14; }

/* The picker's actual button. See the note in dna.js: the dashed panel alone
   read as a note, so the highest-value action on the site was invisible. */
.shotPick .shotBtn { display:inline-block; margin-top:14px; padding:11px 20px;
  background:var(--accent); color:var(--accent-ink,#fff); border-radius:var(--btnRadius,999px);
  font-family:var(--disp); font-weight:var(--w-semi); font-size:15px; letter-spacing:var(--dispSpace); }
.shotPick:hover .shotBtn { filter:brightness(.94); }
.shotBox input[type=file]:focus-visible + .shots { outline:none; }
.shotBox:focus-within .shotPick { border-color:var(--accent); }
.shotBox:focus-within .shotBtn { outline:2px solid var(--accent); outline-offset:3px; }

/* The current page in the nav — a marker, not a link that goes nowhere. */
nav.mainNav .navHere { font-weight:var(--w-semi); color:var(--accent-text,var(--accent));
  border-bottom:2px solid var(--accent); padding-bottom:2px; font-size:15px; }

/* A two-route sticky bar. The single Call button was the only control always
   on screen, on sites whose copy says four times over that texting is the
   fastest way to a price — so the faster route was four screens down and the
   slower one was permanently in the thumb's reach. */
/* Inside the breakpoint that shows the bar at all. Declared outside it, the
   `display:flex` overrode `.callbar { display:none }` and the sticky bar
   appeared at the foot of every DESKTOP page — a phone control on a laptop,
   introduced by the fix that was meant to improve it. Caught by looking at
   the desktop screenshot after changing a phone rule, which is the whole
   argument for looking at both. */
@media (max-width:760px) {
  .callbar.two { display:flex; gap:0; }
  .callbar.two a { flex:1 1 50%; text-align:center; }
  .callbar.two .barAlt { flex:1 1 62%; background:var(--accent); color:var(--accent-ink,#fff); }
  .callbar.two a + a { border-left:1px solid rgba(255,255,255,.28); }
}
@media (max-width:560px) { nav.mainNav .navHere { font-size:14px; } }

/* ============================================================
   Desktop polish, from a visual read of the finished build.
   ============================================================ */

/* A gallery of four in a two-column grid leaves the fourth alone in the left
   column with ~490px of white beside it — the most visible layout fault on
   desktop. Three tiles is the shape that works (one wide, two under); four
   now fills the row instead of orphaning. */
.tiles .gtile:nth-child(4):last-child { grid-column:span 2; aspect-ratio:21/8; }
/* And the two-image case: a wide feature with one half tile under it left
   the other half of the row empty — dead space that read as a missing
   photograph. The second image goes wide too, at a shallower cut than the
   feature so the pair still reads as feature-then-detail.
   min-width scoped, because this sits LATER in the file than the 560px
   one-column block and was overriding it — a 21/10 sliver on a phone whose
   caption covered half the photograph. */
@media (min-width:561px) {
  .tiles .gtile:nth-child(2):last-child { grid-column:span 2; aspect-ratio:21/10; }
}

/* Caption legibility. White type on a pale grey wall was the least readable
   text on the site — the scrim was too weak and too short to sit under it. */
.gtile .cap { background:linear-gradient(transparent, rgba(0,0,0,.30) 35%, rgba(0,0,0,.72));
  padding:26px 14px 12px; text-shadow:0 1px 3px rgba(0,0,0,.55); }

/* A cool grey card inside a warm blush band was the one off-key colour on the
   site. Inside a tinted band the cards take the band's own warmth. */
.tintband .askWay:not(.first) { background:color-mix(in srgb, var(--accent) 5%, #fff); border-color:color-mix(in srgb, var(--accent) 18%, var(--line)); }

/* The service-area strip read as something left over: heading, pills and a
   line crammed into ~150px between two bands. */
.chips { margin-top:16px; }
section .areaNote, .chips + p { margin-top:14px; }

/* Closing headlines were set looser than every other heading on the site,
   including the H1s. */
.finalCta h2 { line-height:1.12; }

/* The rule under the hero separates the stat row. On pages with no stat row
   it sat alone, dividing nothing. */
.heroEditorial .rule:last-child, .heroEditorial .metaRow:empty { display:none; }
.heroEditorial .metaRow:empty + .rule { display:none; }

/* Card internals: a two-line title pushed its body down and left the footer
   rule crowding the last line, while its siblings had air. Bodies stretch so
   the rules line up. */
.sortDoor p:not(.sortNext) { flex:1 1 auto; }

/* No authored placeholder colour meant the browser default: Chrome lands at
   4.61:1 and Firefox near 3.57:1, and these placeholders carry real
   instructions rather than repeating the label. */
label.qf ::placeholder, .qform ::placeholder { color:#6B7885; opacity:1; }

/* Visible only on keyboard focus. A skip link that is always on screen is a
   design problem; one that never appears is not a skip link. */
.skipLink { position:absolute; left:-9999px; top:0; z-index:100; background:var(--ink);
  color:var(--bg); padding:12px 18px; font-weight:var(--w-semi); border-radius:0 0 8px 0; }
.skipLink:focus { left:0; }

/* ============================================================
   DESIGN PASS — per-school temperament layer (Direction B port,
   2026-08-19). The tokens at the top carry the shared discipline
   (three weights, the scale, 8px spacing, the accent ramp); this
   layer spends it per school. Bold schools separate with LINE +
   SPACE and use the accent top-rule (--rule) as the page's one
   accent-line idiom. Quiet schools separate with BACKGROUND
   SHIFT + the shadow ramp and carry no accent lines at all.
   Every selector here is additive — nothing above it changes,
   and the a11y work (skip links, focus rings, aria) is untouched.
   ============================================================ */

/* ---- QUIET (calm, warm): background shift + shadow ---- */
[data-school="calm"] header.top, [data-school="warm"] header.top {
  border-bottom:0; box-shadow:var(--shadow-1); }
[data-school="calm"] .sortDoor, [data-school="warm"] .sortDoor {
  border-top:0; background:var(--bg); box-shadow:var(--shadow-2); }
[data-school="calm"] .sortDoor p.sortNext, [data-school="warm"] .sortDoor p.sortNext {
  border-top:0; color:var(--accent-text); }
[data-school="calm"] a.sortDoor:hover, [data-school="warm"] a.sortDoor:hover { box-shadow:var(--shadow-3); }
/* the flagship service moves to the DEEP step of the ramp, so the accent
   fill stops being asked to be a whole palette */
[data-school="calm"] .featRest .featured, [data-school="warm"] .featRest .featured {
  background:var(--accent-deep); box-shadow:var(--shadow-2); }
[data-school="calm"] .featRest .featured p, [data-school="warm"] .featRest .featured p,
[data-school="calm"] .featRest .featured .svcInc li, [data-school="warm"] .featRest .featured .svcInc li {
  color:var(--deep-ink-soft); }
[data-school="calm"] .spotlight .mark, [data-school="warm"] .spotlight .mark { color:var(--accent-deep); }
/* quiet secondary button: soft fill on the first shadow step, no border */
[data-school="calm"] .btn.ghost, [data-school="warm"] .btn.ghost {
  border:0; background:var(--soft); color:var(--ink); box-shadow:var(--shadow-1); }
[data-school="calm"] .finalCta .btn.ghost, [data-school="warm"] .finalCta .btn.ghost { background:var(--bg); }
/* …except on photo scrims, where the ghost must stay a white outline */
[data-school="calm"] .heroOverlay .btn.ghost, [data-school="warm"] .heroOverlay .btn.ghost,
[data-school="calm"] .heroFormOv .btn.ghost, [data-school="warm"] .heroFormOv .btn.ghost {
  border:1.5px solid #fff; background:transparent; color:#fff; box-shadow:none; }
[data-school="calm"] footer.bottom, [data-school="warm"] footer.bottom {
  border-top:0; background:var(--soft); padding:var(--s5) 0; }

/* ---- BOLD (trade, editorial, darkpremium): the ruled card ---- */
[data-school="trade"] .strength, [data-school="editorial"] .strength, [data-school="darkpremium"] .strength {
  border-top:var(--rule); background:var(--soft); border-radius:var(--radius); padding:20px 22px; }

/* ---- TRADE — "trade bold" (Direction B, approved 2026-08-18) ----
   The discipline spent loud: a huge display step (--h1 to 88px),
   small-caps Archivo kickers, chunky uppercase buttons, thick accent
   top-rules, and the deep band anchoring the quote and the close. */
[data-school="trade"] .logo { font-size:21px; }
[data-school="trade"] .kicker { font-family:var(--disp); letter-spacing:.2em; }
[data-school="trade"] .heroEditorial h1 { line-height:1.0; }
[data-school="trade"] .heroEditorial .rule { height:3px; background:var(--ink); opacity:1; }
[data-school="trade"] .heroEditorial .metaRow b { font-size:var(--step-3); }
[data-school="trade"] .heroEditorial .metaRow div { text-transform:uppercase; letter-spacing:.06em; }
@media (min-width:641px) {
  [data-school="trade"] .heroEditorial .metaRow { margin-top:var(--s5); gap:var(--s4); }
}
[data-school="trade"] .btn { font-family:var(--disp); font-size:15px; text-transform:uppercase;
  letter-spacing:.05em; padding:17px 30px; }
[data-school="trade"] .btn.ghost { border:2px solid var(--ink); }
[data-school="trade"] .heroOverlay .btn.ghost, [data-school="trade"] .heroFormOv .btn.ghost { border-color:#fff; }
[data-school="trade"] nav.mainNav a.navCta { text-transform:uppercase; letter-spacing:.04em; font-size:var(--step--1); }
/* THE strong band: the customer's words on the deep shade */
[data-school="trade"] .tintband:has(.spotlight) { background:var(--accent-deep); }
[data-school="trade"] .tintband:has(.spotlight) .spotlight .mark { color:var(--deep-ink-soft); }
[data-school="trade"] .tintband:has(.spotlight) .spotlight p { color:#fff; }
[data-school="trade"] .tintband:has(.spotlight) .spotlight .who { color:var(--deep-ink-soft);
  text-transform:uppercase; letter-spacing:.08em; }
/* the close: deep again, bookending the quote band */
[data-school="trade"] .finalCta { background:var(--accent-deep); }
[data-school="trade"] .finalCta h2 { color:#fff; }
[data-school="trade"] .finalCta p { color:var(--deep-ink-soft); }
[data-school="trade"] .finalCta .btn.primary { background:#fff; color:var(--ink); }
[data-school="trade"] .finalCta .btn.ghost { border-color:#fff; color:#fff; }

/* The thumb bar steps aside while the page’s own closing buttons are on
   screen (see the observer beside hasCallbar in dna.js). */
body.ctaOnScreen .callbar { transform:translateY(110%); transition:transform .25s; }
.callbar { transition:transform .25s; }
