/* Layout and components. Every value here is a token, so swapping the trade
   preset restyles the whole site without touching this file. */

/* ---- reset ------------------------------------------------------------ */
*,
*::before,
*::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-sans);
  font-size: var(--t-base);
  line-height: var(--leading-body);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, textarea, select { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }
:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; border-radius: var(--r-sm); }
::selection { background: var(--c-accent); color: var(--c-accent-ink); }

/* ---- primitives ------------------------------------------------------- */
.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: var(--gutter); }
.wrap-narrow { max-width: var(--wrap-narrow); }
.section { padding-block: var(--s-8); position: relative; }
.stack > * + * { margin-top: var(--s-3); }
.center { text-align: center; }

.eyebrow {
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--c-accent);
  font-weight: 650;
}
.display {
  font-family: var(--font-display);
  font-size: var(--t-3xl);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  font-weight: 700;
  text-wrap: balance;
}
.h2 { font-size: var(--t-2xl); line-height: var(--leading-tight); letter-spacing: var(--tracking-tight); font-weight: 700; text-wrap: balance; }
.h3 { font-size: var(--t-xl); line-height: 1.18; letter-spacing: var(--tracking-tight); font-weight: 680; text-wrap: balance; }
.lede { font-size: var(--t-lg); color: var(--c-muted); text-wrap: pretty; }
.muted { color: var(--c-muted); }
.mono { font-family: var(--font-mono); font-size: var(--t-sm); }

.btn {
  --btn-bg: var(--c-accent);
  --btn-ink: var(--c-accent-ink);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55em;
  padding: 0.85em 1.35em;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--btn-bg);
  color: var(--btn-ink);
  font-weight: 680;
  font-size: var(--t-sm);
  letter-spacing: 0.005em;
  cursor: pointer;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition: transform var(--dur-fast) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out),
              background-color var(--dur-fast) linear;
  box-shadow: var(--shadow-2);
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--shadow-3); }
.btn:active { transform: translateY(0); }
/* Sheen sweep on hover. Purely decorative, and it is the kind of thing that
   reads as expensive rather than busy -- kept on hover only, never looping. */
.btn::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(100deg, transparent 20%, rgb(255 255 255 / 0.35) 45%, transparent 70%);
  transform: translateX(-120%);
  transition: transform var(--dur-slow) var(--ease-out);
}
.btn:hover::after { transform: translateX(120%); }
.btn-ghost {
  --btn-bg: transparent;
  --btn-ink: var(--c-text);
  border: 1px solid var(--c-line);
  box-shadow: none;
}
.btn-ghost:hover { border-color: var(--c-accent); color: var(--c-accent); }
.btn-lg { padding: 1.05em 1.7em; font-size: var(--t-base); }

.chip {
  display: inline-flex; align-items: center; gap: 0.5em;
  padding: 0.4em 0.8em; border: 1px solid var(--c-line);
  border-radius: var(--r-pill); font-size: var(--t-xs);
  color: var(--c-muted); background: color-mix(in srgb, var(--c-surface) 60%, transparent);
}
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--c-good); flex: none; }
.dot-pulse { animation: pulse 2.4s var(--ease-in-out) infinite; }
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c-good) 60%, transparent); }
  50% { box-shadow: 0 0 0 7px transparent; }
}

.card {
  background: linear-gradient(180deg, var(--c-surface) 0%, color-mix(in srgb, var(--c-surface) 40%, var(--c-bg)) 100%);
  border: 1px solid var(--c-line);
  border-radius: var(--r-lg);
  padding: var(--s-4);
  box-shadow: var(--shadow-1);
  transition: transform var(--dur-base) var(--ease-out),
              border-color var(--dur-base) var(--ease-out),
              box-shadow var(--dur-base) var(--ease-out);
}
.card:hover { transform: translateY(-4px); border-color: color-mix(in srgb, var(--c-accent) 45%, var(--c-line)); box-shadow: var(--shadow-2); }

.grid { display: grid; gap: var(--s-3); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }

/* ---- reveal-on-scroll -------------------------------------------------- */
/* Elements start hidden only once JS confirms it can animate them back, so a
   failed script leaves a readable page rather than a blank one. */
