/* ═══════════════════════════════════════════════════════════════════════════
   ⛔ HAND-EDITED ON PURPOSE — 23 Sep 2026. THIS FILE HAS DIVERGED FROM ITS
   SOURCE, AND THE DIVERGENCE IS THE POINT.

   public/demo/<name> is normally GENERATED from ~/Desktop/demo-<name>/dist by
   tools/sync-demo.mjs, and the generated headers say never to hand-edit it.
   The hero, type and offer-strip pass below was written HERE, directly, with
   the owner's decision, because:

   - the sources live OUTSIDE this repo, are untracked and are unbacked; and
   - for at least one demo the source provably does NOT reproduce the published
     copy — a rebuild loses photo bands, self-hosted fonts and the town.

   public/demo IS committed to git, so this work is recoverable and reviewable
   and the source is neither.

   ⛔ THEREFORE: do NOT run tools/sync-demo.mjs or any build.py against this
   folder. A sync would silently revert everything below and every page would
   still render, which is exactly the failure mode that costs days here.
   Reconcile the source to THIS file first, or delete the source.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Sable Ridge Tree Care — demonstration site
   Design direction: FIELD NOTEBOOK. Warm paper, ink brown, one deep green,
   one dry-bark tan. Hairline rules and air instead of boxes and shadows.
   No external requests of any kind. System fonts only. */

:root{
  --paper:      #f6f2e7;
  --paper-2:    #efeadc;   /* faint tint for specimen blocks */
  --ink:        #241f18;   /* near-black, warm */
  --ink-soft:   #554c3f;
  --ink-faint:  #857a69;
  --paper-3:    #f9f6ee;   /* lifted paper, for plates and cards */
  --green:      #26483a;   /* deep green — canopy in shade */
  --green-soft: #3d6a56;
  --green-deep: #14302a;   /* shadow green — wet bark under canopy */
  --green-new:  #7d9a55;   /* new growth — spring flush on a live oak */
  --rust:       #9c4a24;   /* fall rust — one accent, used sparingly */
  --rust-soft:  #c2764b;
  --tan:        #a98a5f;   /* dry bark */
  --tan-soft:   #c8ae86;
  --rule:       rgba(36,31,24,.20);
  --rule-soft:  rgba(36,31,24,.11);
  --hatch:      rgba(38,72,58,.05);   /* botanical hatch, gradient-built */
  --ease:       cubic-bezier(.22,.61,.36,1);

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua",
           Georgia, "Times New Roman", serif;
  --sans:  system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
           Arial, sans-serif;
  --mono:  ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
           "Liberation Mono", monospace;
}

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

html{ -webkit-text-size-adjust:100%; }

body{
  margin:0;
  /* paper TONE, not one dead cream: a warm sheet lit from the upper right,
     cooling and deepening toward the foot of the page. */
  background-color:var(--paper);
  background-image:
    radial-gradient(1100px 620px at 82% -6%, rgba(255,253,246,.95) 0%, rgba(255,253,246,0) 60%),
    radial-gradient(760px 520px at 6% 22%, rgba(169,138,95,.06) 0%, rgba(169,138,95,0) 64%),
    linear-gradient(180deg, #f9f6ee 0%, #f6f2e7 38%, #f4efe2 72%, #f0e9d9 100%);
  background-repeat:no-repeat;
  background-size:100% 100%;
  color:var(--ink);
  font-family:var(--serif);
  font-size:17px;
  line-height:1.62;
  overflow-x:hidden;
}

/* ---------- demonstration strip ---------- */
.demostrip{
  display:flex; gap:.7rem; align-items:flex-start;
  padding:.7rem 1.1rem;
  background:var(--green);
  color:#f2eede;
  font-family:var(--sans);
  font-size:12.5px;
  line-height:1.5;
  letter-spacing:.005em;
}
.demostrip b{ font-weight:650; }
.demostrip a{ color:#e7d7b4; text-decoration:underline; text-underline-offset:2px; }
.demostrip a:hover{ color:#fff; }
.demostrip__dot{
  flex:0 0 auto; width:8px; height:8px; margin-top:.42rem;
  border-radius:50%; background:var(--tan-soft);
}

/* ---------- layout ---------- */
.wrap{ width:100%; max-width:1060px; margin:0 auto; padding:0 22px; }
.wrap--narrow{ max-width:760px; }

section{ padding:0; }
.band{ padding:56px 0; border-top:1px solid var(--rule-soft); }
.band--first{ border-top:0; }
.band--tint{ background:var(--paper-2); }

/* ---------- masthead ---------- */
.masthead{ padding:26px 0 18px; }
.masthead__row{
  display:flex; flex-wrap:wrap; gap:14px 24px;
  align-items:baseline; justify-content:space-between;
}
.wordmark{ text-decoration:none; color:inherit; display:block; }
.wordmark__name{
  font-family:var(--serif); font-size:25px; line-height:1.1;
  letter-spacing:.005em;
}
.wordmark__rule{
  height:1px; background:var(--tan); margin:.42rem 0 .34rem; width:100%;
}
.wordmark__sub{
  font-family:var(--sans); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.19em; color:var(--ink-faint);
}
.masthead__contact{
  font-family:var(--mono); font-size:13px; color:var(--ink-soft);
  text-align:right; line-height:1.7;
}
.masthead__contact a{ color:var(--green); text-decoration:none; border-bottom:1px solid var(--tan-soft); }
.masthead__contact a:hover{ color:var(--ink); }

nav.nav{ border-top:1px solid var(--rule); border-bottom:1px solid var(--rule); }
.nav__list{
  display:flex; flex-wrap:wrap; gap:0 26px;
  list-style:none; margin:0; padding:10px 0;
  font-family:var(--sans); font-size:12.5px;
  text-transform:uppercase; letter-spacing:.11em;
}
.nav__list a{ color:var(--ink-soft); text-decoration:none; padding:3px 0; display:inline-block; }
.nav__list a:hover{ color:var(--green); }
.nav__list a[aria-current="page"]{
  color:var(--ink); border-bottom:1.5px solid var(--tan);
}

/* ---------- type ---------- */
h1,h2,h3,h4{ font-family:var(--serif); font-weight:600; color:var(--ink); }
h1{ font-size:clamp(30px,5.2vw,46px); line-height:1.12; letter-spacing:-.005em; margin:.1em 0 .35em; font-weight:500; }
h2{ font-size:clamp(23px,3.4vw,31px); line-height:1.2; margin:0 0 .5em; font-weight:500; }
h3{ font-size:19px; line-height:1.3; margin:1.9em 0 .4em; font-weight:600; }
h4{ font-size:16px; margin:1.5em 0 .3em; font-weight:600; }
p{ margin:0 0 1.05em; }
a{ color:var(--green); }
strong{ font-weight:650; }

.eyebrow{
  font-family:var(--sans); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.2em; color:var(--tan); margin:0 0 1.1em;
  display:block;
}
.eyebrow--green{ color:var(--green-soft); }
.lede{ font-size:clamp(18px,2.3vw,21px); line-height:1.55; color:var(--ink-soft); }
.small{ font-family:var(--sans); font-size:13.5px; line-height:1.62; color:var(--ink-soft); }
.caption{
  font-family:var(--sans); font-size:11.5px; line-height:1.55;
  color:var(--ink-faint); letter-spacing:.02em;
}
.num{ font-family:var(--mono); font-variant-numeric:tabular-nums; }
.rule{ height:1px; background:var(--rule); border:0; margin:2.4rem 0; }
.rule--short{ width:64px; height:1px; background:var(--tan); border:0; margin:1.6rem 0; }

ul.list, ol.list{ margin:0 0 1.1em; padding-left:1.15em; }
ul.list li, ol.list li{ margin:0 0 .55em; padding-left:.2em; }
ul.list{ list-style:none; padding-left:0; }
ul.list > li{ position:relative; padding-left:1.1em; }
ul.list > li::before{
  content:""; position:absolute; left:0; top:.72em;
  width:7px; height:1px; background:var(--tan);
}

/* ---------- hero ---------- */
.hero{ padding:44px 0 8px; }
.hero__grid{ display:grid; grid-template-columns:1fr; gap:34px; align-items:start; }
@media(min-width:900px){
  .hero__grid{ grid-template-columns:1.05fr .95fr; gap:52px; }
}
.hero h1{ max-width:14ch; }

/* ---------- botanical plate (inline SVG) ---------- */
.plate{
  border:1px solid var(--rule);
  padding:16px 16px 12px;
  background:#faf7ef;
}
.plate svg{ display:block; width:100%; height:auto; }
.plate__cap{
  display:flex; justify-content:space-between; gap:12px;
  border-top:1px solid var(--rule-soft); margin-top:10px; padding-top:8px;
}

/* ---------- work order / specimen card ---------- */
.card{
  border:1px solid var(--ink);
  background:#fbf8f1;
  padding:0;
}
.card__head{
  padding:18px 20px 14px;
  border-bottom:1px solid var(--ink);
  display:flex; flex-wrap:wrap; gap:10px 26px; justify-content:space-between; align-items:flex-end;
}
.card__title{ font-family:var(--serif); font-size:20px; line-height:1.2; margin:0; font-weight:600; }
.card__meta{ font-family:var(--mono); font-size:12px; color:var(--ink-soft); line-height:1.7; }
.card__meta b{ color:var(--ink); font-weight:600; }
.card__body{ padding:4px 20px 18px; }

.wo{ border-collapse:collapse; width:100%; }
.wo caption{
  text-align:left; font-family:var(--sans); font-size:10.5px;
  letter-spacing:.18em; text-transform:uppercase; color:var(--ink-faint);
  padding:14px 0 8px;
}
.wo th{
  font-family:var(--sans); font-size:10px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--ink-faint); font-weight:600;
  text-align:left; padding:0 0 7px; border-bottom:1px solid var(--ink);
}
.wo th.r, .wo td.r{ text-align:right; }
.wo td{
  padding:13px 0; border-bottom:1px solid var(--rule-soft);
  vertical-align:top;
}
.wo tr:last-child td{ border-bottom:0; }
.wo .sp{ font-family:var(--serif); font-style:italic; color:var(--ink-soft); }
.wo .amt{ font-family:var(--mono); font-size:14px; white-space:nowrap; padding-left:14px; }
.wo .what{ font-size:15.5px; }
.wo .what b{ font-weight:650; }
.wo .note{ display:block; margin-top:.35em; }
.wo__line1{ font-family:var(--sans); font-size:11px; letter-spacing:.12em; text-transform:uppercase; color:var(--ink-faint); display:block; margin-bottom:.3em; }

.wo tr.refused td{ background:var(--paper-2); }
.wo tr.refused .what b{ color:var(--green); letter-spacing:.01em; }
.wo tr.refused .amt{ color:var(--green); }
.refused-why{
  font-family:var(--sans); font-size:13.5px; line-height:1.6;
  color:var(--ink-soft); margin:.5em 0 0; max-width:62ch;
  border-left:2px solid var(--green); padding-left:12px;
}
.wo tr.total td{
  border-top:1px solid var(--ink); border-bottom:0;
  font-family:var(--sans); font-size:11px; letter-spacing:.16em;
  text-transform:uppercase; padding-top:12px;
}
.wo tr.total .amt{
  font-family:var(--mono); font-size:16px; letter-spacing:0;
  text-transform:none; color:var(--ink);
}

@media(max-width:560px){
  .wo, .wo tbody, .wo tr, .wo td{ display:block; width:100%; }
  .wo thead{ display:none; }
  .wo td{ padding:12px 0 0; border-bottom:0; }
  .wo tr{ border-bottom:1px solid var(--rule-soft); padding-bottom:12px; }
  .wo .amt{ padding-left:0; text-align:left; margin-top:.4em; }
  .wo tr.total{ border-bottom:0; }
}

/* ---------- the checkable numbers ---------- */
.figure-row{ display:grid; grid-template-columns:1fr; gap:30px; }
@media(min-width:760px){ .figure-row{ grid-template-columns:repeat(3,1fr); gap:38px; } }
.figure__n{
  font-family:var(--mono); font-size:38px; line-height:1; color:var(--green);
  letter-spacing:-.02em; display:block; margin-bottom:.35em;
}
.figure__n small{ font-size:18px; color:var(--tan); }
.figure h3{ margin:0 0 .35em; font-size:17px; }

/* ---------- two-column ragged service index ---------- */
.index{ display:grid; grid-template-columns:1fr; gap:0; }
@media(min-width:780px){ .index{ grid-template-columns:1fr 1fr; column-gap:56px; } }
.index__item{
  display:grid; grid-template-columns:auto 1fr; gap:0 18px;
  padding:22px 0; border-bottom:1px solid var(--rule-soft);
  text-decoration:none; color:inherit;
}
.index__item:hover .index__name{ color:var(--green); }
.index__item:hover .index__n{ color:var(--green); }
.index__n{
  font-family:var(--serif); font-size:30px; line-height:1; color:var(--tan-soft);
  font-variant-numeric:tabular-nums; padding-top:.06em; width:1.9em;
}
.index__name{ font-family:var(--serif); font-size:19px; line-height:1.25; margin:0 0 .25em; font-weight:600; }
.index__desc{ font-family:var(--sans); font-size:13.5px; line-height:1.55; color:var(--ink-soft); margin:0; }

/* ---------- steps ---------- */
.steps{ counter-reset:step; margin:0; padding:0; list-style:none; }
.step{
  display:grid; grid-template-columns:auto 1fr; gap:0 20px;
  padding:26px 0; border-bottom:1px solid var(--rule-soft);
}
.step__n{
  font-family:var(--mono); font-size:12px; letter-spacing:.14em;
  color:var(--tan); padding-top:.55em; white-space:nowrap;
}
.step h3{ margin:0 0 .35em; }

/* ---------- prose columns ---------- */
.two-col{ display:grid; grid-template-columns:1fr; gap:0 56px; }
@media(min-width:820px){ .two-col{ grid-template-columns:1fr 1fr; } }

.sidenote{
  border-top:1px solid var(--tan);
  padding-top:14px; margin:2rem 0;
  font-family:var(--sans); font-size:13.5px; line-height:1.62; color:var(--ink-soft);
}
.sidenote b{ color:var(--ink); }

.callout{
  border:1px solid var(--rule); padding:22px 24px; background:#faf7ef;
  margin:2rem 0;
}
.callout p:last-child{ margin-bottom:0; }

/* ---------- specs table ---------- */
.spec{ border-collapse:collapse; width:100%; margin:1.4rem 0 1.8rem; }
.spec th{
  text-align:left; font-family:var(--sans); font-size:10px; letter-spacing:.16em;
  text-transform:uppercase; color:var(--ink-faint); font-weight:600;
  padding:0 14px 8px 0; border-bottom:1px solid var(--ink);
}
.spec td{ padding:12px 14px 12px 0; border-bottom:1px solid var(--rule-soft); vertical-align:top; font-size:15.5px; }
.spec td.k{ font-family:var(--sans); font-size:13px; color:var(--ink-soft); width:36%; }
.spec td .num{ font-size:14px; }

/* ---------- faq ---------- */
.qa{ border-bottom:1px solid var(--rule-soft); padding:24px 0; }
.qa h3{ margin:0 0 .45em; }
.qa p:last-child{ margin-bottom:0; }

/* ---------- areas ---------- */
.areas{ display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)); gap:0 32px; }
.area{ padding:16px 0; border-bottom:1px solid var(--rule-soft); }
.area__name{ font-family:var(--serif); font-size:17px; font-weight:600; margin:0 0 .15em; }
.area__note{ font-family:var(--sans); font-size:12.5px; color:var(--ink-faint); margin:0; }

