:root{
  --plate: #0b2f38;
  --accent: #0d5c6b;
  --signal: #ff6a1f;
  --signal-ink: #1c0a01;
  --signal-lite: #ff9358;
  --hairline: rgba(255,255,255,.20);
  --muted: rgba(255,255,255,.58);
}

/* ── ForgeLab lead network ───────────────────────────────────────────────────
   The visitor is on a phone, mid-problem, and has been let down by a tradesman
   before. So the design does one job: read as a straight answer, not as
   marketing. The motif is a stamped service plate — the identification plate on
   a geyser, a DB board, a water meter. Hard edges, hairline rules, no radius,
   no drop shadows, nothing that looks like a SaaS card.

   Two typefaces doing two different jobs: mono stamps the metadata — suburb
   labels, service captions, breadcrumbs, the small print of a rating plate —
   and the sans speaks.

   THE PHONE NUMBER IS NOT METADATA. It was set in mono in the first cut and
   that was wrong: mono reads as a serial number, and the number is the single
   thing a panicking person has to recognise and hit in about four seconds. It
   is set in the sans, large and heavy, with tabular figures so the digits still
   line up. Legibility under panic beats the consistency of the conceit.

   Palette per site is prepended at build time from the site JSON, and comes
   from the trade's own marking colour rather than a brand pick. One light
   theme, committed to, every colour painted explicitly — a page read once in a
   panic is no place for a theme toggle.

   Tokens supplied by build.py: --plate --accent --signal --signal-ink
                                --signal-lite --hairline --muted

   --signal is a BACKGROUND (with --signal-ink on it). --signal-lite is the same
   colour opened up enough to be readable as TEXT on the dark plate. They are
   two tokens because one value cannot do both jobs: wefix247's enamel red is
   dark enough to carry white text and far too dark to read on slate.
   ────────────────────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

:root {
  --ink:      #0d1114;
  --ink-2:    #414d55;
  --ink-3:    #616d75;   /* darkened: #6d7a82 measured 4.42:1 on white,
                            under AA for the 12px mono service captions */
  --paper:    #ffffff;
  --wash:     #f1f3f2;
  --rule:     #d9dedc;
  --rule-2:   #b9c2be;
  --wrap:     1060px;
  --sans: "Instrument Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, Consolas, monospace;
}

html {
  -webkit-text-size-adjust: 100%;
  /* This is a light-only design. Saying so stops a browser in OS dark mode
     rendering the native select and text inputs on its own dark chrome, which
     is the one place the page loses control of its colours. */
  color-scheme: light;
  /* Kills the 300ms wait Safari holds every tap for in case it is a double-tap
     zoom. The whole page is a phone number somebody is trying to press. */
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgba(0,0,0,.08);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  padding-bottom: calc(68px + env(safe-area-inset-bottom, 0px));   /* the sticky dock */
}

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 18px; }

/* The header is sticky, so anything linked by id lands under it without this.
   #quote, #claim and the privacy notice's #register are all reached by link. */
:target, [id] { scroll-margin-top: 74px; }

h1, h2, h3 { margin: 0; line-height: 1.1; letter-spacing: -.022em; text-wrap: balance; }
p { margin: 0; }

a { color: var(--accent); text-underline-offset: 2px; }