.js [data-reveal] { opacity: 0; transform: translateY(18px); }
.js [data-reveal].in {
  opacity: 1; transform: none;
  transition: opacity var(--dur-reveal) var(--ease-out),
              transform var(--dur-reveal) var(--ease-out);
  transition-delay: var(--d, 0ms);
}

/* ---- header ------------------------------------------------------------ */
.header {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--c-bg) 82%, transparent);
  backdrop-filter: blur(14px) saturate(1.3);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur-base) var(--ease-out),
              background-color var(--dur-base) var(--ease-out);
}
.header.stuck { border-bottom-color: var(--c-line); background: color-mix(in srgb, var(--c-bg) 94%, transparent); }
.header-in { display: flex; align-items: center; gap: var(--s-3); height: var(--header-h); }
.brand { display: flex; align-items: center; gap: 0.6rem; font-weight: 720; letter-spacing: var(--tracking-tight); }
.brand-mark {
  width: 34px; height: 34px; border-radius: 10px; flex: none;
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--c-accent), color-mix(in srgb, var(--c-accent) 55%, var(--c-accent-2)));
  color: var(--c-accent-ink); font-weight: 800; font-size: 0.95rem;
  box-shadow: var(--shadow-1);
}
.nav { display: flex; gap: var(--s-3); margin-left: auto; align-items: center; }
/* :not(.btn) is load-bearing. A bare `.nav a` selector outranks `.btn` on
   specificity and repaints the phone number in the header with the muted link
   colour -- 1.02:1 against the copper, i.e. unreadable on the one element that
   matters most on a plumber's page. */
.nav a:not(.btn) { font-size: var(--t-sm); color: var(--c-muted); transition: color var(--dur-fast) linear; }
.nav a:not(.btn):hover { color: var(--c-text); }
@media (max-width: 760px) { .nav .hide-sm { display: none; } }

/* ---- hero -------------------------------------------------------------- */
.hero { position: relative; padding-block: var(--s-6) var(--s-7); overflow: clip; }
/* Asymmetric on purpose. The old 1.05/0.95 split was a centred layout wearing
   a grid costume; 1.25/0.75 gives the headline the width it needs to set at
   the larger type scale and lets the phone sit off-axis, which is the only
   thing on the page that should not be symmetrical. */
.hero-grid { display: grid; gap: var(--s-5); grid-template-columns: 1.25fr 0.75fr; align-items: center; }
@media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; } }
.hero h1 { margin-block: var(--s-2) var(--s-3); }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-4); }
.trust-row { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-4); }
.stat-row { display: flex; gap: var(--s-5); flex-wrap: wrap; margin-top: var(--s-5); }
.stat b { display: block; font-size: var(--t-2xl); letter-spacing: var(--tracking-tight); line-height: 1; color: var(--c-accent); font-variant-numeric: tabular-nums; }
.stat span { font-size: var(--t-xs); color: var(--c-muted); letter-spacing: var(--tracking-wide); text-transform: uppercase; }

/* A slow, wide gradient wash behind the hero. Static gradient, animated
   transform only, so it stays on the compositor and never janks a scroll.
   --hero-wash is the per-theme dial: the dark presets want a strong glow, and
   a light preset that inherited the same strength gets a grey smudge across the
   top of the page that reads as a rendering fault rather than as design. */
.hero::before {
  content: "";
  position: absolute; inset: -30% -10% auto -10%; height: 90%;
  background:
    radial-gradient(60% 55% at 18% 30%,
      color-mix(in srgb, var(--c-accent) calc(var(--hero-wash) * 100%), transparent), transparent 70%),
    radial-gradient(50% 50% at 82% 20%,
      color-mix(in srgb, var(--c-accent-2) calc(var(--hero-wash) * 100%), transparent), transparent 70%);
  filter: blur(10px);
  animation: drift calc(26s * var(--motion-scale)) var(--ease-in-out) infinite alternate;
  pointer-events: none;
}
@keyframes drift {
  from { transform: translate3d(-2%, -1%, 0) scale(1); }
  to { transform: translate3d(3%, 2%, 0) scale(1.08); }
}