/* ---------- form ---------- */
.form{ display:grid; grid-template-columns:1fr; gap:20px; max-width:640px; }
@media(min-width:640px){ .form .half{ grid-column:span 1; } .form{ grid-template-columns:1fr 1fr; } .form .full{ grid-column:1 / -1; } }
label{ display:block; font-family:var(--sans); font-size:11px; letter-spacing:.14em; text-transform:uppercase; color:var(--ink-faint); margin-bottom:7px; }
input,select,textarea{
  width:100%; font-family:var(--serif); font-size:16px; color:var(--ink);
  background:transparent; border:0; border-bottom:1px solid var(--rule);
  padding:7px 0 9px; border-radius:0;
}
textarea{ min-height:120px; resize:vertical; line-height:1.6; }
input:focus,select,textarea:focus{ outline:none; }
input:focus,textarea:focus,select:focus{ border-bottom-color:var(--green); }
select{ font-family:var(--serif); }
.btn{
  display:inline-block; font-family:var(--sans); font-size:12px;
  letter-spacing:.16em; text-transform:uppercase;
  background:var(--green); color:#f4efe1; border:1px solid var(--green);
  padding:13px 26px; cursor:pointer; text-decoration:none; border-radius:0;
}
.btn:hover{ background:#1c372c; }
.btn--ghost{ background:transparent; color:var(--green); }
.btn--ghost:hover{ background:var(--green); color:#f4efe1; }
.btnrow{ display:flex; flex-wrap:wrap; gap:12px; align-items:center; margin:1.6rem 0 0; }

/* ---------- empty state (reviews) ---------- */
.empty{
  border:1px dashed var(--tan-soft); padding:44px 26px; text-align:center;
  background:#faf7ef;
}
.empty__mark{
  font-family:var(--serif); font-size:34px; color:var(--tan-soft); line-height:1;
  display:block; margin-bottom:.4em;
}

/* ---------- footer ---------- */
footer.foot{
  border-top:1px solid var(--ink); margin-top:64px; padding:38px 0 54px;
}
.foot__grid{ display:grid; grid-template-columns:1fr; gap:30px; }
@media(min-width:760px){ .foot__grid{ grid-template-columns:1.3fr 1fr 1fr; gap:44px; } }
.foot h4{ font-family:var(--sans); font-size:10px; letter-spacing:.18em; text-transform:uppercase; color:var(--ink-faint); margin:0 0 .9em; font-weight:600; }
.foot ul{ list-style:none; margin:0; padding:0; font-size:15px; }
.foot li{ margin:0 0 .42em; }
.foot a{ color:var(--ink-soft); text-decoration:none; }
.foot a:hover{ color:var(--green); }
.foot__addr{ font-family:var(--mono); font-size:12.5px; line-height:1.85; color:var(--ink-soft); }
.foot__fine{
  border-top:1px solid var(--rule-soft); margin-top:32px; padding-top:18px;
  font-family:var(--sans); font-size:11.5px; line-height:1.6; color:var(--ink-faint);
}

/* ---------- chat launcher (bottom LEFT — page runs in an iframe) ---------- */
.chat-btn{
  position:fixed; left:18px; bottom:18px; z-index:70;
  display:flex; align-items:center; gap:9px;
  font-family:var(--sans); font-size:12.5px; letter-spacing:.05em;
  background:var(--green); color:#f2eede; border:1px solid var(--green);
  padding:11px 17px; cursor:pointer; border-radius:0;
}
.chat-btn:hover{ background:#1c372c; }
.chat-btn__dot{ width:7px; height:7px; border-radius:50%; background:var(--tan-soft); flex:0 0 auto; }
.chat-panel{
  position:fixed; left:18px; bottom:18px; z-index:71;
  width:330px; max-width:calc(100vw - 36px);
  max-height:min(560px, calc(100vh - 36px));
  display:none; flex-direction:column;
  background:var(--paper); border:1px solid var(--ink);
}
.chat-panel[data-open="1"]{ display:flex; }
.chat-hd{
  display:flex; justify-content:space-between; align-items:center; gap:10px;
  padding:12px 14px; border-bottom:1px solid var(--ink); background:var(--green); color:#f2eede;
}
.chat-hd__t{ font-family:var(--sans); font-size:12px; letter-spacing:.13em; text-transform:uppercase; }
.chat-x{ background:none; border:0; color:#e7d7b4; font-size:19px; line-height:1; cursor:pointer; padding:0 2px; font-family:var(--sans); }
.chat-log{ overflow-y:auto; padding:14px; flex:1 1 auto; }
.chat-msg{ font-family:var(--sans); font-size:13.5px; line-height:1.55; margin:0 0 12px; color:var(--ink); }
.chat-msg--bot{ border-left:2px solid var(--tan); padding-left:11px; }
.chat-msg--you{ text-align:right; color:var(--green-soft); font-style:italic; }
.chat-opts{ padding:0 14px 14px; display:flex; flex-direction:column; gap:7px; }
.chat-opt{
  font-family:var(--sans); font-size:13px; text-align:left;
  background:transparent; color:var(--green); border:1px solid var(--rule);
  padding:9px 11px; cursor:pointer; border-radius:0; line-height:1.4;
}
.chat-opt:hover{ border-color:var(--green); background:#efeadc; }
.chat-form{ padding:0 14px 14px; display:grid; gap:10px; }
.chat-form input{ font-family:var(--sans); font-size:14px; }
.chat-form label{ margin-bottom:4px; }
.chat-fine{ padding:0 14px 13px; font-family:var(--sans); font-size:10.5px; line-height:1.5; color:var(--ink-faint); }

@media(max-width:420px){
  .chat-btn{ left:12px; bottom:12px; padding:10px 14px; }
  .chat-panel{ left:12px; bottom:12px; }
}

/* ---------- misc ---------- */
.skip{ position:absolute; left:-9999px; }
.skip:focus{ left:8px; top:8px; background:var(--paper); padding:8px 12px; z-index:99; }


/* ==========================================================================
   ENRICHMENT PASS — depth, botanical texture, and motion.
   Everything below is additive. Nothing here hides content: every reveal is
   an animation applied by an .is-in class with animation-fill-mode:backwards,
   so if the script never runs, the page is already fully visible.
   ========================================================================== */

/* ---------- type: rag control and a tighter, more confident scale ---------- */
h1,h2,h3,h4,.card__title,.index__name,.figure h3{
  text-wrap:balance;
}
p,.lede,.small,.caption,.index__desc{ text-wrap:pretty; }
h1{
  font-size:clamp(32px,5.6vw,52px);
  line-height:1.08;
  letter-spacing:-.012em;
  overflow-wrap:break-word;
}
h2{ font-size:clamp(24px,3.6vw,33px); letter-spacing:-.008em; }
.lede{ letter-spacing:-.002em; }
.eyebrow{ position:relative; }

/* an eyebrow now carries a hairline tick, like a printed running head */
.eyebrow::after{
  content:""; display:block; width:34px; height:1px;
  background:currentColor; opacity:.5; margin-top:.7em;
}

/* ---------- paper texture: a faint botanical hatch built from gradients ---------- */
.band{ position:relative; }
.band--tint{
  background-color:var(--paper-2);
  background-image:linear-gradient(180deg, rgba(255,253,246,.75), rgba(255,253,246,0) 42%);
}
.band--leaf{
  background-color:rgba(239,234,220,.55);
  background-image:
    repeating-linear-gradient(38deg,  var(--hatch) 0 1px, transparent 1px 15px),
    repeating-linear-gradient(-38deg, var(--hatch) 0 1px, transparent 1px 15px),
    radial-gradient(circle at 50% 50%, rgba(169,138,95,.075) 0 1.1px, transparent 1.7px);
  background-size:auto, auto, 30px 30px;
}
/* a hairline of new growth along the top edge of a tinted band */
.band--tint::before,.band--leaf::before{
  content:""; position:absolute; left:0; right:0; top:-1px; height:1px;
  background:linear-gradient(90deg,
    rgba(169,138,95,0) 0%, var(--tan) 18%, var(--green-new) 50%, var(--tan) 82%,
    rgba(169,138,95,0) 100%);
  opacity:.55;
}

/* a printed color plate: deep green ink field. Used once per page at most. */
.band--ink{
  background-color:var(--green-deep);
  background-image:
    radial-gradient(900px 420px at 20% 0%, rgba(125,154,85,.20) 0%, rgba(125,154,85,0) 62%),
    repeating-linear-gradient(38deg, rgba(255,255,255,.028) 0 1px, transparent 1px 16px),
    repeating-linear-gradient(-38deg, rgba(255,255,255,.028) 0 1px, transparent 1px 16px);
  color:#efe9d8;
  border-top:1px solid var(--green-deep);
}
.band--ink h1,.band--ink h2,.band--ink h3,.band--ink h4{ color:#f6f1e2; }
.band--ink p,.band--ink .lede{ color:#ded5be; }
.band--ink .eyebrow{ color:var(--green-new); }
.band--ink .btn{
  background:#efe9d8; color:var(--green-deep); border-color:#efe9d8;
}
.band--ink .btn:hover{ background:#fff; border-color:#fff; }
.band--ink .btn--ghost{ background:transparent; color:#e5dcc4; border-color:rgba(229,220,196,.45); }
.band--ink .btn--ghost:hover{ background:#efe9d8; color:var(--green-deep); border-color:#efe9d8; }
.band--ink .rule--short{ background:var(--green-new); }

/* ---------- demonstration strip: same words, more depth ---------- */
.demostrip{
  background-image:linear-gradient(100deg, var(--green-deep) 0%, var(--green) 48%, #2c5343 100%);
  border-bottom:1px solid rgba(0,0,0,.25);
}
.demostrip a{ transition:color .18s var(--ease); }
.demostrip__dot{
  background:var(--green-new);
  box-shadow:0 0 0 3px rgba(125,154,85,.22);
}

/* ---------- masthead & nav: printed hover states ---------- */
.wordmark__rule{
  background:linear-gradient(90deg, var(--green) 0%, var(--tan) 46%, var(--tan-soft) 100%);
  transform-origin:left center;
  transition:transform .28s var(--ease);
}
.wordmark:hover .wordmark__rule{ transform:scaleY(2.4); }
.masthead__contact a{
  border-bottom-color:var(--tan);
  transition:color .18s var(--ease), border-bottom-color .18s var(--ease);
}
.masthead__contact a:hover{ color:var(--green-deep); border-bottom-color:var(--green-new); }

.nav__list a{
  background-image:linear-gradient(var(--green-new),var(--green-new));
  background-repeat:no-repeat;
  background-position:0 100%;
  background-size:0% 1.5px;
  transition:color .18s var(--ease), background-size .24s var(--ease);
}
.nav__list a:hover{ color:var(--green-deep); background-size:100% 1.5px; }
.nav__list a[aria-current="page"]{ border-bottom-color:var(--rust-soft); }

/* ---------- links, buttons, general transitions ---------- */
a{ transition:color .18s var(--ease), border-color .18s var(--ease); }
main a:not(.btn):not(.index__item){
  text-decoration-color:var(--tan-soft);
  text-underline-offset:2px;
}
main a:not(.btn):not(.index__item):hover{ color:var(--green-deep); text-decoration-color:var(--green-new); }

.btn{
  position:relative;
  transition:background-color .2s var(--ease), color .2s var(--ease),
             border-color .2s var(--ease), transform .2s var(--ease),
             letter-spacing .2s var(--ease);
}
.btn:hover{ transform:translateY(-1px); letter-spacing:.185em; }
.btn:active{ transform:translateY(0); }
.btn::after{
  content:""; position:absolute; left:0; right:0; bottom:-4px; height:1px;
  background:var(--tan); opacity:0; transition:opacity .2s var(--ease), bottom .2s var(--ease);
}
.btn:hover::after{ opacity:.9; bottom:-6px; }
.foot a{ transition:color .18s var(--ease), padding-left .18s var(--ease); }
.foot a:hover{ color:var(--green-deep); }

/* ---------- plate: a richer printed leaf of the guide ---------- */
.plate{
  position:relative;
  /* a figure carries a 40px UA side margin; a plate is a full-measure object */
  margin-left:0; margin-right:0;
  background-color:var(--paper-3);
  background-image:
    linear-gradient(165deg, rgba(255,255,255,.9) 0%, rgba(255,255,255,0) 46%),
    radial-gradient(120% 90% at 50% 8%, rgba(125,154,85,.07) 0%, rgba(125,154,85,0) 58%),
    linear-gradient(180deg, rgba(169,138,95,0) 62%, rgba(169,138,95,.07) 100%);
  border-color:var(--rule);
  transition:border-color .25s var(--ease);
}
.plate:hover{ border-color:var(--tan); }
/* register marks in the corners, the way a plate is printed */
.plate::before,.plate::after{
  content:""; position:absolute; width:9px; height:9px; pointer-events:none;
  border-color:var(--tan-soft); border-style:solid; border-width:0;
}
.plate::before{ top:5px; left:5px; border-top-width:1px; border-left-width:1px; }
.plate::after{ bottom:5px; right:5px; border-bottom-width:1px; border-right-width:1px; }
.plate__cap{ border-top-color:var(--rule); }
.plate svg{ overflow:visible; }

/* ---------- the specimen card: a considered edge ---------- */
.card{
  position:relative;
  background-color:#fcf9f2;
  background-image:
    linear-gradient(180deg, rgba(255,255,255,.95) 0%, rgba(255,255,255,0) 180px),
    radial-gradient(90% 60% at 100% 0%, rgba(125,154,85,.06) 0%, rgba(125,154,85,0) 60%);
}
.card::after{
  content:""; position:absolute; inset:-7px; border:1px solid var(--tan-soft);
  pointer-events:none; opacity:.7;
}
.card__head{
  background-image:linear-gradient(180deg, rgba(239,234,220,.55), rgba(239,234,220,0));
}
.card__title{ letter-spacing:-.006em; }

/* the refused line: the best line on the card, printed like one */
.wo tr.refused td{
  background-color:transparent;
  background-image:linear-gradient(180deg, rgba(125,154,85,.10) 0%, rgba(125,154,85,.04) 100%);
}
.wo tr.refused td:first-child{ box-shadow:inset 3px 0 0 var(--rust); padding-left:13px; }
.wo tr.refused td:last-child{ padding-right:4px; }
.wo tr.refused .what b{ color:var(--rust); }
.wo tr.refused .amt{ color:var(--green); font-weight:600; }
.refused-why{
  border-left-width:2px;
  border-left-color:var(--green-new);
  background:linear-gradient(90deg, rgba(125,154,85,.07), rgba(125,154,85,0) 60%);
  padding:2px 0 2px 12px;
}
.refused-mark{
  display:inline-block; vertical-align:-.45em; width:1.9em; height:1.9em;
  margin-right:.45em; color:var(--rust);
}
.refused-mark svg{ display:block; width:100%; height:100%; }
.wo tr.total td{ background:linear-gradient(180deg, rgba(169,138,95,.10), rgba(169,138,95,0)); }
.wo tr.total .amt{ color:var(--green-deep); }
.wo tbody tr{ transition:background-color .2s var(--ease); }
.wo tbody tr:not(.total):not(.refused):hover{ background-color:rgba(169,138,95,.06); }

/* ---------- the checkable numbers ---------- */
.figure__n{
  background-image:linear-gradient(170deg, var(--green-soft) 0%, var(--green-deep) 72%);
  -webkit-background-clip:text; background-clip:text; color:transparent;
  font-size:clamp(38px,6vw,46px);
}
.figure__n small{ color:var(--tan); -webkit-text-fill-color:var(--tan); }
.figure{ position:relative; padding-top:20px; }
.figure::before{
  content:""; position:absolute; top:0; left:0; width:46px; height:2px;
  background:linear-gradient(90deg,var(--green-new),var(--tan));
}

/* ---------- two-column index: botanical mark per service ---------- */
.index__item{
  position:relative;
  padding-left:0;
  transition:background-color .2s var(--ease), padding-left .2s var(--ease);
}
.index__item::before{
  content:""; position:absolute; left:0; top:0; bottom:-1px; width:2px;
  background:var(--green-new); transform:scaleY(0); transform-origin:top center;
  transition:transform .24s var(--ease);
}
.index__item:hover{ background-color:rgba(125,154,85,.06); padding-left:12px; }
.index__item:hover::before{ transform:scaleY(1); }
.index__item:focus-visible{ outline:2px solid var(--green); outline-offset:3px; }

.index__key{
  display:flex; flex-direction:column; align-items:center; gap:9px;
  width:3.1em; padding-top:.2em;
}
.index__mark{
  display:block; width:30px; height:30px; color:var(--green-soft);
  transition:color .22s var(--ease), transform .3s var(--ease);
}
.index__mark svg{ display:block; width:100%; height:100%; }
.index__item:hover .index__mark{ color:var(--rust); transform:translateY(-2px) rotate(-3deg); }
.index__n{ width:auto; transition:color .2s var(--ease); }
.index__name{ display:block; transition:color .2s var(--ease); }
.index__desc{ display:block; }
.index__item:hover .index__n{ color:var(--tan); }

/* ---------- designed image slots, waiting for real photographs ---------- */
.photoslot{
  margin:2.4rem auto;
  max-width:640px;
  border:1px solid var(--rule);
  background:var(--paper-3);
  padding:9px 9px 0;
  position:relative;
}
.photoslot__art{
  position:relative;
  aspect-ratio:3 / 2;
  min-height:170px;
  width:100%;
  overflow:hidden;
  background-color:#eeead9;
  background-image:
    radial-gradient(120% 110% at 50% 0%, rgba(255,253,246,.85) 0%, rgba(255,253,246,0) 62%),
    linear-gradient(178deg, rgba(20,48,42,.10) 0%, rgba(20,48,42,.03) 44%, rgba(169,138,95,.16) 100%),
    repeating-linear-gradient(38deg, rgba(20,48,42,.035) 0 1px, transparent 1px 22px);
}
.photoslot--tall .photoslot__art{ aspect-ratio:4 / 5; }
.photoslot--wide .photoslot__art{ aspect-ratio:16 / 9; }
.photoslot__art svg{
  position:absolute; inset:0; width:100%; height:100%; display:block;
}
.photoslot__tag{
  position:absolute; left:0; top:0;
  font-family:var(--sans); font-size:9.5px; letter-spacing:.2em; text-transform:uppercase;
  color:#f2eede; background:var(--green-deep);
  padding:5px 10px 4px;
}
.photoslot__cap{
  display:flex; flex-wrap:wrap; gap:6px 18px; justify-content:space-between;
  padding:9px 2px 10px;
  border-top:1px solid var(--rule-soft); margin-top:9px;
}
.photoslot__what{
  font-family:var(--sans); font-size:12.5px; line-height:1.5; color:var(--ink-soft);
  max-width:62ch; margin:0;
}
.photoslot__what b{ color:var(--ink); font-weight:650; }
.photoslot__ref{
  font-family:var(--mono); font-size:11px; color:var(--ink-faint); white-space:nowrap;
}

/* ---------- section divider: a leaf on a hairline ---------- */
.divider{
  display:flex; align-items:center; gap:16px;
  margin:2.6rem 0; color:var(--tan);
}
.divider::before,.divider::after{
  content:""; flex:1 1 auto; height:1px;
  background:linear-gradient(90deg, rgba(169,138,95,0), var(--tan-soft), rgba(169,138,95,0));
}
.divider__leaf{ flex:0 0 auto; width:84px; height:30px; color:var(--green-soft); opacity:.9; }
.divider__leaf svg{ display:block; width:100%; height:100%; }

/* ---------- wide plates ----------
   On a phone a 700-unit diagram would render its keys at about five pixels.
   The plate keeps its own scroller so it can be read at size, and the page
   itself still never scrolls sideways. The figcaption carries the substance
   as real text either way. */
.plate__scroll{ overflow-x:auto; overflow-y:hidden; -webkit-overflow-scrolling:touch; }
.plate--wide{ margin:2.4rem 0; }
.plate--wide svg{ max-height:none; }
@media(max-width:720px){
  .plate__scroll{
    padding-bottom:6px;
    background:linear-gradient(90deg, rgba(169,138,95,0), rgba(169,138,95,0)) ,
               linear-gradient(90deg, rgba(169,138,95,.16), rgba(169,138,95,0) 24px) right center / 24px 100% no-repeat;
  }
  .plate__scroll svg{ min-width:600px; }
  .plate--wide .plate__cap{ padding-top:10px; }
}

/* ---------- forms ---------- */
input,select,textarea{ transition:border-bottom-color .2s var(--ease), background-color .2s var(--ease); }
input:hover,textarea:hover,select:hover{ border-bottom-color:var(--tan); }
input:focus,textarea:focus,select:focus{
  border-bottom-color:var(--green-new);
  background-color:rgba(125,154,85,.05);
}
label{ transition:color .2s var(--ease); }

/* ---------- steps, qa, areas ---------- */
.step{ transition:background-color .2s var(--ease); }
.step__n{ color:var(--rust); }   /* rust-soft on paper is ~3.3:1 — too low for 12px */
.qa{ transition:background-color .2s var(--ease); }
.area{ transition:border-bottom-color .2s var(--ease); }
.area:hover{ border-bottom-color:var(--green-new); }
.callout{
  background-image:linear-gradient(160deg, rgba(255,255,255,.85), rgba(125,154,85,.06));
  border-left:2px solid var(--green-new);
}
.sidenote{ border-top-color:var(--rust-soft); }
.empty{
  border-style:solid; border-color:var(--rule);
  background-image:
    radial-gradient(90% 70% at 50% 0%, rgba(125,154,85,.09), rgba(125,154,85,0) 70%),
    repeating-linear-gradient(38deg, var(--hatch) 0 1px, transparent 1px 15px);
}
.empty__mark{ color:var(--green-soft); }

/* ---------- chat launcher ---------- */
.chat-btn{
  background-image:linear-gradient(160deg, var(--green) 0%, var(--green-deep) 100%);
  transition:transform .2s var(--ease), background-color .2s var(--ease);
}
.chat-btn:hover{ transform:translateY(-2px); }
.chat-opt{ transition:border-color .2s var(--ease), background-color .2s var(--ease), color .2s var(--ease); }
.chat-opt:hover{ border-color:var(--green-new); }
.chat-hd{ background-image:linear-gradient(100deg, var(--green-deep), var(--green)); }

/* ==========================================================================
   MOTION
   Reveals and the one ambient moment. All of it is opt-in: the default
   rendered state of every element below is fully visible and in place.
   ========================================================================== */
@keyframes sr-rise{
  from{ opacity:0; transform:translateY(14px); }
  to  { opacity:1; transform:translateY(0); }
}
@keyframes sr-rise-sm{
  from{ opacity:0; transform:translateY(9px); }
  to  { opacity:1; transform:translateY(0); }
}
@keyframes sr-draw{
  from{ stroke-dashoffset:var(--dash,600); }
  to  { stroke-dashoffset:0; }
}
/* the oak's crown, breathing. ~14s, a fraction of a percent of scale. */
@keyframes sr-breathe{
  0%,100%{ transform:scale(1) translateY(0); }
  50%    { transform:scale(1.011) translateY(-2px); }
}
@keyframes sr-breathe-slow{
  0%,100%{ transform:scale(1.006) translateY(-1px); }
  50%    { transform:scale(1) translateY(1px); }
}
/* one leaf, off the crown, down and out of the plate */
@keyframes sr-drift{
  0%      { opacity:0; transform:translate(0,0) rotate(0deg); }
  6%      { opacity:.85; }
  55%     { opacity:.8; }
  100%    { opacity:0; transform:translate(-26px,168px) rotate(220deg); }
}
@keyframes sr-sway{
  0%,100%{ transform:rotate(-.62deg); }
  50%    { transform:rotate(.62deg); }
}

@media (prefers-reduced-motion: no-preference){
  .is-in{ animation:sr-rise .58s var(--ease) backwards; }
  .is-in .index__item{ animation:sr-rise-sm .5s var(--ease) backwards; }
  .is-in .index__item:nth-child(2){ animation-delay:.05s; }
  .is-in .index__item:nth-child(3){ animation-delay:.10s; }
  .is-in .index__item:nth-child(4){ animation-delay:.15s; }
  .is-in .index__item:nth-child(5){ animation-delay:.20s; }
  .is-in .index__item:nth-child(6){ animation-delay:.25s; }
  .is-in .index__item:nth-child(7){ animation-delay:.30s; }
  .is-in .index__item:nth-child(8){ animation-delay:.35s; }
  .is-in .figure{ animation:sr-rise-sm .55s var(--ease) backwards; }
  .is-in .figure:nth-child(2){ animation-delay:.09s; }
  .is-in .figure:nth-child(3){ animation-delay:.18s; }
  .is-in .step{ animation:sr-rise-sm .5s var(--ease) backwards; }
  .is-in .step:nth-child(2){ animation-delay:.06s; }
  .is-in .step:nth-child(3){ animation-delay:.12s; }
  .is-in .step:nth-child(4){ animation-delay:.18s; }
  .is-in .step:nth-child(5){ animation-delay:.24s; }

  /* the ambient moment */
  .oak-crown{
    transform-box:view-box; transform-origin:255px 330px;
    animation:sr-breathe 15s ease-in-out infinite;
  }
  .oak-crown--b{
    transform-box:view-box; transform-origin:255px 320px;
    animation:sr-breathe-slow 19s ease-in-out infinite;
  }
  .oak-limbs{
    transform-box:view-box; transform-origin:250px 452px;
    animation:sr-sway 23s ease-in-out infinite;
  }
  .oak-leaf{
    transform-box:fill-box; transform-origin:center;
    animation:sr-drift 17s linear infinite;
  }
  .oak-leaf--2{ animation-duration:23s; animation-delay:8s; }
  .oak-leaf--3{ animation-duration:29s; animation-delay:15s; }
}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
  .oak-leaf{ opacity:0; }
}

/* ---------- small screens: keep the margins generous but never overflow ---------- */
@media(max-width:430px){
  .wrap{ padding:0 18px; }
  .card::after{ inset:-5px; }
  .index__key{ width:2.6em; }
  .index__mark{ width:26px; height:26px; }
  .photoslot__art{ min-height:140px; }
}


/* ═══ 📱 MOBILE MENU — added 8 Sep 2026. See tools/navfix notes.
   ⛔ Do not give this a colour. The panel IS this site's own <nav>, so it
   keeps this site's own paper and rules; the button rides on currentColor.
   ⛔ Do not raise the breakpoint without re-measuring — 860 is where these
   nav rows start wrapping, which is the thing being fixed. */
.navbtn { display: none; }
.navq { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
        overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
@media (max-width: 860px) {
  .navbtn {
    display: inline-flex; align-items: center; gap: .55rem;
    padding: .5rem .8rem; border-radius: .5rem; cursor: pointer;
    font: inherit; font-size: .82rem; letter-spacing: .06em; text-transform: uppercase;
    color: currentColor;
    border: 1px solid currentColor;
    background: transparent;
    opacity: .85;
  }
  .navbtn__ico { position: relative; width: 15px; height: 2px; background: currentColor; }
  .navbtn__ico::before, .navbtn__ico::after {
    content: ""; position: absolute; left: 0; width: 15px; height: 2px; background: currentColor;
  }
  .navbtn__ico::before { top: -5px; }
  .navbtn__ico::after  { top:  5px; }
  .navq:focus-visible + .navbtn { outline: 2px solid currentColor; outline-offset: 2px; }

  /* the demo's own nav, closed */
  nav[aria-label="Main"], nav[aria-label="Primary"] { display: none; }
  .navq:checked ~ nav[aria-label="Main"],
  .navq:checked ~ nav[aria-label="Primary"] { display: block; width: 100%; }

  /* ⚠️ the lists inside are flex rows on every one of these sites; they have to
     stack, and the row gap has to become a tap target. */
  nav[aria-label="Main"] ul, nav[aria-label="Primary"] ul {
    display: block; margin: 0; padding: 0; list-style: none;
  }
  nav[aria-label="Main"] li, nav[aria-label="Primary"] li { display: block; }
  nav[aria-label="Main"] li a, nav[aria-label="Primary"] li a,
  nav[aria-label="Main"] > a, nav[aria-label="Primary"] > a {
    display: block; padding: .7rem .2rem; line-height: 1.2;
  }
  nav[aria-label="Main"] li + li, nav[aria-label="Primary"] li + li {
    border-top: 1px solid currentColor;
  }
  nav[aria-label="Main"] li + li, nav[aria-label="Primary"] li + li { border-top-color: color-mix(in srgb, currentColor 18%, transparent); }
}


/* ═══ 🔤 NAV TYPE PASS 9 Sep 2026 — size and tracking only.
   ⛔ Do not add colour, family, case or weight here: those are what keep these
   twelve sites from converging, and converging is the thing that was fixed
   once already. Measured before: 11–12.5px with tracking wide enough that
   the label read as separate letters rather than a word. */
nav[aria-label="Main"] a,
nav[aria-label="Primary"] a {
  font-size: 13px;
  letter-spacing: .1em;
}

/* ══════════════════════════════════════════════════════════════════════════
   ⭐ THE PROFESSIONAL PASS — tree service, 11 Sep 2026.
   Same five gaps the roofing demo had, answered in this site's own materials:
   a brand MARK, colour in the headline, an offer strip, a primary button that
   is the accent rather than the neutral, and a real shadow under the drawing.
   ⚠️ THIS SITE IS LIGHT. The roofing block's dark gradients are wrong here, so
   the strip and the buttons are re-derived on warm paper. The accent is set at
   the DARKER end on purpose: #2F6B3A on this paper is ~5.7:1, and a brighter
   canopy green would have been a pale green word on a cream page.
   ⛔ No photograph. The plate is an ink drawing and stays one.
   ══════════════════════════════════════════════════════════════════════════ */
:root{
  --canopy:      #2F6B3A;   /* the one decisive accent */
  --canopy-deep: #1F4C28;   /* pressed / hover */
  --canopy-wash: rgba(47,107,58,.10);
}

/* ── the mark ─────────────────────────────────────────────────────────── */
/* The wordmark is three stacked spans, so the mark is set beside all three
   with a grid rather than a flex row — a flex row would have unstacked them. */
.wordmark{
  display:grid; grid-template-columns:auto minmax(0,1fr);
  column-gap:11px; align-items:center;
}
.wordmark__name,.wordmark__rule,.wordmark__sub{ grid-column:2; }
.brandmark{
  grid-column:1; grid-row:1 / span 3;
  width:30px; height:30px; flex:0 0 auto; color:var(--canopy);
  transition:transform .28s var(--ease), color .28s var(--ease);
}
.wordmark:hover .brandmark{ transform:translateY(-1px) rotate(-2deg); color:var(--canopy-deep); }

/* ── the headline carries the colour ──────────────────────────────────── */
h1 .hl{ font-style:normal; color:var(--canopy); }

/* ── the offer strip, re-derived for paper ────────────────────────────── */
/* ⭐ What the customer actually gets, in the site's own sentence. ⛔ Never a
   price, a rating or a count — this demo has published none of those. */
.offerbar{
  border-top:2px solid var(--canopy);
  border-bottom:1px solid var(--rule);
  background-image:linear-gradient(180deg,#f1ecdf,#e9e3d3);
}
.offerbar__in{
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding-top:10px; padding-bottom:10px;
}
.offerbar__tag{
  font-family:var(--mono); font-size:10.5px; text-transform:uppercase;
  letter-spacing:.14em; color:var(--canopy);
  border:1px solid color-mix(in srgb, var(--canopy) 45%, transparent);
  border-radius:999px; padding:3px 9px; flex:0 0 auto;
}
.offerbar__msg{
  margin:0; font-family:var(--sans); font-size:13px; line-height:1.45;
  color:var(--ink-soft); flex:1 1 340px; min-width:0;
}
.offerbar__msg b{ color:var(--ink); font-weight:650; }
.offerbar__go{
  flex:0 0 auto; font-family:var(--mono); font-size:11.5px; text-transform:uppercase;
  letter-spacing:.09em; color:var(--canopy-deep); text-decoration:none; white-space:nowrap;
  border-bottom:1px solid color-mix(in srgb, var(--canopy) 55%, transparent);
  padding-bottom:2px; transition:color .18s var(--ease), border-bottom-color .18s var(--ease);
}
.offerbar__go:hover{ color:var(--canopy); border-bottom-color:var(--canopy); }
@media (max-width:640px){
  .offerbar__go{ display:none; }      /* the hero button is just below it */
  .offerbar__msg{ font-size:12.5px; }
}

/* ── the primary button is the accent ─────────────────────────────────── */
.btn{
  background:var(--canopy); border-color:var(--canopy); color:#f7f4ea;
}
.btn:hover{ background:var(--canopy-deep); border-color:var(--canopy-deep); }

/* ── depth on the drawn plate ─────────────────────────────────────────── */
.hero .plate{
  box-shadow:0 22px 40px rgba(36,31,24,.16), 0 3px 8px rgba(36,31,24,.09);
}
.hero .plate svg{
  filter:drop-shadow(0 10px 14px rgba(20,48,42,.18)) contrast(1.05) saturate(1.05);
}

@media (prefers-reduced-motion:reduce){
  .wordmark:hover .brandmark{ transform:none; }
}

/* 🔴 AND THE GHOST IS RESTATED AFTER IT. `.btn--ghost` is declared ~400 lines
   above; this file is unlayered, so the `.btn` rule above — same specificity,
   later in the file — takes the background and BOTH buttons go solid green.
   Two primaries is no primary. ⛔ Any future `.btn` rule appended below this
   point must restate the ghost again. */
.btn--ghost{
  background:transparent; border-color:var(--canopy); color:var(--canopy-deep);
}
.btn--ghost:hover{
  background:var(--canopy-wash); border-color:var(--canopy); color:var(--canopy-deep);
}

/* ── 🌳 THE WEEK, AS THE CUSTOMER HAS IT — 11 Sep 2026 ────────────────────
   ⭐ The old headline led with the document, which is OUR fact. What this
   customer is actually buying is the tree they were about to lose — the
   removal page already says it plainly: "A surprising number of removal
   requests should be pruning requests… we would rather sell you that." So the
   headline now names the trade and the town and gives the accent to that, and
   this block walks the week from the owner's side of the fence.
   ⛔ No motion of its own. The page's reveal observes `.band > .wrap` and is
   already gated on prefers-reduced-motion; this section inherits that. */
.band--day .day{ list-style:none; margin:1.6rem 0 0; padding:0; display:grid; gap:0; }
.day__i{
  display:grid; grid-template-columns:112px 1fr; gap:0 1.4rem;
  padding:1.1rem 0; border-top:1px solid var(--rule-soft); align-items:start;
}
.day__i:first-child{ border-top:0; }
.day__t{
  font-family:var(--mono); font-size:11px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--canopy); padding-top:.45rem; white-space:nowrap;
}
.day__i h3{
  font-family:var(--serif); font-weight:600; font-size:19px; line-height:1.28;
  margin:0 0 .35rem; color:var(--ink); max-width:62ch;
}
.day__i p{ margin:0; font-size:15.5px; line-height:1.62; color:var(--ink-soft); max-width:62ch; }
/* ⭐ one beat is marked, and it is the hour the headline either comes true or
   does not — the two limbs come off and the tree stays. */
.day__i--live .day__t::after{
  content:""; display:inline-block; width:6px; height:6px; border-radius:50%;
  background:var(--canopy); margin-left:7px; vertical-align:middle;
}
/* 🔴 THE THREE-CHILD GRID BUG. `.day__i` holds THREE children — the timestamp,
   the h3 and the p — in a TWO-column grid, so auto-placement puts the
   paragraph back in column one, at the width of a timestamp. At 1280px that
   renders the beat's paragraph in a 100-odd-pixel gutter and makes the row
   four times as tall as it should be. Both text children are pinned to column
   two. ⛔ Reset this inside the single-column breakpoint, or the `2` invents an
   implicit second column on a phone. */
.day__i > h3,
.day__i > p{grid-column:2}
.day__foot{
  margin:1.5rem 0 0; padding-top:1.1rem; border-top:1px solid var(--rule-soft);
  font-size:15.5px; line-height:1.65; color:var(--ink-soft); max-width:66ch;
}
.day__foot b{ color:var(--ink); font-weight:600; }
@media (max-width:560px){
  .day__i{ grid-template-columns:1fr; gap:.3rem; }
  .day__t{ padding-top:0; }
  .day__i > h3,.day__i > p{grid-column:1}
}


/* ── 📷 PHOTOGRAPHS ───────────────────────────────────────────────────────
   🔴 11 Sep 2026. Owner: "need photos!!" and "no stick diagrams". This demo
   shipped with none, and a page of line drawings reads as a prototype rather
   than as a business's site.

   ⭐ PORTABLE ON PURPOSE. Thirteen demos, thirteen different token names —
   --soil/--panel/--hair here, --paper/--rule/--gr there, light and dark both.
   A component written against one demo's variables is a component that has to
   be rewritten twelve times and will be wrong in four of them. So this uses
   `currentColor` and plain rgba, and inherits the page's own ink.

   ⛔ Every CC BY / CC BY-SA frame carries its credit IN the frame. Attribution
   is a licence term, not a courtesy, and "we'll add the credits later" is
   exactly how a licence gets breached. */
.photo{position:relative;margin:0;line-height:0;border-radius:4px;overflow:hidden;
  border:1px solid rgba(128,128,128,.28)}
.photo img{width:100%;display:block;object-fit:cover;filter:saturate(1.03) contrast(1.02)}
.photo--hero img{height:clamp(260px,34vw,430px)}
.photo--band img{height:clamp(190px,26vw,320px)}
.photo--tall img{height:clamp(240px,30vw,380px)}
/* ⚠️ the badge carries its OWN scrim rather than the frame carrying a gradient.
   A gradient tuned for a dark ground turns a light photo muddy along the bottom,
   and half these demos are light. */
.photo__cr{position:absolute;right:8px;bottom:8px;z-index:2;
  font-size:9.5px;letter-spacing:.04em;line-height:1.45;font-weight:500;
  color:rgba(255,255,255,.88);background:rgba(0,0,0,.52);padding:3px 7px;border-radius:2px;
  text-shadow:0 1px 2px rgba(0,0,0,.5)}
.photo__cr a{color:inherit;text-decoration:underline;text-underline-offset:2px}
.photo__cap{line-height:1.55;font-size:12.5px;opacity:.72;padding-top:9px}

/* ── 🚪 THE WAY OUT STAYS ON SCREEN ───────────────────────────────────────
   🔴 11 Sep 2026, owner: "need to be able and x out of all the demo sites if
   you view on mobile dont let people get stuck somewher with out easy exit."

   This banner is the only route from a demo back to us, and it sat at the top
   of the document as a static block. On a phone, two swipes down a service page
   and it is gone — a visitor who arrived on a shared link has no way back and
   no reason to think one exists. ⚠️ The link was always there and was always
   unreachable, which is the same shape as the embed's close button being parked
   off-screen above the iframe.

   ⭐ Sticky on phones only. On a desktop the banner is in view at the top of a
   page people can see all of, and pinning it would just spend vertical room. */
@media (max-width: 640px) {
  .demostrip {
    position: sticky;
    top: 0;
    z-index: 90;
  }
  /* ⚠️ AND THE LINK HAS TO BE HITTABLE, NOT MERELY PRESENT. It is inline text
     inside a sentence, so on a 375px screen it wrapped into two fragments 15px
     tall — measured, both genuinely tappable, and both far under the 44px a
     thumb needs. ⭐ Make it a control: one line, real padding, no wrap. */
  .demostrip a {
    display: inline-block;
    margin-top: 4px;
    padding: 11px 12px;
    white-space: nowrap;
    font-weight: 700;
  }
}


/* 🔴 INSIDE OUR OWN FRAME THE BANNER IS DUPLICATE — 11 Sep 2026. Owner, looking
   at the embed on the home page: "take all of this off this is awfull they know
   that". He is right about that surface: our own chrome prints a disclosure
   directly under the frame, in our voice, so the demo's banner made two stacked
   notices — which reads as nervous rather than as honest.
   ⛔ A STANDALONE PAGE KEEPS IT. There the banner is the ONLY notice, and these
   pages carry a live telephone line: an invented business with a working number
   and nothing saying so is a trap, not a demo.
   ⚠️ Fails in the honest direction — with JavaScript off, nothing is hidden.
   ⛔ If the note under the frame is ever removed, delete this rule first. */
html[data-embedded] .demostrip { display: none !important; }


/* ── 🧭 THE UTILITY BAR — 15 Sep 2026 ─────────────────────────────────
   Written by tools/demo-utilbar.mjs. See that file for why the disclosure
   banner became a chip and why hours are absent on the demos that publish none.
   ⛔ Self-contained colour on purpose: every demo means something different by
   --ink, and borrowing it painted this a different thing on each site. */
.utilbar{background:#0f1b2a;color:rgba(255,255,255,.92);
  border-bottom:1px solid rgba(255,255,255,.14);font-size:.78rem;line-height:1.4;
  font-family:system-ui,-apple-system,"Segoe UI",sans-serif}
.utilbar__in{display:flex;align-items:center;justify-content:space-between;
  gap:.9rem;min-height:38px;padding:.3rem 20px;flex-wrap:wrap;
  max-width:1180px;margin:0 auto}
.utilbar__hours{margin:0;display:flex;align-items:center;gap:.45rem;min-width:0}
.utilbar__hours b{font-weight:600;color:#fff}
.utilbar__sep{opacity:.45}
.utilbar__hours>span:last-child{opacity:.72}
.utilbar__right{display:flex;align-items:center;gap:.9rem;flex-wrap:wrap;min-width:0}
.utilbar__lnk{color:rgba(255,255,255,.88);text-decoration:none;
  border-bottom:1px solid rgba(255,255,255,.26);padding-bottom:1px}
.utilbar__lnk:hover{color:#fff;border-bottom-color:#fff}
/* ⭐ colour is never the only carrier — the words say Open or Closed outright */
.utilbar__dot{width:8px;height:8px;border-radius:50%;flex:0 0 auto;background:#7fe0a8}
.utilbar__hours[data-state="open"] .utilbar__dot{background:#7fe0a8;animation:utilpulse 3s ease-out infinite}
.utilbar__hours[data-state="soon"] .utilbar__dot{background:#ffc861}
.utilbar__hours[data-state="shut"] .utilbar__dot{background:#9aa6b1}
@keyframes utilpulse{0%{box-shadow:0 0 0 0 rgba(127,224,168,.5)}
  70%{box-shadow:0 0 0 6px rgba(127,224,168,0)}100%{box-shadow:0 0 0 0 rgba(127,224,168,0)}}
@media (prefers-reduced-motion:reduce){.utilbar__dot{animation:none !important}}
.utilbar .demostrip{display:inline-flex;align-items:center;gap:.4rem;
  padding:.16rem .55rem;border-radius:999px;background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.22);font-size:.72rem;color:#fff;
  text-decoration:none;cursor:pointer}
.utilbar .demostrip:hover{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.38)}
.utilbar .demostrip b{text-transform:uppercase;letter-spacing:.08em;font-size:.68rem;font-weight:700}
.utilbar .demostrip__dot{width:7px;height:7px;border-radius:50%;background:#ff6a55;display:block}
@media (max-width:860px){
  /* ⛔ the TAIL hides, never the notice — and the chip becomes the link to it */
  .utilbar__demotail{display:none}
  .utilbar__in{gap:.55rem}
  .utilbar__right{gap:.7rem}
  .utilbar .demostrip{min-height:30px}
}
@media (max-width:560px){
  .utilbar{font-size:.72rem}
  .utilbar__hours>span:last-child,.utilbar__sep{display:none}
  .utilbar .demostrip{min-height:34px;padding-inline:.7rem}
}
/* ⛔ Inside our own iframe the surrounding chrome carries the disclosure, so the
   chip is hidden there and ONLY there. A standalone page always keeps it. */
html[data-embedded] .utilbar .demostrip{display:none !important}

/* 🔴 NO STATUS LIGHT WITHOUT A STATUS — 15 Sep 2026. Six of these demos publish
   no hours at all, and one publishes "by appointment". The dot is a status
   light: green, beside a company name with nothing behind it, it silently says
   OPEN NOW about a business whose hours nobody ever wrote. It only appears once
   the script has decided a real state from real published hours.
   ⚠️ This shipped for one sync because the fix was written into a script that
   died on an assertion BEFORE the file was saved — the edit was reported and
   never landed. Verify the artefact, not the log line. */
.utilbar__hours:not([data-state]) .utilbar__dot{display:none}


/* ── 🖼️ THE PHOTOGRAPH IS THE HERO — 15 Sep 2026 ─────────────────────────
   Written by tools/demo-photo-hero.mjs; the reasoning lives there. */
.lanaihero{position:relative;isolation:isolate;display:flex;flex-direction:column;justify-content:center;
  min-height:clamp(330px,62vh,600px);overflow:hidden;background:#07182a}
.lanaihero>img{position:absolute;inset:0;z-index:0;width:100%;height:100%;
  object-fit:cover;object-position:center 58%}
/* 🔴 TWO GRADIENTS, BOTH LOAD-BEARING. The horizontal one carries the headline;
   the vertical one holds the eyebrow and the buttons, which sit where the
   horizontal scrim has already thinned out. */
.lanaihero__scrim{position:absolute;inset:0;z-index:1;
  background:
    linear-gradient(90deg, rgba(5,18,32,.93) 0%, rgba(5,18,32,.86) 38%,
                           rgba(5,18,32,.46) 70%, rgba(5,18,32,.24) 100%),
    linear-gradient(0deg,  rgba(5,18,32,.42) 0%, rgba(5,18,32,.30) 50%,
                           rgba(5,18,32,.14) 100%)}
/* ⛔ padding-block, never the shorthand — a `padding: X 0 Y` here wipes the
   horizontal gutter the wrap class contributes and every line goes flush to the
   edge of the screen. That shipped once. */
.lanaihero__in{position:relative;z-index:2;
  padding-block:clamp(2rem,5vw,3.4rem) clamp(1.9rem,4.5vw,3rem)}
.lanaihero h1{color:#fff;max-width:20ch;text-wrap:balance}
.lanaihero .h1__where{color:#fff}
.lanaihero .hl{color:rgba(255,255,255,.74)}
.lanaihero .eyebrow,.lanaihero .lbl,.lanaihero .kicker{color:rgba(255,255,255,.88)}
.lanaihero .btnrow,.lanaihero .hero__act{margin-top:1.4rem;display:flex;flex-wrap:wrap;gap:.7rem}
/* ⛔ A ghost/outline button is a hairline on paper; over a photograph it
   disappears. WCAG 2.2 asks 3:1 for the control's own boundary, not just its
   label. */
.lanaihero .btn--ghost,.lanaihero .btn--line,.lanaihero .btn--out{
  border-color:rgba(255,255,255,.62);color:#fff;background:rgba(7,22,38,.42);
  -webkit-backdrop-filter:blur(3px);backdrop-filter:blur(3px)}
.lanaihero .btn--ghost:hover,.lanaihero .btn--line:hover,.lanaihero .btn--out:hover{
  background:rgba(7,22,38,.66);border-color:#fff}
.lanaihero .photo__cr{position:absolute;right:10px;bottom:9px;z-index:3;
  font-size:10px;color:rgba(255,255,255,.8);background:rgba(0,0,0,.5);
  padding:3px 7px;border-radius:3px}
.lanaihero .photo__cr a{color:inherit}
@media (max-width:640px){
  /* ⚠️ At phone width the headline spans the full column, so a left-weighted
     gradient leaves its right-hand words over bright sky. Mostly vertical here. */
  .lanaihero{min-height:clamp(300px,52vh,420px)}
  .lanaihero__scrim{background:
    linear-gradient(0deg, rgba(5,18,32,.80) 0%, rgba(5,18,32,.72) 50%,
                          rgba(5,18,32,.55) 100%),
    linear-gradient(90deg, rgba(5,18,32,.55) 0%, rgba(5,18,32,.30) 100%)}
  .lanaihero h1{max-width:none}
}




/* 🔴 THE HERO BUTTONS — 15 Sep 2026. Owner: "make sure the buttons are spread
   out and even across heros", "not sqished into the tiltles".
   Measured at 1280 before touching anything: rv-powersports had its buttons
   touching the headline at a gap of ZERO, because its row is `.hero__cta` and
   the rule only named `.btnrow` and `.hero__act`. The rest sat at 22px with an
   11px gap between them and heights running 40 to 53.
   ⭐ One rule, all three row names, and a floor under the height so a row of
   buttons reads as a row rather than as two different controls. */
.lanaihero .btnrow,
.lanaihero .hero__act,
.lanaihero .hero__cta{
  margin-top:clamp(1.6rem,2.6vw,2.2rem);
  display:flex; flex-wrap:wrap; align-items:center;
  gap:.85rem;
}
.lanaihero .btn{
  min-height:48px;
  display:inline-flex; align-items:center; justify-content:center;
  padding-inline:1.25rem;
}
@media (max-width:560px){
  /* ⚠️ Full width and stacked on a phone — two half-width buttons side by side
     put both under the 48px the thumb needs in the direction that matters. */
  .lanaihero .btnrow,.lanaihero .hero__act,.lanaihero .hero__cta{gap:.65rem}
  .lanaihero .btn{width:100%}
}


/* ── 👥 THE SOCIAL MARKS — 15 Sep 2026. Owner: "put fake no link social on the
   headers", after twice being told there is nowhere honest to point them.
   ⛔ THEY ARE NOT LINKS, AND THAT IS THE POINT. These companies are invented,
   so a social icon could only lead to an invented profile, to somebody else's
   real account, or to nothing — and a control that goes nowhere is worse than
   no control. They are `<span>` marks, `aria-hidden`, not focusable and not
   clickable: an illustration of where a real client's profiles sit in the bar,
   on a page that already says it is a demonstration.
   ⛔ Do not turn these into <a> on a real build without real profiles behind
   them. Bots On Staff's own Facebook and Instagram have never published once. */
.utilbar__social{display:inline-flex;align-items:center;gap:.55rem;opacity:.62}
.utilbar__social svg{width:15px;height:15px;display:block}
@media (max-width:560px){ .utilbar__social{display:none} }


/* 🔴 THE GHOST BUTTON, RESTATED BELOW `.btn` — 15 Sep 2026.
   The polish gate refused four demos for this and it was right: adding a
   `.lanaihero .btn` block after the ghost rules puts the outline variant at the
   mercy of source order in unlayered CSS. It happens that the block above sets
   no background, so nothing rendered wrong — but "it happens to be fine" is not
   a property anyone can rely on while editing this file later.
   ⛔ Any new `.btn` rule goes ABOVE this, or this moves below it. */
.lanaihero .btn--ghost,
.lanaihero .btn--line,
.lanaihero .btn--out{
  border-color:rgba(255,255,255,.62);
  color:#fff;
  background:rgba(7,22,38,.42);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
}
.lanaihero .btn--ghost:hover,
.lanaihero .btn--line:hover,
.lanaihero .btn--out:hover{background:rgba(7,22,38,.66);border-color:#fff}

.lanaihero .btn--ghost{
  border-color:rgba(255,255,255,.62);
  color:#fff;
  background:rgba(7,22,38,.42);
}


/* ── 📣 THE OFFER BAND, ON THE PHOTOGRAPH — 15 Sep 2026 ──────────────────────
   Owner: "i dont think it needs the white section evry vist", then "figure it
   out in a great spot dont just throw it somewhere be creative".
   🔴 IT CANNOT SIMPLY GO. The polish gate requires an offer strip on every page
   and it is right to — it is the one line on a demonstration site that says what
   the shop actually promises. But as a white slab wedged between the header and
   the hero it interrupted the only picture on the page before anyone had seen it.
   ⭐ So it is pinned to the FOOT of the hero, over the photograph, on the same
   dark glass as the scrim. The promise now reads as part of the image instead of
   as an announcement above it, and the page opens header -> photograph -> story
   with nothing cutting across.
   ⛔ Its own backdrop is near-opaque on purpose: type over a photograph is the
   one thing on this estate that has been measured wrong twice, and a band that
   carries its own ground cannot drift when the picture changes. */
.lanaihero{padding-bottom:0}
.lanaihero .offerbar{
  position:absolute; left:0; right:0; bottom:0; z-index:3;
  background:rgba(6,19,34,.86);
  -webkit-backdrop-filter:blur(10px); backdrop-filter:blur(10px);
  border-top:1px solid rgba(255,255,255,.16);
  border-bottom:0;
}
.lanaihero .offerbar__in{
  display:flex; align-items:center; gap:1rem; flex-wrap:wrap;
  padding-block:.7rem;
}
.lanaihero .offerbar__tag{
  color:#fff; border-color:rgba(255,255,255,.45); background:rgba(255,255,255,.10);
}
.lanaihero .offerbar__msg{color:rgba(255,255,255,.92); margin:0}
.lanaihero .offerbar__msg b{color:#fff}
.lanaihero .offerbar__go{color:#fff; border-color:rgba(255,255,255,.5)}
/* ⚠️ the hero's own content must clear the band, or the buttons sit under it */
.lanaihero__in{padding-bottom:clamp(5.5rem,9vw,7rem)}
@media (max-width:860px){
  /* ⛔ On a phone the band would eat the picture. It goes back into the flow
     directly beneath the hero — still out from between the header and the photo,
     which is the thing that was wrong. */
  .lanaihero .offerbar{position:static;backdrop-filter:none;-webkit-backdrop-filter:none}
  .lanaihero__in{padding-bottom:clamp(1.9rem,4.5vw,3rem)}
}


/* ══ 🧭 THE HEADER, 2026 — 15 Sep 2026 ══════════════════════════════════════
   Owner: "the header need to be way better on each site look like proper 2026
   header trends", "make sure everyting looks as goos as outr customer sites".
   🔴 MEASURED FIRST, ALL TWELVE AT 1280: heights ran from 62px to 223px, only
   one was sticky, and eleven carried a telephone number that the new utility bar
   was already showing a few pixels above it.
   ⭐ This layer is keyed on the `header` ELEMENT, not on a class, because these
   demos call it .site, .top, .mast, .nav and .masthead — five names for one
   thing. Anything that needs a class name is done per demo.
   ⛔ It is deliberately visual-only: sticky, glass, a hairline that appears on
   scroll, and honest focus rings. It does not re-order anybody's markup. */
header{
  position:sticky; top:0; z-index:60;
  -webkit-backdrop-filter:saturate(1.3) blur(10px);
  backdrop-filter:saturate(1.3) blur(10px);
  transition:box-shadow .22s ease, border-color .22s ease;
}
/* ⭐ The rule under the header only appears once you have scrolled — a border
   that is always there is chrome, a border that arrives is depth. */
header::after{
  content:""; position:absolute; left:0; right:0; bottom:-1px; height:1px;
  background:currentColor; opacity:0; transition:opacity .22s ease;
  pointer-events:none;
}
html[data-scrolled] header::after{opacity:.16}
html[data-scrolled] header{box-shadow:0 10px 30px -22px rgba(0,0,0,.55)}

/* ⛔ 44px is not decoration. WCAG 2.2 §2.5.8, and on a phone this is the only
   navigation there is. */
@media (max-width:900px){
  header nav a{min-height:44px;display:flex;align-items:center}
}
/* a focus ring that is visible on both a light and a dark header */
header a:focus-visible, header button:focus-visible, header label:focus-visible{
  outline:2px solid currentColor; outline-offset:3px; border-radius:6px;
}


/* 🔴 STICKY WAS LOSING ON SPECIFICITY — 15 Sep 2026. `header{position:sticky}`
   is (0,0,1) and these demos set `.top{position:relative}` at (0,1,0), so five
   of twelve silently stayed put while the other seven pinned. Measured, not
   assumed: auto-detailing, drain-cleaning, mobile-repair, plumbing-hvac and
   rv-powersports all read `relative` after the layer went in.
   ⭐ `header[class]` is (0,1,1) and beats a single class without reaching for
   !important, which would then have to be fought later. */
header[class]{position:sticky;top:0;z-index:60}

/* 🔴 THE OFF-CANVAS MENU WAS WIDENING THE PAGE. Parked at translateX(102%) the
   panel still counted toward scrollWidth — 700px against a 371px viewport — so
   the whole site scrolled sideways on a phone with nothing visible to scroll to.
   ⛔ `overflow-x:hidden` would fix it and break `position:sticky` in the same
   stroke; `clip` does not create a scroll container, so the header still pins. */
html{overflow-x:clip}


/* 🔴 THE NAV WAS WRAPPING ONTO ITS OWN ROW — 15 Sep 2026, measured at 1280.
   These headers are flex rows that ran out of width, so the navigation dropped
   beneath the brand and the header doubled in height: 134, 138, 104, 223.
   A sticky header that tall eats a quarter of a laptop screen, and it is the
   clearest difference between these and the client sites.
   ⭐ One row, and the NAV is the part allowed to give — `min-width:0` lets it
   shrink, and if it still will not fit it scrolls sideways within itself rather
   than pushing the whole header down. ⛔ `scrollbar-width:none` hides the bar,
   not the ability to scroll; the items remain reachable by wheel, trackpad,
   touch and keyboard. */
@media (min-width:901px){
  header .top__in,
  header .masthead__row,
  header .brandline{flex-wrap:nowrap}
  header nav{min-width:0}
}
@media (min-width:901px){
  header nav ul{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;-ms-overflow-style:none}
  header nav ul::-webkit-scrollbar{display:none}
  header nav a{white-space:nowrap}
}

/* ⚠️ Already one row; it was the 26/18 padding around a 73px row doing it. */
header{padding-block:.55rem}
header .masthead__row{gap:clamp(.8rem,2vw,1.6rem)}


/* 🔴 THE PADDING, NOT THE LAYOUT — 15 Sep 2026. Having got these headers onto
   one row, they were still 93-193px, and the cause was the same specificity
   mistake as the sticky rule: `header{padding-block:.5rem}` is (0,0,1) and
   `.site{padding:44px 0 32px}` is (0,1,0), so the trim never applied. Measured
   on auto-detailing: brand row 112px inside 44px above and 32px below.
   ⭐ `header[class]` wins without reaching for !important.
   ⚠️ This trims the ROOM around the brand, not the brand. What is left is each
   demo's own lockup at its own size — a 112px logo-and-tagline block is a
   design decision, and shrinking it would be changing their identity rather
   than tightening their chrome. */
header[class]{padding-block:clamp(.45rem,1vw,.8rem)}


/* 🔴 ONE HERO WAS 83vh BECAUSE ITS HEADLINE WAS 104px — 15 Sep 2026.
   Owner: "make sure desktop hero are proper sixe". Measured at 1280: nine
   heroes sat at 62-66vh and auto-detailing at 83vh, and the cause was not the
   hero box at all — its <h1> renders at 104px over three lines, 306px of type.
   That size was tuned for a hero made ONLY of words; over a photograph it is
   shouting. ⭐ Capped to the size the rest already use, so the set reads as one
   family. ⛔ Still large text for contrast purposes (>=24px), so the 3:1
   threshold the probe applies is unchanged. */
.lanaihero h1{font-size:clamp(2rem,4.4vw,3.5rem);line-height:1.06}

/* ═══ 2026 HERO + TYPE PASS ═══ hand-edited, see the note at the top of this file.
   ⛔ APPENDED deliberately: h1 is defined at ~124 and again at ~435, and an
   unlayered stylesheet resolves that by source order. */

/* ── 1. TYPE IN rem, h1 >= 3x BODY AT EVERY WIDTH ──────────────────────────
   BEFORE, and this was the flattest scale of the four: body 17px hard-pinned in
   px (WCAG 1.4.4 fails), hero h1 32px at 320 and 375 — a ratio of 1.88 against
   a bar of 3.0, and only 3.06 at 1280. A 32px headline over a 17px body is not
   a hierarchy, it is two body sizes.
   ⭐ Body is 1.0625rem (the same 17px, now scalable) and the h1 floor is
   3.1875rem — exactly 3x it, in the same unit, so the ratio cannot drift. */
body{font-size:1.0625rem}
h1,
.lanaihero h1{
  font-size:clamp(3.1875rem, 1.6rem + 4.8vw, 4.25rem);
  line-height:1.05;letter-spacing:-0.028em;font-weight:500;text-wrap:balance;
}

/* ── 2. THE HERO IS THE DOCUMENT ───────────────────────────────────────────
   The offer strip was 40 words describing the card, plus an uppercase pill and
   a repeat of the button beside it — 47 words, on all eighteen pages. It is now
   line 6 of work order SR-2419: the topping this customer asked for, refused,
   at $0.00. Eight words, and it argues instead of promising. */
.offerbar__tag,.offerbar__msg,.offerbar__go{display:none}
.herodoc{
  display:flex;align-items:baseline;flex-wrap:wrap;gap:.45rem 1.05rem;
  padding-top:.85rem;padding-bottom:.9rem;
}
.herodoc__no{
  flex:0 0 auto;font-family:var(--mono);font-size:.75rem;letter-spacing:.12em;
  color:var(--ink-faint);
}
.herodoc__item{
  flex:1 1 15rem;min-width:0;color:var(--ink);
  font-size:clamp(.9375rem,1.5vw,1.0625rem);line-height:1.35;
}
.herodoc__item b{color:var(--rust);font-weight:600}
.herodoc__amt{
  flex:0 0 auto;font-family:var(--mono);font-weight:700;
  font-variant-numeric:tabular-nums;font-size:clamp(1rem,1.7vw,1.1875rem);
  color:var(--rust);letter-spacing:-.01em;
}

/* ── 3. ONE HERO, AND IT HOLDS THE FOLD ────────────────────────────────────
   ⛔ min-height, never height: a five-line h1 at 320px is taller than the
   viewport and a fixed height clips it. */
.lanaihero{min-height:min(88vh,44rem);justify-content:flex-end}
/* ⛔ padding-TOP only. `.lanaihero .offerbar` is position:absolute, pinned to the
   bottom of the band, and the clearance that keeps the buttons out from under it
   is `.lanaihero__in{padding-bottom:clamp(5.5rem,9vw,7rem)}` further up this
   file — with a smaller value in the <=860px branch where the bar goes static.
   Setting padding-bottom here overrode BOTH and buried 35px of a 53px button row
   under the strip. Measured, not guessed: btnrow 726.8-779.7, strip top 744.4. */
.lanaihero__in{padding-top:3rem}
.lanaihero .btnrow{margin-top:1.15rem}
.lanaihero__in :is(h1,.btnrow){text-shadow:0 1px 2px rgba(0,0,0,.70),0 2px 20px rgba(0,0,0,.52)}
/* 🔴 `a.btn`, NOT `.btn`. THE TWO-PRIMARIES BUG: this stylesheet is unlayered,
   so a bare `.btn{` rule appended here would beat the `.btn--ghost{` rules above
   it at equal specificity and BOTH hero buttons would render solid — which is a
   defect that has actually shipped on this site. Qualifying the selector keeps
   the last `.btn{` above the last `.btn--ghost{`, which is what
   tools/check-demo-polish.mjs enforces. ⛔ Never append a bare `.btn{` below. */
.lanaihero a.btn{text-shadow:none}

/* ── 4. THE 2018 TELLS ─────────────────────────────────────────────────────
   This file's own header promises "hairline rules and air instead of boxes and
   shadows", then carries a 22px/40px drop shadow on the hero plate and 18
   uppercase selectors. ⭐ Uppercase survives only inside the work order and the
   spec table, where it is how the document actually reads. */
.wordmark__sub,.nav__list,.eyebrow,.btn,.foot h4,.chat-hd__t,
.photoslot__tag,.navbtn{text-transform:none;letter-spacing:.005em}
.eyebrow{border:0;border-radius:0;padding-left:0;color:var(--ink-faint)}
.hero .plate,.plate,.card,.chat-panel{box-shadow:none}
.btn:hover{transform:none}
.plate,.card,.specimen,.chat-panel,.form{border-color:var(--rule)}

/* 🔴 THE TWO-PRIMARIES BUG — see the identical note in roofing/styles.css.
   The `.lanaihero a.btn{…}` line above is now the last `.btn` rule in this
   unlayered file, so the ghost is restated here, last and unchanged. */
.btn--ghost{
  background:transparent; border-color:var(--canopy); color:var(--canopy-deep);
}

/* 🔴 THE STRIP IS DARK INSIDE THE HERO, NOT PAPER. This is a warm-paper site, so
   the document row above was written in `--ink` on the assumption the offer
   strip is a pale band — which it is on all seventeen interior pages. Inside
   `.lanaihero` an earlier rule repaints it `rgba(6,19,34,.86)` so it reads over
   the photograph, and the dark row on the dark strip measured 1.13:1 against a
   floor of 4.5, with the $0.00 at 2.83 against 3.0. The refusal — the most
   persuasive thing on the site — was effectively invisible in the hero.
   ⭐ ONE SELECTOR, TWO BACKDROPS: resolve it by naming the ancestor, not by
   changing the token, because the paper version is correct where it lives. */
.lanaihero .herodoc__item{color:#fff}
.lanaihero .herodoc__item b{color:#ffb27a}
.lanaihero .herodoc__amt{color:#ffb27a}
.lanaihero .herodoc__no{color:rgba(255,255,255,.80)}

/* 🔴 A POOL UNDER THE WORDS, NOT A LID ON THE PICTURE.
   MEASURED with the type hidden, before: band mean luma 37-45 against a floor
   of 60, picture side 58-79 against 80. At that level the photograph is paying
   for bandwidth and a licence obligation and contributing nothing anyone can
   see — and the owner's instruction is a full-picture hero, professionally
   done. Meanwhile the headline was sitting at 11-17:1 against a floor of 3.0.
   ⭐ So the margin gets SPENT ON THE PHOTOGRAPH, which is the right order: make
   the foreground carry itself, then take the darkness back.
   🔴 EVERY VERTICAL STOP IS IN px. A gradient percentage resolves against the
   ELEMENT, and this band is 704px tall against a 900px screen — the old
   `linear-gradient(0deg, …50%…)` was aiming its mid stop ~350px below where it
   looked like it was. Horizontal % is safe: the element is viewport-wide.
   ⭐ The last third stays at .06. That number IS the picture. If contrast ever
   fails here, fix the foreground or the near stops — never the far end. */
.lanaihero__scrim{
  background:
    linear-gradient(0deg,  rgba(5,18,32,.46) 0px, rgba(5,18,32,0) 240px),
    linear-gradient(92deg, rgba(5,18,32,.88) 0%,  rgba(5,18,32,.80) 40%,
                           rgba(5,18,32,.66) 58%, rgba(5,18,32,.20) 78%,
                           rgba(5,18,32,.06) 100%)}

/* ⭐ THE MARK IS TYPOGRAPHIC NOW — a serif letterform, 22x30, not a square line
   drawing. width:auto or the portrait ratio is squashed back into a square. */
.brandmark{width:auto;height:30px}

/* ── A PHOTOGRAPH WHERE A DRAWING WAS ────────────────────────────────────────
   ⛔ Not a picture in a rounded card with margin round it — the owner's words
   are "full picture … done professionally". Full-bleed to the gutter, one
   hairline caption under it, no shadow, no radius, no frame. */
.photoband{margin:0 0 2.25rem;padding:0}
.photoband img{display:block;width:100%;height:clamp(240px,34vw,460px);
  object-fit:cover;object-position:center 55%}
.photoband__cap{max-width:74ch;margin:.7rem auto 0;padding:0 clamp(14px,3vw,26px);
  font-size:.8125rem;line-height:1.5;opacity:.72}

/* ═══ GLASS — TREE SERVICE: A SOFT FROSTED CHIP ══════════════════════════════
   A different MATERIAL from the other three, not the same pill in a new colour:
   soft 12px corners, warm frost, no hard top lip. This is the paper-notebook
   voice, so the glass is warm rather than smoked.
   ⛔ Base declaration = the no-backdrop-filter fallback and it clears 4.5:1 by
   itself; the blur is the @supports enhancement that pays for the lower alpha. */
.lanaihero .btn,.lanaihero .btn--ghost{
  border-radius:12px;border:1px solid rgba(255,255,255,.26);
  transition:background-color .24s var(--ease),border-color .24s var(--ease);
}
.lanaihero .btn{
  --glass-fb:rgba(38,72,58,.94);
  background:rgba(38,72,58,.94);color:#fff;border-color:rgba(190,222,200,.50);
}
@supports ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .lanaihero .btn{background:rgba(38,72,58,.78);
    -webkit-backdrop-filter:blur(18px) saturate(1.25);backdrop-filter:blur(18px) saturate(1.25)}
}
.lanaihero .btn:focus-visible,.lanaihero .btn--ghost:focus-visible{
  outline:2px solid #f6f2e7;outline-offset:3px}
/* 🔴 restated last — see the note in roofing/styles.css */
.btn--ghost{
  --glass-fb:rgba(246,242,231,.92);
  background:rgba(246,242,231,.92);color:#241f18;
  border:1px solid rgba(36,31,24,.20);border-radius:12px;
}
@supports ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .btn--ghost{background:rgba(246,242,231,.74);
    -webkit-backdrop-filter:blur(18px) saturate(1.15);backdrop-filter:blur(18px) saturate(1.15)}
}

/* 🔴 same specificity defect as roofing — `.lanaihero .btn` was matching the
   secondary, which also carries `.btn`. Both hero buttons rendered green. */
.lanaihero .btn.btn--ghost{
  background:rgba(246,242,231,.92);color:#241f18;
  border:1px solid rgba(36,31,24,.20);border-radius:12px;
  --glass-fb:rgba(246,242,231,.92);
}
@supports ((backdrop-filter:blur(2px)) or (-webkit-backdrop-filter:blur(2px))){
  .lanaihero .btn.btn--ghost{background:rgba(246,242,231,.74);
    -webkit-backdrop-filter:blur(18px) saturate(1.15);backdrop-filter:blur(18px) saturate(1.15)}
}
.btn--ghost{background:rgba(246,242,231,.92);color:#241f18;border-radius:12px}

/* ═══ THE SHEEN IS A SHAPE, NOT A SHEET ══════════════════════════════════════
   Owner, 23 Sep 2026: "i think the picture should be full hero then shene out
   where you want the text" · "evry hero needs to be perfecto".
   🔴 MEASURED BEFORE (tools/_sheen.mjs): sheen extent 100% of the frame on all
   four heroes — a global wash. The band, with the opaque offer strip excluded,
   sat at roughly HALF the photograph's own luminance across the whole picture,
   including the sky and the far side where no word is ever printed.

   ⭐ THE TECHNIQUE: a vertical intensity profile PAINTED, multiplied by a
   horizontal falloff MASKED. Two background layers would composite additively
   and still cover the whole box; a mask multiplies, so the result is a genuine
   two-dimensional shape that is soft on both axes and reaches true zero.
   ⛔ Soft stops only. A visible boundary where the sheen ends is worse than the
   flat wash it replaces.
   🔴 EVERY VERTICAL STOP IS IN px. A gradient percentage resolves against the
   ELEMENT, and this band is min(88vh,44rem) — its height moves with the window.
   Horizontal % is safe: the element is viewport-wide.
   ⭐ The horizontal stops are keyed to THIS site's measured type block, not to a
   shape that looked right — the widest run of ink ends at a different place on
   each of the four.
   ⚠️ FALLBACK: where mask-image is unsupported the vertical gradient paints
   alone — a bottom wash at full width. Dimmer than intended, never unreadable,
   which is the right direction for a graceful failure. */
.lanaihero__scrim{
  background:linear-gradient(0deg,
    rgba(6,20,14,.92) 0px,
    rgba(6,20,14,.88) 170px,
    rgba(6,20,14,.66) 330px,
    rgba(6,20,14,.30) 460px,
    rgba(6,20,14,0)   600px);
  -webkit-mask-image:linear-gradient(90deg,#000 0%,#000 48%,
    rgba(0,0,0,.58) 64%, rgba(0,0,0,.18) 78%, transparent 88%);
  mask-image:linear-gradient(90deg,#000 0%,#000 48%,
    rgba(0,0,0,.58) 64%, rgba(0,0,0,.18) 78%, transparent 88%);
}
/* ⛔ A PHONE IS NOT A NARROW DESKTOP. Below 741px the headline wraps to four or
   five lines and the type occupies almost the whole frame, so a horizontal
   falloff keyed to a desktop text block would leave the last words bare. The
   sheen goes nearly full width and taller; what still protects the photograph
   here is the VERTICAL profile, because the top half carries no type. */
@media (max-width:46.25rem){
  .lanaihero__scrim{
    background:linear-gradient(0deg,
      rgba(6,20,14,.93) 0px,
      rgba(6,20,14,.90) 220px,
      rgba(6,20,14,.70) 400px,
      rgba(6,20,14,.32) 530px,
      rgba(6,20,14,0)   660px);
    -webkit-mask-image:linear-gradient(90deg,#000 0%,#000 80%,rgba(0,0,0,.45) 92%,transparent 100%);
    mask-image:linear-gradient(90deg,#000 0%,#000 80%,rgba(0,0,0,.45) 92%,transparent 100%);
  }
}

/* 🔴 THE REFUSAL WAS OFF-SCREEN ON A PHONE. Diagnosed, not guessed: the glyph
   probe returned NO DIFF for the whole document row at 320 and 375, and a
   no-diff has three causes — invisible, unpainted, covered — of which only one
   is a contrast defect. tools/_heroluma.mjs now reports which; it said
   UNPAINTED, outside the captured viewport. The hero was min(88vh,44rem) = 704px
   tall, and 704 + the masthead put the strip 27px below an 812px fold.
   ⛔ That breaks the one rule this whole hero exists for: the refusal is read
   WITHOUT SCROLLING. A shorter band on a phone, so the row is on screen.
   ⛔ min-height, never height — the band still grows when a five-line headline
   needs it, which is the case a fixed height would clip. */
@media (max-width:46.25rem){
  .lanaihero{min-height:min(70vh,34rem)}
}

/* ⚠️ THE PHONE RAMP HAD TO SHRINK WITH THE PHONE BAND. Shortening the hero so
   the refusal clears the fold left the previous px stops (zero at 660px) taller
   than the band itself (~544px), so the sheen never reached zero and the whole
   phone hero went to band luma 53 against a floor of 60 — darker than the
   desktop version it was supposed to improve on.
   ⛔ This is the cost of px stops, and it is still the right trade: a % stop
   would drift with the viewport height instead, which is harder to see and
   harder to fix. When the band's height changes, the ramp is a number you own. */
@media (max-width:46.25rem){
  .lanaihero__scrim{
    background:linear-gradient(0deg,
      rgba(6,20,14,.93) 0px,
      rgba(6,20,14,.88) 140px,
      rgba(6,20,14,.62) 260px,
      rgba(6,20,14,.26) 350px,
      rgba(6,20,14,0)   430px);
  }
}

/* ⚖️ THE PHONE HERO IS A THREE-WAY TRADE AND THE FIRST TWO ATTEMPTS EACH LOST
   ONE LEG OF IT: a tall band put the refusal below the fold; a short band with
   a short ramp pushed the top of the headline to 1.89:1 against a floor of 3.
   ⛔ Contrast is not the leg that gives. So the TYPE BLOCK shrinks instead:
   the two hero buttons sit side by side rather than stacked full width, which
   returns a whole row (~55px) to the photograph, and the band grows back.
   ⭐ Then the ramp covers the type's real height and still reaches zero with
   clean photograph above it. Measured, not reasoned. */
@media (max-width:46.25rem){
  .lanaihero{min-height:min(72vh,36rem)}
  /* ⛔ comma-listed with the ghost on purpose: a bare `.btn{` rule here would
     become the last one in this unlayered file and strip the secondary. */
  .lanaihero .btn,.lanaihero .btn--ghost,
  .band--photo .btn,.band--photo .btn--out{width:auto;flex:0 1 auto}
  .lanaihero__scrim{
    background:linear-gradient(0deg,
      rgba(6,20,14,.93) 0px,
      rgba(6,20,14,.90) 200px,
      rgba(6,20,14,.74) 330px,
      rgba(6,20,14,.40) 440px,
      rgba(6,20,14,.12) 510px,
      rgba(6,20,14,0)   580px);
  }
}

/* 🔴 THE CHAT LAUNCHER WAS PAINTED ON TOP OF THE REFUSAL. Measured at 375px:
   the launcher is position:fixed at left:16px bottom:16px, box 16,748→107,796,
   and the document row sits at 0,723→375,777. document.elementFromPoint at the
   row's left end returned the launcher, not the row — so the first words of the
   one line this whole hero exists for were covered, at scroll 0, before the
   reader has done anything.
   ⚠️ This is the case ux-build calls unavoidable: a floating element is escapable
   by scrolling everywhere EXCEPT where the reader already is.
   ⭐ Raise it clear of the strip on phones rather than shrinking the hero again
   — the strip's own height is the offset, taken from the same tokens it uses. */
@media (max-width:46.25rem){
  .chat-btn,.chat-panel{bottom:calc(16px + 3.9rem + env(safe-area-inset-bottom,0px))}
}

/* ⚠️ AND THE SAME COLLISION AT 741px, WHICH THE PHONE BREAKPOINT MISSED.
   The probe found chat-btn painted over "Line 6" at 741 on tree-service: at that
   width the nav wraps, the masthead grows, and the strip is pushed far enough
   down the viewport to meet a launcher pinned 16px off the bottom. It does NOT
   collide at 1280 or 1440, where the header is short again — so this is a
   header-height effect, not a width effect, and the breakpoint has to be wide
   enough to cover every layout where the two can meet. Verified at 320, 375,
   741, 1280 and 1440. */
@media (max-width:64rem){
  .chat-btn,.chat-panel{bottom:calc(16px + 3.9rem + env(safe-area-inset-bottom,0px))}
}

/* 🔴 AND IT COLLIDES AT 1280 TOO — RAISED AT EVERY WIDTH.
   Measured directly on the page: the launcher covers 84% of the row's line
   number and document.elementFromPoint at its centre returns the launcher, not
   the row. My own glyph probe called 1280 CLEAN, because the uncovered 16% of
   the glyphs still produced a diff and so it returned a ratio instead of the
   no-diff that would have flagged it. ⛔ A contrast probe is not an overlap
   probe; do not let one stand in for the other.
   ⭐ The media query is gone. A launcher pinned 16px off the bottom will meet
   the strip at whatever width the header happens to be tall enough — 741 and
   1280 both did — so the offset is unconditional. It costs one row of empty
   space at the bottom of the screen and removes the whole class of collision. */
.chat-btn,.chat-panel{bottom:calc(16px + 3.9rem + env(safe-area-inset-bottom,0px))}

/* 🔴 MOVING THE LAUNCHER WAS THE WRONG FIX AND IT CAUSED WHAT IT CURED.
   Measured per width instead of reasoned: at 320 the strip ends 72px above the
   fold and at 741 it ends 88px above, and the launcher (42-48px plus its 16px
   inset) ALREADY FIT UNDERNEATH at both. Lifting it 78px moved it off the
   photograph and INTO the strip — two new collisions in exchange for one. And a
   single lift cannot be right everywhere: the room below the strip is 95px on
   roofing at 1280 and 8px on tree-service at the same width, because the two
   heroes are not the same height.
   ⭐ SO THE STRIP MOVES, NOT THE LAUNCHER. A fixed gutter at the foot of the
   band puts the document row clear of anything pinned to the bottom of the
   viewport, at every width, on every one of the four — and the launcher goes
   back where its own stylesheet put it.
   ⛔ Both declarations are needed: the strip is position:absolute in the wide
   layout and static below 860px, and only one of them answers to each. */
.chat-btn,.chat-panel{bottom:18px}
.lanaihero{padding-bottom:4.6rem}
.lanaihero .offerbar{bottom:4.6rem}

/* ⚠️ AT 320 THE ROW WRAPS TO THREE LINES and the strip grows from ~55px to
   ~108px, which ate the 4.6rem gutter and put it back under the launcher —
   plumbing-hvac's ran 671..779 in a 780px viewport, flush against the fold.
   The gutter has to clear the TALLEST the strip gets, not the shortest.
   ⭐ 320 is SC 1.4.10's own number and where a real iPhone SE at 400% zoom
   lands; it is the width where everything is worst and the one most likely to
   be skipped. Measured here, not extrapolated from 375. */
@media (max-width:22.5rem){
  .lanaihero{padding-bottom:7.6rem}
  .lanaihero .offerbar{bottom:7.6rem}
}

/* 🔴 AT 320 THE $0.00 WAS 97% COVERED BY THE CHAT LAUNCHER.
   The row is a flex line; at 320 it wraps to three stacked lines and the amount
   drops to the THIRD line, left-aligned — which is precisely where a launcher
   pinned to the bottom-left sits. document.elementFromPoint at the middle of
   "$0.00" returned the launcher. The single most important literal on the site,
   invisible, at the width the accessibility criterion names.
   ⭐ A two-column grid keeps the amount on the right edge where a document puts
   it, clear of anything docked bottom-left, and drops the strip from three
   lines to two — which also buys back the fold. */
@media (max-width:22.5rem){
  .herodoc{display:grid;grid-template-columns:minmax(0,1fr) auto;
    align-items:baseline;column-gap:.7rem;row-gap:.2rem}
  .herodoc__no{grid-column:1/-1}
  .herodoc__item{grid-column:1}
  .herodoc__amt{grid-column:2;justify-self:end}
}

/* ⚠️ AT 320 THE CONTENT ALREADY FILLS THE SCREEN, so a min-height only pushes
   the foot of the band past the fold. A six-line headline at the 3x-body floor
   plus two buttons plus the document row is taller than 320x780 leaves after
   the masthead — there is nothing for a minimum to add, and what it adds comes
   off the bottom, which is where the refusal lives.
   ⛔ Still min-height:auto rather than a fixed height: the band must be free to
   grow, it just must not be padded taller than its content. */
@media (max-width:22.5rem){
  .lanaihero{min-height:auto}
}

/* ⚠️ THE 320 GUTTER WAS BELOW THE FOLD AND SO BOUGHT NOTHING. Measured on
   plumbing-hvac: band 162..886 in a 780px viewport, strip 670..764, gutter
   121.6px sitting at 764..886 — entirely off-screen. The strip's position is
   set by the CONTENT ABOVE IT, not by padding underneath, so the only way to
   lift it is to take height out of what comes first.
   ⭐ ~56px recovered from the hero's top padding, the headline's leading and
   the button gap — none of it from the type SIZE, which is pinned at 3x body. */
@media (max-width:22.5rem){
  .lanaihero .lanaihero__in,.lanaihero>.wrap{padding-top:1rem}
  .lanaihero h1,.lanaihero .h1{line-height:.98}
  .lanaihero .btnrow{margin-top:.8rem}
  .lanaihero{padding-bottom:1.5rem}
}

/* ⚖️ THE 320 RAMP, AND THE TRADE I REFUSED TO MAKE.
   Letting content drive the band at 320 made it shorter again, so the previous
   ramp (zero at 580px) never reached zero inside it and the whole hero went to
   band luma 46 against a floor of 60. This ramp is scaled to the band that is
   actually there.
   ⛔ AND IT STILL COVERS THE TYPE FIRST. At 320 a headline pinned at 3x body is
   six lines, and with two buttons and the document row the type occupies almost
   the whole band — there is no width of clean photograph to be had without
   either shrinking the type below its floor or pushing the refusal past the
   fold. Both are worse than a darker picture on the narrowest phone, so the
   picture-side number is reported under floor rather than bought. */
@media (max-width:22.5rem){
  .lanaihero__scrim{
    background:linear-gradient(0deg,
      rgba(6,20,14,.93) 0px,
      rgba(6,20,14,.90) 180px,
      rgba(6,20,14,.76) 300px,
      rgba(6,20,14,.46) 400px,
      rgba(6,20,14,.16) 470px,
      rgba(6,20,14,0)   530px);
  }
}

/* ⚖️ 320 RAMP, TUNED TO THIS SITE'S OWN BAND. One shared set of stops could not
   serve four heroes whose headlines wrap to four, five and six lines: the same
   ramp left roofing's band at 48 luma with contrast to spare, and dropped
   plumbing-hvac's headline to 2.61 against a floor of 3. The type is covered
   first, everywhere; what varies is how much photograph is left over. */
@media (max-width:22.5rem){
  .lanaihero__scrim{
    background:linear-gradient(0deg,
      rgba(6,20,14,.93) 0px,
      rgba(6,20,14,.90) 170px,
      rgba(6,20,14,.74) 280px,
      rgba(6,20,14,.44) 360px,
      rgba(6,20,14,.15) 420px,
      rgba(6,20,14,0)   480px);
  }
}