.skip { position: absolute; left: -9999px; top: 0; z-index: 99;
        background: var(--ink); color: #fff; padding: 12px 18px; }
.skip:focus { left: 0; }
/* The focus ring was --signal, which is a BACKGROUND colour: measured 2.86:1
   on paper for plumbers24 and 1.78:1 for solarpower247's amber, i.e. all but
   invisible to the keyboard user it exists for. It is now a token that flips
   to white on every dark surface, so it clears 3:1 on both grounds. */
:root { --focus: var(--ink); }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
.plate, .hdr, .dock, .partner, .trust, .quote__head { --focus: #ffffff; }

/* Every section heading is stamped: a hairline above, a mono kicker rule.
   One device, used everywhere, so the page reads as one object. */
.h2 {
  font-size: clamp(20px, 2.6vw, 25px); font-weight: 700;
  padding-top: 16px; border-top: 2px solid var(--ink); margin-bottom: 22px;
}

/* ── header ──────────────────────────────────────────────────────────────── */

.hdr { background: var(--plate); color: #fff; position: sticky; top: 0; z-index: 20; }
.hdr__in { display: flex; align-items: stretch; gap: 20px; min-height: 54px; }
.logo {
  display: flex; align-items: center; color: #fff; text-decoration: none;
  font-weight: 700; font-size: 18px; letter-spacing: -.03em; flex: none;
}
.hdr__nav { display: none; gap: 20px; margin-left: auto; align-items: center; }
.hdr__nav a { color: rgba(255,255,255,.76); text-decoration: none; font-size: 14px; font-weight: 600; }
.hdr__nav a:hover { color: #fff; }
.hdr__call {
  margin-left: auto; display: flex; align-items: center; padding: 0 16px;
  background: var(--signal); color: var(--signal-ink); text-decoration: none;
  font-size: 16px; font-weight: 700; white-space: nowrap;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.hdr__nav + .hdr__call { margin-left: 0; }
@media (min-width: 900px) { .hdr__nav { display: flex; } }

/* ── the plate ───────────────────────────────────────────────────────────── */
/* The signature. A stamped identification plate: signal bar, hairline rule,
   mono metadata underneath like a rating label. */

.plate {
  background: var(--plate); color: #fff;
  border-top: 6px solid var(--signal);
  padding: 30px 0 0;
}
.plate__eyebrow {
  font-family: var(--mono); font-size: 12px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--signal-lite);
}
.plate__h1 {
  font-size: clamp(31px, 6.4vw, 52px); font-weight: 700;
  margin-top: 14px; max-width: 16ch; color: #fff;
}
.plate__lede {
  margin-top: 16px; font-size: clamp(16.5px, 2vw, 19px);
  color: rgba(255,255,255,.86); max-width: 52ch;
}
.plate__meta {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  margin: 26px 0 0; padding: 16px 0 22px; border-top: 1px solid var(--hairline);
  gap: 14px;
}
.plate__meta dt {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--muted);
}
.plate__meta dd { margin: 3px 0 0; font-size: 15px; font-weight: 600; color: #fff; }

/* ── breadcrumbs ─────────────────────────────────────────────────────────── */

.crumbs { padding: 14px 0 0; }
.crumbs ol { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0;
             font-family: var(--mono); font-size: 12px; color: var(--ink-3); }
.crumbs li + li::before { content: "/"; margin-right: 8px; color: var(--rule-2); }
.crumbs a { color: var(--ink-2); text-decoration: none; }
.crumbs a:hover { color: var(--accent); }

/* ── the two actions ─────────────────────────────────────────────────────── */
/* Deliberately not buttons. Two plates, side by side, each stating what it is
   in mono above what it does in sans. */

.acts { display: grid; grid-template-columns: 1fr; gap: 0; margin: 22px 0 0;
        border: 2px solid var(--ink); }
@media (min-width: 620px) { .acts { grid-template-columns: 1fr 1fr; } }

.act { display: block; padding: 18px 20px; text-decoration: none; color: var(--ink);
       border-bottom: 2px solid var(--ink); }
.act:last-child { border-bottom: 0; }
@media (min-width: 620px) {
  .act { border-bottom: 0; border-right: 2px solid var(--ink); }
  .act:last-child { border-right: 0; }
}
.act--wa { background: var(--signal); color: var(--signal-ink); }
.act--wa:hover { filter: brightness(.94); }
.act--call { background: var(--paper); }
.act--call:hover { background: var(--wash); }
/* .72 measured 4.25:1 on the signal orange at 11px, just under AA. The label
   still needs to sit back from the number under it, so the step is small. */
.act__k { display: block; font-family: var(--mono); font-size: 11px;
          letter-spacing: .12em; text-transform: uppercase; opacity: .86; }
.act__v { display: block; font-size: 22px; font-weight: 700; letter-spacing: -.02em; margin-top: 6px; }
.act--call .act__v { font-size: 27px; font-weight: 700; letter-spacing: -.025em;
                     font-variant-numeric: tabular-nums; }
/* .78 measured under AA as white on WeFix247's workshop red. The caption still
   needs to sit back from the headline, so the step down is small. */
.act__n { display: block; font-size: 14px; margin-top: 4px; opacity: .92; }

/* ── sections ────────────────────────────────────────────────────────────── */

/* Content sections only. The plate is itself a <section> in <main>, so a bare
   `main section` rule puts 46px of white between the header and the plate and
   breaks the top of every page. Scoped to .wrap's children, which the plate is
   not (it CONTAINS a .wrap rather than sitting in one). */
.wrap > section { margin-top: 46px; }
.acts + section { margin-top: 46px; }

/* The table-era steps rules lived here and were removed when the steps became
   cards: `.steps__list li` forced a 54px + 1fr grid onto every card, which put
   the icon and the number in the first column and crushed the body copy into a
   one-word-wide second one. The card styles further down are the only ones. */

.svcs__list { border-top: 1px solid var(--rule); }
.svc {
  display: grid; grid-template-columns: 1fr; gap: 2px; padding: 16px 0;
  border-bottom: 1px solid var(--rule); text-decoration: none; color: var(--ink);
}
@media (min-width: 720px) {
  .svc { grid-template-columns: 15rem 1fr auto; gap: 24px; align-items: baseline; }
}
.svc:hover { background: var(--wash); }
.svc__name { font-weight: 700; font-size: 17px; }
.svc__card { color: var(--ink-2); font-size: 15.5px; }
.svc__from { font-family: var(--mono); font-size: 12px; color: var(--ink-3);
             white-space: nowrap; }
.svc:hover .svc__name { color: var(--accent); }

.local p, .detail .prose p { color: var(--ink-2); max-width: 66ch; font-size: 16.5px; }
.detail .prose p + p { margin-top: 13px; }

.trust { background: var(--ink); color: #fff; padding: 26px 22px; }
.trust__list { list-style: none; margin: 0; padding: 0; display: grid;
               grid-template-columns: 1fr 1fr; gap: 22px; }
@media (min-width: 760px) { .trust__list { grid-template-columns: repeat(4, 1fr); } }
.trust__list b { display: block; font-size: 21px; font-weight: 700; letter-spacing: -.02em; }
.trust__list span { display: block; font-size: 13.5px; color: rgba(255,255,255,.66);
                    margin-top: 4px; line-height: 1.45; }
.trust__note { margin-top: 22px; padding-top: 18px; border-top: 1px solid rgba(255,255,255,.16);
               font-size: 14px; color: rgba(255,255,255,.7); max-width: 64ch; }

.areas__list { display: flex; flex-wrap: wrap; gap: 0; border-top: 1px solid var(--rule);
               border-left: 1px solid var(--rule); }
.areas__list a {
  flex: 1 1 auto; min-width: 8.5rem; padding: 12px 14px; text-decoration: none;
  color: var(--ink); font-size: 14.5px; font-weight: 600;
  border-right: 1px solid var(--rule); border-bottom: 1px solid var(--rule);
}
.areas__list a:hover { background: var(--signal); color: var(--signal-ink); }

/* ── form ────────────────────────────────────────────────────────────────── */

.quote { border: 2px solid var(--ink); }
.quote__head { background: var(--ink); color: #fff; padding: 22px; }
.quote__head .h2 { border-top: 0; padding-top: 0; margin-bottom: 8px; color: #fff; }
.quote__head p { color: rgba(255,255,255,.74); font-size: 15.5px; max-width: 56ch; }
#leadform { display: grid; grid-template-columns: 1fr; gap: 16px; padding: 22px; }
@media (min-width: 620px) { #leadform { grid-template-columns: 1fr 1fr; } }
.f { display: grid; gap: 6px; }
.f--wide { grid-column: 1 / -1; }
.f label { font-family: var(--mono); font-size: 11px; letter-spacing: .1em;
           text-transform: uppercase; color: var(--ink-2); }
.opt { text-transform: none; letter-spacing: 0; color: var(--ink-3); }
.f input, .f select, .f textarea {
  font: inherit; font-size: 16px; padding: 12px 13px;
  border: 1px solid var(--rule-2); background: var(--paper); color: var(--ink);
  width: 100%; border-radius: 0;
}
.f textarea { resize: vertical; }
.f input:focus, .f select:focus, .f textarea:focus { border-color: var(--ink); }
.f input[aria-invalid="true"] { border-color: #b3261e; border-width: 2px; }
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.nojs { grid-column: 1 / -1; background: var(--signal); color: var(--signal-ink);
         padding: 13px 15px; font-size: 14.5px; font-weight: 600; }

.consent { grid-column: 1 / -1; font-size: 13.5px; color: var(--ink-2);
           border-left: 3px solid var(--signal); padding-left: 13px; max-width: 62ch; }

.btn {
  grid-column: 1 / -1; display: block; width: 100%;
  background: var(--signal); color: var(--signal-ink); border: 0;
  font: inherit; font-weight: 700; font-size: 17px; padding: 16px; cursor: pointer;
}
.btn:hover { filter: brightness(.94); }
.btn[disabled] { opacity: .55; cursor: default; }
.formnote { grid-column: 1 / -1; font-size: 15px; font-weight: 600;
            min-height: 1.4em; color: var(--accent); }
.formnote[data-bad="1"] { color: #b3261e; }

/* ── faq ─────────────────────────────────────────────────────────────────── */

.faq__i { border-bottom: 1px solid var(--rule); }
.faq__i:first-of-type { border-top: 1px solid var(--rule); }
.faq__i summary {
  cursor: pointer; padding: 15px 0; font-weight: 600; font-size: 16.5px;
  list-style: none; display: flex; gap: 14px; align-items: baseline;
}
.faq__i summary::-webkit-details-marker { display: none; }
.faq__i summary::before {
  content: "+"; font-family: var(--mono); color: var(--signal-ink);
  background: var(--signal); width: 22px; height: 22px; display: grid;
  place-items: center; flex: none; font-size: 14px;
}
.faq__i[open] summary::before { content: "\2212"; }
.faq__i div { padding: 0 0 18px 36px; }
.faq__i p { color: var(--ink-2); max-width: 64ch; }

/* ── prose (legal pages) ─────────────────────────────────────────────────── */

.prose { max-width: 68ch; }
.prose__lead { font-size: 18px; color: var(--ink); }
.prose h2 { font-size: 20px; font-weight: 700; margin-top: 34px;
            padding-top: 14px; border-top: 2px solid var(--ink); }
.prose p { color: var(--ink-2); margin-top: 12px; }
.prose strong { color: var(--ink); }

/* ── footer + dock ───────────────────────────────────────────────────────── */

.ftr { margin-top: 60px; background: var(--plate); color: #fff; padding: 30px 0 34px; }
.ftr__top { display: flex; flex-wrap: wrap; gap: 14px 26px; align-items: baseline;
            padding-bottom: 18px; border-bottom: 1px solid var(--hairline); }
.ftr__brand { font-weight: 700; font-size: 18px; letter-spacing: -.03em; }
.ftr__nav { display: flex; flex-wrap: wrap; gap: 20px; margin-left: auto; }
.ftr__nav a { color: rgba(255,255,255,.82); font-size: 14.5px; }
.ftr__legal { margin-top: 18px; font-size: 13.5px; color: rgba(255,255,255,.62);
              max-width: 74ch; line-height: 1.6; }
.ftr__meta { margin-top: 14px; font-family: var(--mono); font-size: 12px;
             color: rgba(255,255,255,.5); }

.dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
        display: grid; grid-template-columns: 1fr 1fr; border-top: 2px solid var(--ink); }
/* The home indicator sits over the bottom ~34px on a modern iPhone, which was
   eating part of the two controls the whole site funnels into. */
.dock__a { padding: 16px 8px calc(16px + env(safe-area-inset-bottom, 0px));
           text-align: center; text-decoration: none;
           font-weight: 700; font-size: 15.5px; }
.dock__a--wa { background: var(--signal); color: var(--signal-ink); }
.dock__a--call { background: var(--plate); color: #fff; font-weight: 700;
                 font-size: 16.5px; font-variant-numeric: tabular-nums; }
@media (min-width: 900px) { .dock { display: none; } body { padding-bottom: 0; } }

@media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } }

/* ── vetting, pricing, hub ───────────────────────────────────────────────────
   Added after benchmarking the marketplaces. The single cheapest trust element
   any of them has is NAMING the checks instead of asserting a grade, and it
   needs no review corpus to be true. */

.vet__list { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--rule); }
.vet__list li { display: grid; grid-template-columns: 1fr; gap: 3px;
                padding: 15px 0; border-bottom: 1px solid var(--rule); }
@media (min-width: 720px) {
  .vet__list li { grid-template-columns: 17rem 1fr; gap: 24px; align-items: baseline; }
}
.vet__list b { font-weight: 700; font-size: 16.5px; }
.vet__list b::before { content: "\2713"; color: var(--accent); margin-right: 9px; font-weight: 700; }
.vet__list span { color: var(--ink-2); font-size: 15.5px; }
.vet__note { margin-top: 16px; font-size: 14.5px; color: var(--ink-3); max-width: 60ch; }

.tablewrap { overflow-x: auto; }
.prices__t { border-collapse: collapse; width: 100%; min-width: 320px; }
.prices__t th { text-align: left; font-family: var(--mono); font-size: 10.5px;
                letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3);
                padding: 0 14px 10px 0; border-bottom: 2px solid var(--ink); }
.prices__t td { padding: 12px 14px 12px 0; border-bottom: 1px solid var(--rule);
                font-size: 16px; }
.prices__t td:last-child { font-family: var(--mono); font-size: 14.5px;
                           white-space: nowrap; font-variant-numeric: tabular-nums; }
.prices__note { margin-top: 16px; font-size: 14px; color: var(--ink-3); max-width: 62ch; }

.areas__hub { display: inline-block; margin-top: 16px; font-weight: 600;
              font-size: 15.5px; text-decoration: none; color: var(--accent); }
.areas__hub:hover { text-decoration: underline; }

/* ── a 3px radius, on things you tap and nothing else ────────────────────────
   The plate stays hard-edged; that is the identity. But the design critique was
   right that unrelieved sharp corners read as "industrial supplier" to somebody
   who is not a designer, and this visitor is a homeowner standing in a puddle,
   not a specifier. Radius here is an affordance — it marks what is tappable —
   rather than decoration, which is why it is on controls only. */
.act, .btn, .hdr__call, .dock__a, .areas__list a,
.f input, .f select, .f textarea { border-radius: 3px; }
.acts { border-radius: 4px; overflow: hidden; }
.quote { border-radius: 4px; overflow: hidden; }

/* ── the trade register ──────────────────────────────────────────────────────
   These tables carry other people's businesses, so they are styled as a
   *record* rather than as cards: a register extract, set the way the plate
   sets facts. Company names in the sans because they are names; everything
   measured — phone numbers, counts — in the mono, same rule as the rest of
   the site.

   Deliberately not cards. A grid of rounded tiles with logos is what every
   directory does, and it reads as "these are our partners", which would be a
   lie on a page listing 264 companies we have never spoken to. */

.reg__lede { margin: 0 0 20px; max-width: 66ch; color: var(--ink-2);
             font-size: 15.5px; }
.reg__t { border-collapse: collapse; width: 100%; min-width: 300px; }
.reg__t th[scope="col"] { text-align: left; font-family: var(--mono);
              font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase;
              color: var(--ink-3); padding: 0 14px 10px 0;
              border-bottom: 2px solid var(--ink); font-weight: 500; }
.reg__t td, .reg__t th[scope="row"] { padding: 12px 14px 12px 0; text-align: left;
              border-bottom: 1px solid var(--rule); font-size: 15.5px;
              font-weight: 400; vertical-align: baseline; }
.reg__t th[scope="row"] { font-weight: 600; padding-right: 20px; }
.reg__t th[scope="row"] a { color: var(--ink); text-decoration: none;
              text-decoration-skip-ink: auto; }
.reg__t th[scope="row"] a:hover { text-decoration: underline; }
/* An outbound link to somebody else's register entry is marked, so it is
   obvious before the tap that it leaves the site. */
.reg__t th[scope="row"] a[target="_blank"]::after {
  content: "\2197"; font-size: .8em; color: var(--ink-3); margin-left: 5px; }
.reg__t td:last-child { font-family: var(--mono); font-size: 14px;
              white-space: nowrap; font-variant-numeric: tabular-nums; }
.reg__tel { color: var(--accent); text-decoration: none; }
.reg__tel:hover { text-decoration: underline; }
.reg__all { display: inline-block; margin-top: 16px; font-weight: 600;
            font-size: 15.5px; text-decoration: none; color: var(--accent); }
.reg__all:hover { text-decoration: underline; }

.reg__area { margin: 30px 0 10px; font-size: 17px; font-weight: 700;
             display: flex; align-items: baseline; gap: 10px; }
.reg__area span { font-family: var(--mono); font-size: 12px; color: var(--ink-3);
                  font-weight: 500; }
.reg--full .tablewrap + .reg__area { margin-top: 38px; }

/* ── one company's page ──────────────────────────────────────────────────── */

.listing__dl { display: grid; gap: 0; margin: 0; border-top: 1px solid var(--rule); }
.listing__dl > div { display: grid; grid-template-columns: 1fr; gap: 2px;
                     padding: 13px 0; border-bottom: 1px solid var(--rule); }
@media (min-width: 620px) {
  .listing__dl > div { grid-template-columns: 12rem 1fr; gap: 20px;
                       align-items: baseline; }
}
.listing__dl dt { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em;
                  text-transform: uppercase; color: var(--ink-3); }
.listing__dl dd { margin: 0; font-size: 16px; }
.listing__dl dd a { color: var(--accent); }

/* Provenance line. Small, always present, never a link we dress up — the point
   is that anybody can go and check the claim at its source. */
.src { margin-top: 14px; font-size: 13px; color: var(--ink-3); }
.src a { color: var(--ink-3); }

.chips { list-style: none; display: flex; flex-wrap: wrap; gap: 8px;
         margin: 0; padding: 0; }
.chips li { font-family: var(--mono); font-size: 12.5px; padding: 6px 10px;
            border: 1px solid var(--rule-2); border-radius: 3px; color: var(--ink-2); }

.vet__list--reg b::before { content: "\2713"; }

/* ── callouts ────────────────────────────────────────────────────────────────
   Used for the three things on a register page that are not the register: what
   it is not, how to get off it, and what we actually offer. Ruled box, no
   fill, because a tinted panel would read as promotion and two of the three
   are the opposite of that. */

.callout { border: 1px solid var(--rule-2); padding: 22px; margin-top: 34px; }
.callout .h2 { margin-top: 0; border: 0; padding-top: 0; font-size: 19px; }
.callout p { max-width: 68ch; font-size: 15.5px; color: var(--ink-2); margin: 0 0 12px; }
.callout p:last-child { margin-bottom: 0; }
.callout--act { border-color: var(--ink); border-left-width: 4px; }
.callout__acts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }
.callout__acts .btn { grid-column: auto; display: inline-block; width: auto;
                      padding: 12px 18px; font-size: 15.5px; text-decoration: none;
                      text-align: center; }
.btn--ghost { background: transparent; color: var(--ink);
              border: 1px solid var(--rule-2); }
.btn--ghost:hover { background: var(--paper); filter: none;
                    border-color: var(--ink); }

.prose--wide p { max-width: 72ch; }

/* On the dark plate, an inline link needs the opened-up signal to clear AA;
   --accent is tuned for the white page below it and measures badly here. */
.plate__meta a { color: var(--signal-lite); }
.plate__meta a:hover { text-decoration: none; }

/* ── paid position, always visibly paid ──────────────────────────────────────
   A promoted row in something presented as a public register has to be marked,
   or the register is worth nothing to the reader and therefore worth nothing to
   the trades paying for it. The mark is small but it is never subtle: mono,
   uppercase, on the signal colour, sitting against the company name rather than
   tucked in a corner. */

.reg__mark { display: inline-block; margin-left: 9px; vertical-align: 2px;
             font-family: var(--mono); font-size: 9.5px; letter-spacing: .1em;
             text-transform: uppercase; font-weight: 500; padding: 3px 6px;
             border: 1px solid var(--rule-2); color: var(--ink-3);
             border-radius: 2px; white-space: nowrap; }
.reg__mark--x { background: var(--signal); color: var(--signal-ink);
                border-color: transparent; }
.reg__disc { margin: 14px 0 0; font-size: 13.5px; color: var(--ink-3);
             max-width: 62ch; }

/* ── the area partner ────────────────────────────────────────────────────────
   Renders only when somebody has actually signed. Set on the dark plate so it
   reads as part of the site's own structure rather than as an advert, because
   it is not an advert: it is the answer to "who is going to phone me". */

.partner { background: var(--plate); color: #fff; padding: 24px;
           border-radius: 4px; margin-top: 30px; }
.partner__k { margin: 0; font-family: var(--mono); font-size: 10.5px;
              letter-spacing: .12em; text-transform: uppercase;
              color: var(--signal-lite); }
.partner__name { margin: 6px 0 0; font-size: clamp(24px, 4vw, 32px);
                 font-weight: 700; letter-spacing: -.01em; }
.partner__why { margin: 12px 0 0; max-width: 60ch; font-size: 15.5px;
                color: var(--muted); }
.partner__acts { display: flex; flex-wrap: wrap; align-items: center; gap: 18px;
                 margin: 18px 0 0; }
.partner__tel { font-family: var(--mono); font-size: 20px; font-weight: 500;
                color: #fff; text-decoration: none;
                font-variant-numeric: tabular-nums; }
.partner__tel:hover { color: var(--signal-lite); }
.partner__more { color: var(--signal-lite); font-size: 14.5px;
                 text-decoration: none; font-weight: 600; }
.partner__more:hover { text-decoration: underline; }

/* ── the tier table on the trade page ───────────────────────────────────────
   Three columns, and the free one is first on purpose. A trade reading this has
   been cold-called three times this month; leading with "you are already on
   here for nothing" is the only opening that does not sound like the other
   three. */

.tiers__grid { display: grid; gap: 16px; grid-template-columns: 1fr;
               margin-top: 4px; }
@media (min-width: 860px) { .tiers__grid { grid-template-columns: repeat(3, 1fr); } }
.tier { border: 1px solid var(--rule-2); padding: 20px; display: flex;
        flex-direction: column; }
.tier--pick { border-color: var(--ink); border-top: 4px solid var(--signal); }
.tier__k { margin: 0; font-family: var(--mono); font-size: 10.5px;
           letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.tier__price { margin: 8px 0 0; font-size: 26px; font-weight: 700;
               letter-spacing: -.02em; }
.tier__for { margin: 8px 0 14px; font-size: 15px; color: var(--ink-2);
             padding-bottom: 14px; border-bottom: 1px solid var(--rule); }
.tier__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.tier__list li { font-size: 14.5px; color: var(--ink-2); padding-left: 19px;
                 position: relative; }
.tier__list li::before { content: "\2713"; position: absolute; left: 0;
                         color: var(--accent); font-weight: 700; }
.tiers__note { margin-top: 18px; font-size: 14.5px; color: var(--ink-3);
               max-width: 66ch; }

/* ── filtering the full register ────────────────────────────────────────────
   264 rows is a lot to scroll on a phone. The field is progressive: it is
   written in by app.js, so with JavaScript off the table is simply all there,
   which is the correct fallback for a page whose whole job is being complete. */

.regfilter { margin: 0 0 18px; }
.regfilter input { width: 100%; max-width: 26rem; font: inherit; font-size: 16px;
                   padding: 11px 13px; border: 1px solid var(--rule-2);
                   border-radius: 3px; background: var(--paper); color: var(--ink); }
.regfilter input:focus-visible { border-color: var(--ink); }
.regfilter__n { display: block; margin-top: 8px; font-family: var(--mono);
                font-size: 12px; color: var(--ink-3); }

/* The native select was the one control still wearing the browser's own
   styling, which read as "form" rather than as part of the plate. */
.f select { appearance: none; background-color: var(--paper); color: var(--ink);
            background-image:
   url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath fill='%23616d75' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");
   background-repeat: no-repeat; background-position: right 14px center;
   padding-right: 40px; }

/* ── the plate becomes a plate ───────────────────────────────────────────────
   On a wide screen the hero was a headline capped at 16ch with the entire right
   half of a very dark band left empty, and the spec strip lying flat underneath
   it. That reads as an unfinished template rather than as a decision.

   The fix is the motif the whole site is named after. A real service plate has
   the title on the left and the ratings stamped in a column beside it, so the
   same elements are simply re-laid: text left, the spec list right, a hairline
   between them. No new content, nothing invented, and the measure on the
   headline stays exactly where it was — it just no longer sits in a void.

   Below 900px it collapses back to the original stacked strip, which was
   already right for a phone. */

@media (min-width: 900px) {
  .plate .wrap {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(260px, .9fr);
    column-gap: 52px;
    align-items: start;
  }
  .plate__eyebrow { grid-column: 1; grid-row: 1; }
  .plate__h1      { grid-column: 1; grid-row: 2; }
  .plate__lede    { grid-column: 1; grid-row: 3; }
  .plate__meta {
    grid-column: 2; grid-row: 1 / 4;
    /* Distributed down the column rather than stacked at the top, so the
       hairline has rows against it for its whole length. A rating plate is
       spaced like this; a list of three things pushed to the top is not. */
    display: flex; flex-direction: column; justify-content: space-between;
    gap: 18px;
    margin: 4px 0 0; padding: 0 0 30px 30px;
    border-top: 0; border-left: 1px solid var(--hairline);
    align-self: stretch;
  }
  .plate__meta dd { font-size: 16px; }
  /* The strip used to close the plate off. With it moved, the text column
     needs its own bottom air. */
  .plate__lede { padding-bottom: 30px; }
}

/* One more measure fix: the lede was capped at 52ch and the headline at 16ch,
   so on a wide plate the two ragged edges disagreed. 44ch tracks the headline. */
@media (min-width: 1100px) { .plate__lede { max-width: 44ch; } }

/* The full register is 264 rows in twenty-odd tables. content-visibility lets
   the browser skip laying out the ones that are off screen, and the intrinsic
   size keeps the scrollbar honest so it does not jump while you scroll. Only
   on the full register: the six-row block on a suburb page is not worth it. */
.reg--full .tablewrap {
  content-visibility: auto;
  contain-intrinsic-size: auto 600px;
}

/* ── tap targets ─────────────────────────────────────────────────────────────
   Measured at 360px: the phone number in a register row was a 17px-tall target,
   which is the single most important tap on that page and smaller than a
   fingertip. WCAG 2.5.8 asks 24px; a phone number on a trade site should be
   comfortably past that. Padding rather than font-size, so the table keeps its
   density and the row height barely moves.

   Inline links inside a paragraph are left alone: the same guideline exempts
   them, and padding text mid-sentence looks broken. */

.reg__tel { display: inline-block; padding: 12px 0; margin: -12px 0; }
.reg__all, .areas__hub, .partner__more, .src a {
  padding: 10px 0; margin: -10px 0; display: inline-block;
}
.reg__all, .areas__hub { margin-top: 6px; }

/* Footer and breadcrumb links sit in dense navs where 44px each would double
   the block. 32px is the compromise, and they are secondary by definition. */
.ftr__nav a, .crumbs a { display: inline-block; padding: 6px 0; }

/* At 360px the phone number was being pushed past the edge of the table and
   into its horizontal scroller, which is a poor place for the primary action.
   On a suburb page every row already says the same town, so the Listed in
   column is the one that can go. Dropped by class, never by nth-child: the
   columns differ per register and on a two-column table nth-child(2) is the
   phone. */
@media (max-width: 560px) {
  .reg__c-area { display: none; }
}

/* ── the coverage map ────────────────────────────────────────────────────────
   Every dot is a suburb page, positioned by its real latitude and longitude, so
   what you get is the actual shape of Johannesburg rather than an illustration
   of it. Drawn on the plate because it is a diagram, not a photograph, and the
   dark ground is where the site's own colour reads as data. */

.jmap { margin-top: 40px; }
.jmap__lede { margin: 0 0 20px; max-width: 66ch; color: var(--ink-2);
              font-size: 15.5px; }
.jmap__frame { background: var(--plate); padding: 20px; border-radius: 4px;
               overflow: hidden; }
.jmap__frame svg { display: block; width: 100%; height: auto; }
.jmap__pin circle { fill: var(--signal-lite); opacity: .5;
                    transition: opacity .12s ease, r .12s ease; }
.jmap__pin:hover circle, .jmap__pin:focus-visible circle { opacity: 1; r: 12; }
.jmap__pin:focus-visible { outline: none; }
.jmap__pin:focus-visible circle { stroke: #fff; stroke-width: 3; }
.jmap__pin.is-near circle { fill: #fff; opacity: 1; r: 14; }
.jmap__credit { margin-top: 12px; font-size: 12.5px; color: var(--ink-3); }
.jmap__credit a { color: var(--ink-3); }

/* The dots are 7px at a 1000-unit viewBox, which on a phone is a target far
   under any sane minimum. The picker below the map is the real control on a
   small screen; the map stays as the picture. */
@media (max-width: 700px) { .jmap__pin circle { r: 10; } }

/* ── find my area ────────────────────────────────────────────────────────────
   A button that reads a position the page never sends anywhere, and a plain
   suburb field beside it that does the same job with the keyboard, with
   JavaScript off, or when somebody says no to the permission prompt. Both are
   present at once rather than one replacing the other. */

.finder { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 14px 18px;
          padding: 18px; border: 1px solid var(--rule-2); border-radius: 4px;
          margin-bottom: 20px; }
.btn--find { grid-column: auto; display: inline-flex; align-items: center;
             gap: 9px; width: auto; padding: 13px 18px; font-size: 16px; }
.btn--find::before { content: "◎"; font-size: 17px; line-height: 1; }
.finder__pick { display: flex; flex-direction: column; gap: 5px; flex: 1 1 15rem; }
.finder__pick span { font-family: var(--mono); font-size: 10.5px;
                     letter-spacing: .12em; text-transform: uppercase;
                     color: var(--ink-3); }
.finder__pick input { font: inherit; font-size: 16px; padding: 12px 13px;
                      border: 1px solid var(--rule-2); border-radius: 3px;
                      background: var(--paper); color: var(--ink); }
.finder__pick input:focus-visible { border-color: var(--ink); }
.finder__out { flex: 1 1 100%; margin: 0; font-size: 15.5px; min-height: 1.4em; }
.finder__out a { font-weight: 700; }
.finder__km { font-family: var(--mono); font-size: 13px; color: var(--ink-3);
              margin-left: 10px; }

.jmap__label { fill: rgba(255,255,255,.82); font-family: var(--mono);
               font-size: 21px; letter-spacing: .01em; dominant-baseline: middle;
               paint-order: stroke; stroke: var(--plate); stroke-width: 5px; }

/* ── where a suburb is ───────────────────────────────────────────────────────
   The 250 suburbs without a hand-written note get measured facts instead of
   invented local colour: which part of the city, how far from the centre, what
   it sits between, how much of the register is nearby. Set as a spec block on
   purpose. Two hundred and fifty generated paragraphs differing by two nouns
   and a number would read as generated; a stamped list of measurements reads
   as what it is. */

.facts__dl { display: grid; gap: 0; margin: 0; border-top: 1px solid var(--rule); }
.facts__dl > div { display: grid; grid-template-columns: 1fr; gap: 3px;
                   padding: 13px 0; border-bottom: 1px solid var(--rule); }
@media (min-width: 620px) {
  .facts__dl > div { grid-template-columns: 11rem 1fr; gap: 20px;
                     align-items: baseline; }
}
.facts__dl dt { font-family: var(--mono); font-size: 10.5px; letter-spacing: .12em;
                text-transform: uppercase; color: var(--ink-3); }
.facts__dl dd { margin: 0; font-size: 16px; }
.facts__dl dd a { color: var(--accent); text-decoration: none; }
.facts__dl dd a:hover { text-decoration: underline; }

/* ── what decides the price ──────────────────────────────────────────────────
   The price table stays empty until the trade partner gives real numbers. This
   is the half that does not need them, and it is arguably the more useful half:
   what moves the figure, and the questions that make two quotes comparable.

   The questions sit in a bordered aside rather than in the table, because they
   are the part somebody screenshots and reads back to a tradesman on the
   phone. Numbered, so they can be worked through. */

.cost__lede { margin: 0 0 20px; max-width: 66ch; color: var(--ink-2);
              font-size: 15.5px; }
.cost__t { border-collapse: collapse; width: 100%; }
.cost__t th[scope="row"] { text-align: left; font-weight: 700; font-size: 16px;
              padding: 15px 24px 15px 0; border-bottom: 1px solid var(--rule);
              vertical-align: baseline; width: 1%; white-space: nowrap; }
.cost__t td { padding: 15px 0; border-bottom: 1px solid var(--rule);
              font-size: 15.5px; color: var(--ink-2); vertical-align: baseline; }
@media (max-width: 640px) {
  .cost__t, .cost__t tbody, .cost__t tr, .cost__t th, .cost__t td { display: block; }
  .cost__t th[scope="row"] { border: 0; padding: 16px 0 2px; white-space: normal;
                             width: auto; }
  .cost__t td { padding-top: 0; }
}

.cost__ask { margin-top: 26px; padding: 22px; border: 1px solid var(--rule-2);
             border-left: 4px solid var(--signal); }
.cost__askh { margin: 0 0 14px; font-size: 17px; font-weight: 700; }
.cost__asks { margin: 0; padding-left: 1.35em; display: grid; gap: 10px; }
.cost__asks li { font-size: 15.5px; color: var(--ink-2); padding-left: 4px; }
.cost__asks li::marker { font-family: var(--mono); font-size: 13px;
                         color: var(--ink-3); }

/* ── who to call, first thing ────────────────────────────────────────────────
   Somebody landing on a suburb page has a problem right now. Everything else on
   the page is true and none of it is what they came for in the first ten
   seconds. So: names, distance, and a button that dials, above everything that
   explains anything.

   Cards rather than table rows, because the only thing that matters here is
   that the number is a big target under a thumb. The register table lower down
   was removed from these pages — it was the same rows twice. */

.pick { margin-top: 30px; }
.pick__head { margin-bottom: 18px; }
.pick__lede { margin: 10px 0 0; max-width: 64ch; font-size: 15px;
              color: var(--ink-2); }
.pick__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px;
              grid-template-columns: 1fr; }
@media (min-width: 700px)  { .pick__list { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .pick__list { grid-template-columns: repeat(3, 1fr); } }

.pick__c { border: 1px solid var(--rule-2); border-radius: 4px; padding: 16px;
           display: flex; flex-direction: column; gap: 6px; background: var(--paper); }
/* The paying trade, and it says so on the card rather than just sitting first. */
.pick__c--p { border-color: var(--ink); border-top: 4px solid var(--signal); }
.pick__where { margin: 0; font-family: var(--mono); font-size: 11px;
               letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); }
.pick__name { margin: 0; font-size: 18px; font-weight: 700; line-height: 1.25; }
.pick__tag { align-self: flex-start; font-family: var(--mono); font-size: 10px;
             letter-spacing: .08em; text-transform: uppercase; padding: 4px 7px;
             border: 1px solid var(--rule-2); border-radius: 2px; color: var(--ink-3); }
.pick__tag--p { background: var(--signal); color: var(--signal-ink);
                border-color: transparent; }
/* Outlined, not filled. Five solid dark slabs under the site's own call block
   turned the top of every suburb page into a phone directory and out-shouted
   the one filled button that is ours. Still a full-width 48px target. */
.pick__call { margin-top: auto; display: flex; align-items: baseline; gap: 10px;
              background: var(--paper); color: var(--ink); text-decoration: none;
              border: 1.5px solid var(--ink); padding: 12px 14px; border-radius: 3px; }
.pick__call span { font-family: var(--mono); font-size: 11px; letter-spacing: .1em;
                   text-transform: uppercase; color: var(--ink-2); }
.pick__call b { font-size: 19px; font-weight: 700;
                font-variant-numeric: tabular-nums; }
.pick__call:hover { background: var(--plate); color: #fff; border-color: var(--plate); }
.pick__call:hover span { color: inherit; }
/* An odd card out on the two-column grid spans the row instead of sitting
   alone under a gap. */
@media (min-width: 700px) and (max-width: 1039px) {
  .pick__c:last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.pick__c--p .pick__call { background: var(--signal); color: var(--signal-ink); }
.pick__c--p .pick__call span { opacity: .8; }
.pick__more { font-size: 13.5px; color: var(--accent); text-decoration: none; }
.pick__more:hover { text-decoration: underline; }

/* ── the suburb map ──────────────────────────────────────────────────────────
   Real coordinates, ~2KB of inline SVG, and it is what makes "4 km away" mean
   something at a glance. Lines back to the suburb so it reads as distance
   rather than as scattered confetti. */

.smap { margin: 18px 0 0; }
.smap__box { background: var(--plate); border-radius: 4px; padding: 14px; }
/* Johannesburg is taller than it is wide, so at full width the locator was
   1349px of mostly empty plate. Fixed box, SVG letterboxed inside it. */
.smap svg { display: block; width: 100%; height: auto; max-height: 400px; }
.smap figcaption { margin-top: 10px; font-size: 13.5px; color: var(--ink-3);
                   max-width: 64ch; }
.smap__all circle { fill: var(--signal-lite); opacity: .5; }
.smap__ring { fill: none; stroke: #fff; stroke-width: 3; }
.smap__here { fill: var(--signal); }
.smap__label { fill: #fff; font-family: var(--mono); font-size: 24px;
               paint-order: stroke; stroke: var(--plate); stroke-width: 6px; }
.smap figcaption a { color: var(--accent); }

/* When the call leads, it takes the signal colour and the WhatsApp block drops
   back to the paper card. The two swap roles rather than both shouting. */
.acts--call .act--call { background: var(--signal); color: var(--signal-ink); }
.acts--call .act--call:hover { filter: brightness(.94); }
.acts--call .act--wa { background: var(--paper); color: var(--ink); }
.acts--call .act--wa:hover { background: var(--wash); filter: none; }

/* ── photographs ─────────────────────────────────────────────────────────────
   Empty until there are real ones. See build.photo_strip for why there is no
   stock here and where the real ones are meant to come from. Sized and lazy so
   that adding them later cannot cost the page its load time or shift its
   layout. */

.shots__g { display: grid; gap: 14px; grid-template-columns: 1fr; }
@media (min-width: 680px) { .shots__g { grid-template-columns: repeat(2, 1fr); } }
.shots__f { margin: 0; }
.shots__f img { display: block; width: 100%; height: auto; border-radius: 4px;
                background: var(--wash); }
.shots__f figcaption { margin-top: 8px; font-size: 13.5px; color: var(--ink-2); }
.shots__c { display: block; margin-top: 3px; font-size: 12px; color: var(--ink-3); }

.smap__label--n { fill: rgba(255,255,255,.72); font-family: var(--mono);
                  font-size: 19px; paint-order: stroke; stroke: var(--plate);
                  stroke-width: 5px; }

/* ── cards, not tables ───────────────────────────────────────────────────────
   The suburb page read as a document because five sections in a row had the
   same shape: a heavy rule, a heading, hairline rows of text. Steps, services
   and vetting are now cards with an icon each, which is the rhythm every trade
   site that works actually has. The price and area-facts blocks stay as rows,
   because those genuinely are reference tables, and now they are the only
   ones. */

.ico, .step__i, .svc__i, .vetc__i {
  width: 28px; height: 28px; flex: none; fill: none; stroke: currentColor;
  stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
}

/* steps */
.steps__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px;
               grid-template-columns: 1fr; border: 0; }
@media (min-width: 760px) { .steps__list { grid-template-columns: repeat(3, 1fr); } }
.step { position: relative; padding: 20px; border: 1px solid var(--rule-2);
        border-radius: 4px; background: var(--paper); }
.step__i { color: var(--accent); width: 32px; height: 32px; }
.step__n { position: absolute; top: 18px; right: 18px; font-family: var(--mono);
           font-size: 12px; color: var(--ink-3); background: none; width: auto;
           height: auto; display: block; }
.step__t { margin: 12px 0 6px; font-size: 17px; font-weight: 700; }
.step__b { margin: 0; font-size: 15px; color: var(--ink-2); }

/* services */
.svcs__grid { display: grid; gap: 12px; grid-template-columns: 1fr; }
@media (min-width: 560px) { .svcs__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 980px) { .svcs__grid { grid-template-columns: repeat(3, 1fr); } }
.svcs__grid .svc { display: flex; flex-direction: column; gap: 6px;
                   padding: 18px; border: 1px solid var(--rule-2); border-radius: 4px;
                   text-decoration: none; color: var(--ink); background: var(--paper);
                   transition: border-color .12s ease, transform .12s ease; }
.svcs__grid .svc:hover { border-color: var(--ink); transform: translateY(-2px); }
.svc__i { color: var(--accent); width: 34px; height: 34px; margin-bottom: 4px; }
.svcs__grid .svc__name { font-size: 17px; font-weight: 700; line-height: 1.25; }
.svcs__grid .svc__card { font-size: 15px; color: var(--ink-2); }
.svc__go { margin-top: auto; padding-top: 8px; font-size: 14px; font-weight: 600;
           color: var(--accent); }

/* vetting */
.vet__grid { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px;
             grid-template-columns: 1fr; }
@media (min-width: 720px) { .vet__grid { grid-template-columns: repeat(2, 1fr); } }
.vetc { display: flex; gap: 14px; align-items: flex-start; padding: 18px;
        border: 1px solid var(--rule-2); border-radius: 4px; background: var(--paper); }
.vetc__i { color: var(--accent); width: 30px; height: 30px; }
.vetc b { display: block; font-size: 16.5px; font-weight: 700; }
.vetc span { display: block; margin-top: 4px; font-size: 15px; color: var(--ink-2); }

@media (prefers-reduced-motion: reduce) {
  .svcs__grid .svc:hover { transform: none; }
}

.pick__kind { margin: auto 0 0; padding-top: 8px; font-size: 14px; color: var(--ink-2); }

/* ── phones ──────────────────────────────────────────────────────────────────
   SVG text is sized in the map's own units, so a label that reads well at
   1280px shrinks to about 7px on a 390px phone. There, only this suburb's own
   name is kept and made legible; the neighbours are texture, and their names
   would have to be too small to read or too big to fit without colliding. */
@media (max-width: 600px) {
  .smap__label--n { display: none; }
  .smap__label { font-size: 46px; stroke-width: 10px; }
  .smap__ring { stroke-width: 5; }

  /* Steps: icon beside the heading rather than above it, so three cards stop
     costing three full screens of scroll. */
  .step { display: grid; grid-template-columns: auto 1fr; column-gap: 12px;
          padding: 16px; }
  .step__i { grid-row: 1 / 3; width: 28px; height: 28px; margin-top: 2px; }
  .step__t { margin: 0 0 4px; font-size: 16px; }
  .step__b { grid-column: 2; font-size: 14.5px; }
  .step__n { top: 16px; right: 16px; }

  /* Services the same way: icon to the left, so seven cards are a compact
     list rather than seven screens. */
  .svcs__grid .svc { display: grid; grid-template-columns: auto 1fr;
                     column-gap: 12px; row-gap: 2px; padding: 14px 16px; }
  .svc__i { grid-row: 1 / 4; width: 28px; height: 28px; margin: 2px 0 0; }
  .svcs__grid .svc__name { font-size: 16px; }
  .svcs__grid .svc__card { font-size: 14.5px; }
  .svc__go { padding-top: 4px; font-size: 13.5px; }
}