/* Fake phone showing the real booking screen a customer would get. */
.phone {
  width: min(300px, 100%); margin-inline: auto;
  border: 9px solid var(--c-surface-2); border-radius: 34px;
  background: var(--c-bg-2); box-shadow: var(--shadow-3);
  overflow: hidden; position: relative;
  transform: perspective(1200px) rotateY(-6deg) rotateX(2deg);
  transition: transform var(--dur-slow) var(--ease-out);
}
.phone:hover { transform: perspective(1200px) rotateY(0deg) rotateX(0deg); }
.phone-notch { height: 26px; background: var(--c-surface-2); display: grid; place-items: center; }
.phone-notch::after { content: ""; width: 68px; height: 5px; border-radius: 3px; background: color-mix(in srgb, var(--c-text) 22%, transparent); }
.phone-body { padding: var(--s-3); display: grid; gap: var(--s-2); }
.phone-row { display: flex; gap: var(--s-2); align-items: center; padding: var(--s-2); border-radius: var(--r-md); background: var(--c-surface); font-size: var(--t-xs); }
.phone-send {
  margin-top: var(--s-2); padding: var(--s-3); border-radius: var(--r-md);
  background: color-mix(in srgb, var(--c-good) 16%, var(--c-surface));
  border: 1px solid color-mix(in srgb, var(--c-good) 40%, transparent);
  font-size: var(--t-xs); color: var(--c-text);
  animation: arrive var(--dur-slow) var(--ease-out) both;
  animation-delay: calc(900ms * var(--motion-scale));
}
@keyframes arrive { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

/* ---- the "what your customer sees now" comparison ---------------------- */
.ba { display: grid; gap: var(--s-4); grid-template-columns: 1fr 1fr; }
@media (max-width: 860px) { .ba { grid-template-columns: 1fr; } }
.ba-pane { border: 1px solid var(--c-line); border-radius: var(--r-lg); overflow: hidden; background: var(--c-surface); }
.ba-head { display: flex; align-items: center; gap: 0.6rem; padding: 0.8rem var(--s-3); border-bottom: 1px solid var(--c-line); font-size: var(--t-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; }
.ba-body { padding: var(--s-4); min-height: 260px; }
.ba-verdict { padding: var(--s-3); border-top: 1px solid var(--c-line); font-size: var(--t-sm); }
/* The ruled list inside the after-pane runs to the pane's own edges, so it
   reads as the pane's content rather than as a card dropped inside a card. */
.ba-ruled { border-top: 0; }
.ba-ruled .ruled-row:last-child { border-bottom: 0; }
.ba-ruled .ruled-row { padding-inline: var(--s-4); }
.ghost-note { padding: 0.6rem 0.9rem; font-size: 0.78rem; color: #777; }
.ba-verdict.bad { color: var(--c-bad); }
.ba-verdict.good { color: var(--c-good); }

/* A deliberately bad mock of what a stranger sees today: wrong name, no phone,
   no way to do anything. It is ugly on purpose -- that is the point. */
.ghost-site { font-family: var(--font-sans); color: #4a4a4a; background: #fff; margin: calc(var(--s-3) * -1); }
.ghost-bar { background: #f1f1f1; border-bottom: 1px solid #ddd; padding: 0.6rem 0.9rem; font-size: 0.72rem; color: #777; }
.ghost-title { font-size: 1.05rem; font-weight: 400; color: #333; padding: 1rem 0.9rem 0.2rem; }
.ghost-line { height: 8px; border-radius: 3px; background: #ececec; margin: 0.55rem 0.9rem; }
.ghost-line.w70 { width: 70%; } .ghost-line.w45 { width: 45%; } .ghost-line.w85 { width: 85%; }

/* ---- services ---------------------------------------------------------- */
.svc { display: flex; flex-direction: column; gap: var(--s-2); }
.svc-ico { width: 40px; height: 40px; border-radius: var(--r-md); display: grid; place-items: center; background: color-mix(in srgb, var(--c-accent) 16%, transparent); color: var(--c-accent); font-size: 1.15rem; }
.svc h3 { font-size: var(--t-lg); font-weight: 660; }
.svc p { color: var(--c-muted); font-size: var(--t-sm); }

/* ---- steps ------------------------------------------------------------- */
.steps { counter-reset: step; display: grid; gap: var(--s-3); }
.step { position: relative; padding-left: 3.4rem; }
.step::before {
  counter-increment: step; content: counter(step);
  position: absolute; left: 0; top: 0;
  width: 2.3rem; height: 2.3rem; border-radius: 50%;
  display: grid; place-items: center;
  background: color-mix(in srgb, var(--c-accent) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--c-accent) 40%, transparent);
  color: var(--c-accent); font-weight: 700; font-size: var(--t-sm);
}

/* ---- service area ------------------------------------------------------ */
.areas { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.area {
  padding: 0.5em 0.9em; border-radius: var(--r-pill);
  border: 1px solid var(--c-line); font-size: var(--t-sm); color: var(--c-muted);
  transition: color var(--dur-fast) linear, border-color var(--dur-fast) linear,
              background-color var(--dur-fast) linear;
}
.area:hover { color: var(--c-accent-ink); background: var(--c-accent); border-color: var(--c-accent); }

/* Grouped service area, for the studio page. The heading is what makes a long
   distance credible: a reader who sees "Warrenton" and "Belleville" in one flat
   row discounts both, and one who sees them under their own counties does not.
   The left rule ties each group to its label without a box, which would fight
   the flat chips underneath it. */
.area-groups { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.area-group { border-left: 2px solid var(--c-accent); padding-left: var(--s-3); }
.area-group__label {
  font-size: var(--t-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase;
  color: var(--c-accent); font-weight: 650; margin-bottom: var(--s-2);
}
.area-group .areas { gap: 0.4rem; }
.area-group .area { font-size: var(--t-xs); padding: 0.35em 0.7em; }

/* ---- CTA band ---------------------------------------------------------- */
.band {
  background: linear-gradient(120deg, var(--c-surface-2), var(--c-surface));
  border-block: 1px solid var(--c-line);
  position: relative; overflow: hidden;
}
.band::after {
  content: ""; position: absolute; inset: auto -20% -60% -20%; height: 120%;
  background: radial-gradient(50% 60% at 50% 100%, color-mix(in srgb, var(--c-accent) 26%, transparent), transparent 70%);
  pointer-events: none;
}

/* ---- form -------------------------------------------------------------- */
.form { display: grid; gap: var(--s-3); }
.field { display: grid; gap: 0.4rem; }
.field label { font-size: var(--t-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--c-muted); }
.input {
  width: 100%; padding: 0.85em 1em; border-radius: var(--r-md);
  border: 1px solid var(--c-line); background: var(--c-bg-2); color: var(--c-text);
  transition: border-color var(--dur-fast) linear, box-shadow var(--dur-fast) linear;
}
.input:focus { outline: none; border-color: var(--c-accent); box-shadow: var(--ring); }
.input::placeholder { color: color-mix(in srgb, var(--c-muted) 65%, transparent); }
.form-note { font-size: var(--t-xs); color: var(--c-muted); }
.form-done { display: none; padding: var(--s-4); border-radius: var(--r-md); background: color-mix(in srgb, var(--c-good) 14%, var(--c-surface)); border: 1px solid color-mix(in srgb, var(--c-good) 40%, transparent); }
.form.sent .form-fields { display: none; }
.form.sent .form-done { display: block; animation: arrive var(--dur-slow) var(--ease-out) both; }

/* ---- service rows -------------------------------------------------------
   Three columns on desktop: index, the pitch, and the outcome. The outcome
   column is the one that does the selling -- "a site you are proud to send
   customers to" is a thing the reader can picture, where a feature list is not
   -- so it gets equal weight rather than being a small footnote under the copy.

   The border between the number column and the body, rather than a gap, is
   deliberate: it makes the column read as a ruled index instead of a floating
   number that landed in the wrong place. */
.svc-rows { border-top: 1px solid var(--c-line); }
.svc-row {
  display: grid;
  gap: var(--s-2) var(--s-4);
  grid-template-columns: 3.5rem minmax(0, 1fr) minmax(0, 0.8fr);
  padding-block: var(--s-4);
  border-bottom: 1px solid var(--c-line);
  align-items: start;
}
@media (max-width: 820px) {
  .svc-row { grid-template-columns: 3rem minmax(0, 1fr); }
  .svc-row__outcome { grid-column: 2; }
}
.svc-row__n {
  font-family: var(--font-mono);
  font-size: var(--t-sm);
  color: var(--c-muted);
  padding-top: 0.35em;
  border-right: 1px solid var(--c-line);
}
.svc-row__n span { display: block; padding-right: var(--s-3); }
.svc-row__label {
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--c-accent);
  font-weight: 650;
}
.svc-row h3 { font-size: var(--t-xl); line-height: 1.15; letter-spacing: var(--tracking-tight); font-weight: 700; margin-block: 0.35em 0.5em; }
.svc-row__body { color: var(--c-muted); font-size: var(--t-sm); max-width: 46ch; }
.svc-row__outcome { border-left: 0; padding-left: 0; }
@media (min-width: 821px) {
  .svc-row__outcome { border-left: 1px solid var(--c-line); padding-left: var(--s-4); }
}
.svc-row__outcome b {
  display: block;
  font-size: var(--t-xs);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--c-muted);
  font-weight: 650;
  margin-bottom: 0.5em;
}
.svc-row__outcome span { font-size: var(--t-sm); }

/* ---- outcomes -----------------------------------------------------------
   The three-word summary. Set large and left-aligned rather than centred: a
   tradesperson reading this on a phone is scanning for what it says, not for how
   it is arranged. */
.outcomes { border-top: 1px solid var(--c-line); display: grid; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 700px) { .outcomes { grid-template-columns: 1fr; } }
.outcome {
  display: flex; flex-direction: column; justify-content: space-between; gap: var(--s-2);
  min-height: 9.5rem; padding: var(--s-3) var(--s-3) var(--s-3) 0;
  border-right: 1px solid var(--c-line);
}
.outcome + .outcome { padding-left: var(--s-3); }
.outcome:last-child { border-right: 0; }
@media (max-width: 700px) {
  .outcome { min-height: 0; padding: var(--s-3) 0; border-right: 0; border-bottom: 1px solid var(--c-line); }
  .outcome + .outcome { padding-left: 0; }
  .outcome:last-child { border-bottom: 0; }
}
.outcome b {
  font-size: var(--t-2xl); line-height: 0.95; letter-spacing: var(--tracking-tight);
  font-weight: 750; font-variant-numeric: tabular-nums;
}
.outcome span { font-size: var(--t-sm); color: var(--c-muted); max-width: 22ch; }

/* ---- estimator ----------------------------------------------------------
   The restraint here is the design. A number that is meant to be believed gets
   room, a number that is provisional gets none -- so the estimate is the large
   figure and the caveat is the small one, and the two cannot be confused at a
   glance from across a kitchen table. */
.estimator { display: grid; gap: var(--s-4); grid-template-columns: minmax(0, 1fr) minmax(0, 0.9fr); align-items: start; }
@media (max-width: 900px) { .estimator { grid-template-columns: 1fr; } }
.est-form { display: grid; gap: var(--s-3); }
.est__q { border: 0; border-top: 1px solid var(--c-line); padding: var(--s-3) 0 0; margin: 0; min-width: 0; }
.est__q legend { font-size: var(--t-base); font-weight: 660; letter-spacing: var(--tracking-tight); padding: 0; display: flex; gap: 0.6em; align-items: baseline; }
.est__n { font-family: var(--font-mono); font-size: var(--t-xs); color: var(--c-accent); }
.est__help { font-size: var(--t-xs); color: var(--c-muted); margin-top: 0.4em; }
.est__opts { display: grid; gap: 0.4rem; margin-top: var(--s-2); }
/* Native radio, restyled. The visible control is the label, which makes the
   whole row the hit target -- a 1px radio in the corner of a list is not
   something you tap on a phone with a cold hand. */
.est__opt {
  display: flex; gap: 0.7em; align-items: flex-start;
  padding: 0.7em 0.9em; border: 1px solid var(--c-line); border-radius: var(--r-md);
  font-size: var(--t-sm); cursor: pointer;
  transition: border-color var(--dur-fast) linear, background-color var(--dur-fast) linear;
}
.est__opt:hover { border-color: color-mix(in srgb, var(--c-accent) 50%, var(--c-line)); }
.est__opt input { accent-color: var(--c-accent); margin: 0; flex: none; margin-top: 0.3em; }
.est__opt:has(input:checked) {
  border-color: var(--c-accent);
  background: color-mix(in srgb, var(--c-accent) 7%, transparent);
}
.est__tally { font-size: var(--t-xs); color: var(--c-muted); }
.est-go { align-self: start; }

.est-out {
  border: 1px solid var(--c-line); border-radius: var(--r-lg); padding: var(--s-4);
  background: var(--c-surface); position: sticky; top: calc(var(--header-h) + var(--s-2));
}
.est-out[hidden] { display: none; }
.est__head h3 { font-size: var(--t-lg); margin-block: 0.3em 0.4em; }
.est__head p { font-size: var(--t-sm); }
.est__figures {
  display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-3);
  margin: var(--s-4) 0; padding-block: var(--s-3);
  border-block: 1px solid var(--c-line);
}
.est__figures dt { font-size: var(--t-xs); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--c-muted); }
/* The estimate is the largest thing in the panel, because it is the thing being
   quoted. Everything provisional is small. */
.est__figures dd { margin: 0.35em 0 0; font-size: var(--t-xl); font-weight: 720; letter-spacing: var(--tracking-tight); font-variant-numeric: tabular-nums; }
.est__plus { font-size: var(--t-sm); font-weight: 500; color: var(--c-muted); letter-spacing: 0; }
.est__list { list-style: none; padding: 0; display: grid; gap: var(--s-2); }
.est__item { display: grid; gap: 0.2em; padding-left: 1em; border-left: 2px solid var(--c-accent); }
.est__item--talk { border-left-style: dashed; border-left-color: var(--c-muted); }
.est__item strong { font-size: var(--t-sm); }
.est__item span { font-size: var(--t-xs); color: var(--c-muted); }
.est__caveat { font-size: var(--t-xs); color: var(--c-muted); margin-top: var(--s-3); }

/* ---- selected work ------------------------------------------------------
   Screenshots on the left, what it is and where to see it on the right.
   The screenshots are the argument: a page selling web work that shows no web
   work is asking to be believed on trust alone, and the two things a busy
   owner will actually do -- skim the pictures and tap a link -- are the two
   things a plain ruled row used to make impossible. */
.work-rows { border-top: 1px solid var(--c-line); }
.work-row {
  display: grid; gap: var(--s-3) var(--s-4);
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  padding-block: var(--s-4); border-bottom: 1px solid var(--c-line); align-items: start;
}
@media (max-width: 760px) { .work-row { grid-template-columns: 1fr; } }
.work-row__shots { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
.work-row__pic { display: block; border: 1px solid var(--c-line); border-radius: 8px; overflow: hidden; }
.work-row__shot {
  display: block; width: 100%; height: auto;
  aspect-ratio: 1200 / 750; object-fit: cover; object-position: top center;
}
.work-row h3 { font-size: var(--t-base); font-weight: 680; letter-spacing: var(--tracking-tight); }
.work-row p { font-size: var(--t-sm); color: var(--c-muted); }
.work-row__link { margin-top: var(--s-2); }
.work-row__score { font-family: var(--font-mono); font-size: var(--t-sm); color: var(--c-muted); white-space: nowrap; }
.work-row__score b { color: var(--c-good); font-weight: 700; }

/* ---- footer ------------------------------------------------------------ */
.footer { border-top: 1px solid var(--c-line); padding-block: var(--s-5) var(--s-6); font-size: var(--t-sm); color: var(--c-muted); }
.footer-grid { display: grid; gap: var(--s-4); grid-template-columns: 1.4fr 1fr 1fr; }
@media (max-width: 760px) { .footer-grid { grid-template-columns: 1fr; } }

/* ---- the demo bar ------------------------------------------------------
   Not decoration. This build is a pitch mock-up, and the whole point is that
   the recipient can feel the design without walking away with a working site,
   so the bar is fixed, unmissable, and says exactly what the page will not do. */
.demobar {
  position: sticky; top: 0; z-index: 90;
  /* Solid colour first as a fallback and so the bar's own contrast is
     measurable by anything walking the background stack. */
  background-color: #1b1206;
  background-image: repeating-linear-gradient(135deg, #1b1206 0 14px, #241806 14px 28px);
  border-bottom: 1px solid #4a3410;
  color: #ffd9a8; font-size: var(--t-xs);
  padding: 0.5rem var(--gutter);
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  justify-content: center; text-align: center;
}
.demobar b { color: #ffb867; }
.demobar .picker { display: flex; gap: 0.3rem; margin-left: auto; }
.demobar button {
  background: #2c1e08; color: #ffd9a8; border: 1px solid #5a3f14;
  border-radius: var(--r-pill); padding: 0.25em 0.7em; font-size: var(--t-xs);
  cursor: pointer; transition: all var(--dur-fast) var(--ease-out);
}
.demobar button[aria-pressed="true"] { background: var(--c-accent); color: var(--c-accent-ink); border-color: var(--c-accent); }
@media (max-width: 620px) { .demobar .picker { margin-left: 0; width: 100%; justify-content: center; } }

/* ===========================================================================
   Editorial kit — added because the mock-up read as generated.
   ===========================================================================
   The failure this fixes is repetition, not decoration. Five sections ran the
   identical sequence — eyebrow, centred h2, centred lede, grid of three rounded
   cards — and a reader who scrolls past the first two stops seeing the third as
   content and starts seeing it as a template. No amount of colour work fixes
   that; the rhythm has to change.

   So the sections below deliberately disagree with each other: one is
   full-bleed and left-ruled, one is an editorial list with hairline rules, one
   is an asymmetric grid with no card chrome at all. A page with three
   different section shapes reads as designed; a page with three of the same
   shape reads as assembled.
   =========================================================================== */

/* ---- section header, three variants ------------------------------------- */
/* v1: the default, but flush LEFT and not over-centred. Centred headings with
   a centred lede underneath are the single loudest generated-page tell. */
.sec-head { display: grid; gap: var(--s-2); max-width: 62ch; }
.sec-head--left { text-align: left; margin-inline: 0; }
.sec-head--wide { max-width: none; }
.sec-head p { text-wrap: pretty; }

/* A hard left rule instead of a floating centred eyebrow. It anchors the
   section to the margin and gives the eye a consistent place to re-enter the
   page after a long image or a tall list. */
.sec-rule {
  border-left: 3px solid var(--c-accent);
  padding-left: var(--s-3);
  display: grid;
  gap: var(--s-2);
}
.sec-rule .eyebrow { color: var(--c-text); }

/* ---- editorial list -----------------------------------------------------
   Hairline-ruled rows instead of cards. Two reasons it beats a card grid for a
   trade: a roofer reads services as a list he can scan for the one job he
   needs, and a list of six services in three columns of boxes makes him
   compare boxes. A ruled list just reads down. */
.ruled { border-top: 1px solid var(--c-line); }
.ruled-row {
  display: grid;
  gap: 0.15rem var(--s-4);
  grid-template-columns: 2.5rem minmax(0, 15ch) minmax(0, 1fr);
  padding-block: var(--s-3);
  border-bottom: 1px solid var(--c-line);
  align-items: baseline;
  transition: background-color var(--dur-fast) linear,
              padding-left var(--dur-base) var(--ease-out);
}
@media (max-width: 720px) {
  .ruled-row { grid-template-columns: 2rem minmax(0, 1fr); }
  .ruled-row__n { display: none; }
}
.ruled-row__n {
  font-family: var(--font-mono);
  font-size: var(--t-xs);
  color: var(--c-accent);
  font-variant-numeric: tabular-nums;
}
.ruled-row__title { font-size: var(--t-lg); font-weight: 680; letter-spacing: var(--tracking-tight); }
.ruled-row__body { color: var(--c-muted); font-size: var(--t-sm); }
.ruled-row:hover {
  background: color-mix(in srgb, var(--c-accent) 5%, transparent);
  padding-left: var(--s-2);
}

/* ---- photo wall ---------------------------------------------------------
   The reason this section exists. A trade site without job photography is the
   most obviously unfinished thing about it, and no amount of typographic
   confidence substitutes for "here is the sink I rebuilt on Tuesday".

   There are no photographs here, and there is a standing temptation to reach
   for stock imagery or an AI-generated bathroom. That would be the worst
   possible move on a pitch page: a plumber who recognises a stock photo in his
   own mock-up has stopped believing the rest of it, and `sample.css` exists
   precisely because invented content is worse than an admitted gap.

   So these are honest empty frames. They say what goes there, they are visibly
   placeholders rather than a trick, and they demonstrate the one thing the
   client actually needs to be shown about the design: that the layout is built
   around their work rather than around decoration. */
.wall { display: grid; gap: var(--s-2); grid-template-columns: repeat(3, 1fr); }
@media (max-width: 640px) { .wall { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 900px) { .wall { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 480px) { .wall { grid-template-columns: 1fr; } }
.wall__frame {
  position: relative;
  aspect-ratio: 4 / 3;
  border: 1px dashed var(--c-line);
  background:
    repeating-linear-gradient(-45deg,
      transparent 0 7px,
      color-mix(in srgb, var(--c-text) 4%, transparent) 7px 9px);
  display: grid;
  place-items: center;
  padding: var(--s-2);
  overflow: hidden;
  transition: border-color var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}
.wall__frame:hover { border-color: var(--c-accent); transform: translateY(-3px); }
/* One frame runs tall, so the wall has a rhythm instead of being a grid of
   identical rectangles — which is the second-most-common generated-page tell
   after the repeated section shape. */
/* Spans two of the three rows. The height is derived from the row rather than
   set to 100%, which is what left a dead gap under the short cells in the first
   version of this wall. */
.wall__frame--tall { grid-row: span 2; aspect-ratio: auto; }
@media (max-width: 640px) { .wall__frame--tall { grid-row: span 2; aspect-ratio: auto; } }
.wall__label {
  font-size: var(--t-xs);
  color: var(--c-muted);
  text-align: center;
  line-height: 1.35;
  letter-spacing: 0.01em;
}
.wall__frame--tall .wall__label { max-width: 18ch; }
.wall__cap {
  font-size: var(--t-xs);
  color: var(--c-muted);
  margin-top: var(--s-3);
  padding-left: var(--s-3);
  border-left: 2px solid var(--c-accent);
}

/* ---- full-bleed statement -----------------------------------------------
   One section per page breaks the wrap and runs edge to edge. Used for the
   single most important line on the page, never for a heading. */
.bleed {
  border-block: 1px solid var(--c-line);
  background: var(--c-surface);
  padding-block: var(--s-7);
  position: relative;
  overflow: hidden;
}
.bleed__inner { max-width: 20ch; }
.bleed__text {
  font-size: var(--t-2xl);
  line-height: 1.02;
  letter-spacing: -0.03em;
  font-weight: 750;
  text-wrap: balance;
}
.bleed__text em { font-style: normal; color: var(--c-accent); }
/* A single oversized mark, cropped off the right edge. Cheap, and it stops the
   section reading as another centred text block. */
.bleed::after {
  content: attr(data-mark);
  position: absolute;
  right: -0.08em;
  bottom: -0.34em;
  font-size: clamp(9rem, 26vw, 22rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.06em;
  color: var(--c-text);
  opacity: 0.035;
  pointer-events: none;
  user-select: none;
}

/* The second line of the headline. It is the only place on the page that gets
   the accent at display size, which is what makes it read as an answer rather
   than as a subtitle. */
.hero__accent {
  display: block;
  color: var(--c-accent);
  margin-top: 0.06em;
}

/* The stat row sits under the hero grid now, so it needs top space and a rule
   to separate it from the fold rather than floating loose. */
.hero .stat-row {
  margin-top: var(--s-6);
  padding-top: var(--s-4);
  border-top: 1px solid var(--c-line);
}

/* The stats band. Once it was a strip under the hero; as a section it needs a
   label's worth of breathing room, and the sample flag that site.js injects
   above it needs somewhere to sit. */
.bleed .stat-row { margin-top: 0; }
.bleed .stat b { font-size: clamp(2.4rem, 1.4rem + 4vw, 4.6rem); }
.bleed .stat { display: grid; gap: 0.3rem; }
.bleed .stat span { font-size: var(--t-xs); }
.bleed .sample-flag { margin-bottom: var(--s-3); }

/* Inside the comparison panes the three-column ruled row is too tight -- the
   titles wrap to three lines in a half-width pane and the layout reads as
   broken rather than dense. Collapsed to number + stacked content. */
.ba-ruled .ruled-row { grid-template-columns: 2rem minmax(0, 1fr); }
.ba-ruled .ruled-row__body { grid-column: 2; }
.ba-ruled .ruled-row__title { font-size: var(--t-base); }
@media (max-width: 720px) {
  .ba-ruled .ruled-row { grid-template-columns: minmax(0, 1fr); }
  .ba-ruled .ruled-row__n { display: none; }
  .ba-ruled .ruled-row__body { grid-column: 1; }
}
