/* ---------------------------------------------------------------------------
   Pro Plumbing — design tokens
   ---------------------------------------------------------------------------
   Sampled from Greg's logo rather than guessed. The two hero colours are the
   ones the mark is actually built from:

     #29AAE1  the signature blue — the swoosh, the wordmark, the houses
     #F4891F  the orange end of the warm swoosh
     #C9291F  the red end of it
     #0070B8  the deeper blue in the wordmark and the P's stem
     #001D32  the near-black blue the whole mark sits on

   The ramps around them are extended, not sampled, and kept sympathetic: the
   neutrals are tinted toward the brand blue so greys sit with the mark rather
   than against it.

   ⚠ THE LOGO'S OWN COLOURS DO NOT WORK AS TEXT ON WHITE. Measured:
       #29AAE1 on white = 2.65:1      #F4891F on white = 2.49:1
   Both are under even the 3:1 minimum for a border or an icon, let alone the
   4.5:1 text needs. That is not a fault in the logo — it is designed to sit on
   black, where the same colours measure 7.13:1 and 7.59:1. It does mean the
   brand blue and orange are DECORATIVE on a light page: large fills, the mark
   itself, a dark band. Anything that has to be read or perceived uses
   --blue-700 or --flame-600 and darker, which are measured below.
--------------------------------------------------------------------------- */

/* Archivo Narrow, self-hosted, one variable file covering both weights the
   site uses. See src/assets/fonts/README.md for why this face, why headings
   only and why not a Google Fonts <link>. `swap` because a plumbing emergency
   should read the heading in the system font rather than wait for ours. */
@font-face {
  font-family: 'Archivo Narrow';
  src: url('../fonts/archivo-narrow-latin.woff2') format('woff2-variations');
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Brand blue. 500 is the logo's own blue; 700 is the functional one. */
  --blue-50: #eaf7fd;
  --blue-100: #cfeefa;
  --blue-200: #a3ddf4;
  --blue-300: #6ac6ec;
  --blue-400: #3fb6e8;
  --blue-500: #29aae1; /* logo */
  --blue-600: #1490ce; /* 3.55:1 on white — borders, large UI, not body text */
  --blue-700: #0070b8; /* logo; 5.24:1 on white — links, buttons */
  --blue-800: #00568c; /* 7.75:1 on white */
  --blue-900: #003a61;
  --blue-950: #001d32; /* logo */

  /* The warm swoosh, orange through to red. */
  --flame-50: #fef3e8;
  --flame-100: #fde2c7;
  --flame-200: #fbc493;
  --flame-300: #f8a55b;
  --flame-400: #f4891f; /* logo — decorative on white (2.49:1), fine on dark */
  --flame-500: #e85c25; /* 3.51:1 on white AND 5.38:1 on dark — the focus ring */
  --flame-600: #d6372a; /* 4.73:1 on white — the accent button */
  --flame-700: #c9291f; /* logo */
  --flame-800: #a2211a;

  /* Neutrals, tinted toward the brand blue. */
  --slate-50: #f5f8fa;
  --slate-100: #e8eef3;
  --slate-200: #d2dde6;
  --slate-300: #aebfcd;
  --slate-400: #7e94a6;
  --slate-500: #5a7186; /* 5.07:1 on white */
  --slate-600: #445a6d; /* 7.17:1 on white */
  --slate-700: #334656;
  --slate-800: #22303c; /* 13.50:1 on white — body text */
  --slate-900: #141f28;
  --slate-950: #07121c; /* the ground the logo was drawn for */

  /* Spacing, on a 0.25rem base. The number IS the multiple, so --space-6 is
     6 x 0.25 = 1.5rem and the name carries its own arithmetic.

     This scale was not imposed, it was measured: 54 of the 80 spacing values
     already in this file sat on these seven steps before any token existed.
     Formalising it is a description of what the stylesheet was already doing.

     The off-scale values are gone now, resolved per use rather than by a
     blanket round, because a single rounding rule would have made some of
     them worse. Two rules, and they pull in opposite directions on purpose:

       - Padding and gaps on anything a thumb touches ROUND UP (0.6 and 0.7
         both go to 0.75). The review flags several targets under the 44px
         convention, so on an interactive element the nearer step is not
         automatically the better one.
       - Everything else rounds to the NEAREST step (0.35 to 0.25, 0.4 and
         0.45 to 0.5, 0.85 to 0.75).

     The three heading sizes that were 1.1, 1.15 and 1.125rem are now one
     token. They were three decisions rendering as one thing. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;

  /* Type. Same rule: only the sizes already in use, named rather than
     collapsed. 0.9/0.95 and 1.1/1.125/1.15 are near-duplicates and the
     review reports them; they are not merged here because a 2% type change
     is still a type change. */
  --text-sm: 0.9rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-h1: clamp(1.6rem, 4vw, 2.2rem);

  /* Roles. Templates use these, not the ramps, so a rebrand is one block.
     `--heading` exists so a heading follows its band: `.band--dark` redefines
     it and every h1/h2 inside flips without being told. */
  /* Two measures. 68ch is a reading measure and stays the default for prose.
     Photography and grids get the wide one — a hero pinned to a paragraph's
     width is the difference between a page that looks sure of itself and one
     that looks like a document. */
  /* The display face is a role too, with the system stack behind it, so a
     heading still renders in something sensible if the font never arrives. */
  --font-display: 'Archivo Narrow', 'Arial Narrow', system-ui, sans-serif;

  /* Three, and the distinction matters. --measure is the CONTAINER width and is
     deliberately overridable: `.band--wide` raises it so a band can use the
     page. --measure-text is the READING width and is never overridden, because
     a paragraph does not get easier to read inside a wide band — writing a
     prose cap as var(--measure) is how the service descriptions ended up 150
     characters long. */
  --measure: 68ch;
  --measure-wide: 74rem;
  --measure-text: 68ch;

  --heading: var(--slate-900);
  --ink: var(--slate-800);
  --ink-muted: var(--slate-600);
  --surface: #fff;
  --surface-sunk: var(--slate-50);
  --rule: var(--slate-200);
  --link: var(--blue-700);
  --link-hover: var(--blue-800);
  --ring: var(--flame-500);
}

* {
  box-sizing: border-box;
}
body {
  margin: 0;
  font:
    16px/1.65 system-ui,
    -apple-system,
    'Segoe UI',
    sans-serif;
  color: var(--ink);
  background: var(--surface);
}
/* The full-bleed grid. `main` is the whole width and lays out three columns:
   slack, the reading measure, slack. Every direct child lands in the middle
   column without asking, so nothing that existed before this had to change —
   and a section that wants the whole width says `.band` and gets it, with the
   same three columns nested inside so its own content keeps the measure.

   This is what makes the alternating colour bands possible at all. A section
   cannot carry a full-width background while its parent is capped at 68ch. */
main {
  display: grid;
  grid-template-columns: 1fr min(var(--measure-wide), calc(100% - 2 * var(--space-4))) 1fr;
  padding: var(--space-8) 0 var(--space-12);
}
main > * {
  grid-column: 2;
}

/* One left edge. The container is wide so every band, grid and paragraph
   starts at the same x; the READING measure is then applied to the things
   that are read, rather than to the box around them. Three left edges on one
   page is an accident; this is the fix for it.

   Grids opt out below, because a grid capped at a paragraph's width is a
   paragraph-shaped grid. */
main p,
main h1,
main h2,
main h3,
main dl,
main .stack,
main .covers,
main .callout,
main .crumbs {
  max-width: var(--measure-text);
}
.work,
.gallery,
.hero-inner {
  max-width: none;
}
/* Wider than prose, narrower than the page. At the full wide measure this
   became seven columns of three-line tiles, which is more tiles and a worse
   grid — the point is something big enough to hit while holding a bucket. */
.problems ul {
  max-width: 56rem;
}
/* Inside a box the box is already the measure. */
.callout p,
.callout h2,
.stack p,
.stack h2 {
  max-width: none;
}

/* A band: full width, its own vertical rhythm, the measure restored inside. */
.band {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1fr min(var(--measure), calc(100% - 2 * var(--space-4))) 1fr;
  padding: var(--space-12) 0;
  margin: var(--space-12) 0;
}
.band > * {
  grid-column: 2;
}
.band > :first-child {
  margin-top: 0;
}
.band > :last-child {
  margin-bottom: 0;
}

/* The dark band. Nothing here is a new colour: --blue-950 is the ground Greg's
   logo was drawn for, and the roles are redefined rather than overridden per
   element — which is the whole reason the stylesheet has role tokens. Anything
   inside a dark band inherits the flip, including partials that know nothing
   about it. */
.band--dark {
  background: var(--blue-950);
  --ink: var(--slate-50);
  --ink-muted: var(--blue-200);
  --heading: var(--slate-50);
  --link: var(--blue-300);
  --link-hover: var(--blue-100);
  --rule: rgba(255, 255, 255, 0.18);
  --surface: var(--blue-900);
  --surface-sunk: var(--blue-900);
  color: var(--ink);
}

/* The hero is a band too, but split: the statement and the call on one side,
   one tall photograph on the other. Split rather than full-bleed because
   Greg's best originals are portrait at 1536x2048 and his best landscape is
   960x720 — which would be upscaled to fill a wide band, and look soft exactly
   where the page is trying to look sure of itself. See planning/design/. */
.hero,
.band--wide {
  --measure: var(--measure-wide);
}
.hero {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1fr min(var(--measure), calc(100% - 2 * var(--space-4))) 1fr;
  padding: 0;
  margin: 0 0 var(--space-12);
}
.hero-inner {
  grid-column: 2;
  display: grid;
  gap: var(--space-8);
  align-items: center;
}
.hero-shot {
  margin: 0;
}
.hero-shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
}
@media (min-width: 48em) {
  .hero-inner {
    grid-template-columns: 1.1fr 0.9fr;
    gap: var(--space-12);
  }
  /* The photograph is capped so a tall portrait does not set the height of the
     whole first screen. */
  .hero-shot img {
    max-height: 34rem;
    object-fit: cover;
  }
}
h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.1;
  /* Condensed type sets tighter than the system stack, so it wants a shade
     more letter-spacing at small sizes and none at large. */
  letter-spacing: 0.005em;
  color: var(--heading);
}
h1 {
  font-weight: 700;
  letter-spacing: -0.005em;
}
h1 {
  font-size: var(--text-h1);
}
.lead {
  font-size: var(--text-lg);
  color: var(--ink-muted);
}
a {
  color: var(--link);
}
/* Every hover state is paired with the same :active state, and the pairing is
   the point rather than a tidy-up: a phone has no hover at all, so a rule that
   only fires on :hover is a desktop decoration and a tap gets no acknowledgement
   from the site whatsoever. The tap is also the slower, less precise input -- a
   finger covers the thing it is pressing -- so it is the one that needs the
   feedback more. Same declarations, so the palette stays closed and there is no
   second appearance to keep in step. */
a:hover,
a:active {
  color: var(--link-hover);
}
:focus-visible {
  outline: 3px solid var(--ring);
  outline-offset: 2px;
  border-radius: 2px;
}

/* The dark band the mark was designed for. */
.site-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--slate-950);
  color: #fff;
}
.site-header a {
  color: #fff;
}
.brand {
  font-family: var(--font-display);
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-weight: 700;
  font-size: var(--text-lg);
  letter-spacing: 0.02em;
  text-decoration: none;
}
.brand img {
  width: 38px;
  height: 38px;
  display: block;
}
.site-header nav ul {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
}
.site-header .tel {
  margin-left: auto;
  font-weight: 700;
  color: var(--blue-300);
  white-space: nowrap;
}

.hero {
  padding-bottom: var(--space-2);
}
.btn {
  display: inline-block;
  padding: var(--space-3) var(--space-5);
  background: var(--blue-700);
  color: #fff;
  font-weight: 600;
  text-decoration: none;
  border-radius: 6px;
}
.btn:hover,
.btn:active {
  background: var(--blue-800);
  color: #fff;
}
.btn-accent {
  background: var(--flame-600);
}
.btn-accent:hover,
.btn-accent:active {
  background: var(--flame-700);
}
.cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin: var(--space-6) 0;
}

.crumbs {
  font-size: var(--text-sm);
  color: var(--ink-muted);
  margin-bottom: var(--space-4);
}

.callout {
  margin: var(--space-8) 0;
  padding: var(--space-4) var(--space-5);
  background: var(--surface-sunk);
  /* The brand blue as a large decorative fill, which is what it is good at. */
  border-left: 5px solid var(--blue-500);
  border-radius: 0 6px 6px 0;
}
.callout h2 {
  font-size: var(--text-lg);
  margin-top: 0;
}

label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--space-1);
}
input,
textarea {
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--slate-400);
  border-radius: 4px;
  font: inherit;
}
button[type='submit'] {
  padding: var(--space-3) var(--space-5);
  border: 0;
  border-radius: 6px;
  background: var(--flame-600);
  color: #fff;
  /* Two declarations, not one. `font: inherit, 600` is not valid CSS -- the
     shorthand takes no comma list -- so the whole declaration was dropped and
     the button fell back to the UA's own button font: measured in Chromium as
     Arial at 13.3333px, on the page whose only job is to be filled in. The
     inputs above it were correct, which is what made it survive an eyeball.
     `font: inherit` resets family, size, line-height and weight together, so
     the weight has to be restated after it, not inside it. */
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
button[type='submit']:hover,
button[type='submit']:active {
  background: var(--flame-700);
}

/* The footer is the last band rather than a light strip with a rule on top:
   it closes the page on the same ground the header opens it on. */
.site-footer {
  background: var(--blue-950);
  padding: var(--space-12) var(--space-4);
  font-size: var(--text-sm);
  --ink: var(--slate-50);
  --ink-muted: var(--blue-200);
  --heading: var(--slate-50);
  --link: var(--blue-300);
  --link-hover: var(--blue-100);
  --rule: rgba(255, 255, 255, 0.18);
  color: var(--ink-muted);
}
.site-footer strong {
  color: var(--ink);
}

/* The social row. A list rather than a bare <a> because there will be a second
   account one day and a row of one is still a row. */
.social {
  /* The two sizes are declared once, here, because a third value is derived
     from them below and a literal in that calc would go stale the moment
     either changed. */
  --glyph: 22px; /* the size the mark reads at */
  --target: 44px; /* the size a thumb needs -- not the same number */
  list-style: none;
  display: flex;
  gap: var(--space-1);
  margin: var(--space-4) 0;
  padding: 0;
  /* Optical alignment, and it is not a nicety. The glyph is centred in a target
     twice its width, so its visible left edge sits half the difference in from
     the link's box -- while every other line in this footer starts flush. The
     icon read as indented against them. Pulling the row back by exactly that
     half-difference puts the MARK in the text column rather than the box that
     contains it, which is what the eye is lining up. Derived rather than typed:
     -11px would be a literal that silently stops being right. */
  margin-left: calc((var(--glyph) - var(--target)) / 2);
}
.social a {
  /* This is the one place on the site where the full 44px is not a compromise.
     An icon link has no words to widen it, so the target IS the padding -- drop
     it and the link becomes a 22px target, which is under even the WCAG floor.
     The nav links elsewhere get to stay at 40px precisely because they have
     text; these have none. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--target);
  height: var(--target);
  border-radius: 50%;
  color: var(--link);
  /* The icon is the only thing in the link, so an underline would sit under a
     glyph rather than under text. */
  text-decoration: none;
}
/* Sized here as well as on the element, and deliberately: the width/height
   attributes in the markup are what hold the layout before this stylesheet
   arrives, and this is what keeps the glyph tied to --glyph afterwards. */
.social a svg {
  width: var(--glyph);
  height: var(--glyph);
}
.social a:hover,
.social a:active {
  color: var(--link-hover);
  /* Faint rather than a filled circle: the footer is quiet and a solid disc
     appearing under the cursor is louder than the link it belongs to. */
  background: rgba(255, 255, 255, 0.1);
}

/* Text for a screen reader and nothing else. The clip-rect pattern rather than
   `display: none` or `left: -9999px`: display:none is not announced at all, and
   moving text 9999px off-canvas makes some browsers scroll to it when the link
   inside takes focus. This is the only accessible name the social links have,
   so getting it wrong makes them read as "link". */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------------------------------------------------------
   Services: cards, photographs and the "what this covers" list.

   Every photograph on the site is one of Greg's own jobs. They arrived as
   800x800 thumbnails padded with white, which is invisible on a white page and
   made the grids look ragged; the padding is trimmed off, so they are now 4:3
   and 3:4 at their true size. Each record carries its own width/height and the
   markup emits them, so the page does not jump while they load. The grids then
   crop to one landscape box so a row of mixed portraits and landscapes lines
   up.
--------------------------------------------------------------------------- */
/* The list, used by BOTH the services and the small jobs. The small-jobs index
   already had this shape — name, one line, a rule between — and the services
   were the ones in a card grid. Identical rounded cards with one radius and one
   shadow each is a named tell of a generated page; a list is lighter, reads
   faster, and needs no stand-in panel for a service that has no photograph.
   Which is how `.card-photo-none` stopped existing. */
.stack {
  list-style: none;
  padding: 0;
  margin: var(--space-6) 0;
}
.stack li {
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--rule);
}
.stack li:first-child {
  border-top: 1px solid var(--rule);
}
.stack h2,
.stack h3 {
  font-size: var(--text-lg);
  margin: 0 0 var(--space-1);
}
.stack p {
  margin: 0;
  color: var(--ink-muted);
}

/* The photography, bigger. The brief's one departure from the reference: it
   drops cards and has a gallery elsewhere, but Greg's photographs are the best
   material on this site, so they change shape rather than shrink — three large
   images across instead of eight thumbnails. */
.work {
  list-style: none;
  padding: 0;
  margin: var(--space-8) 0 0;
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.work img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  border-radius: 8px;
}

/* The service-page galleries and the single job photograph. These were
   collateral damage when the card rules were cut out and are restored here
   deliberately larger: the container is the wide measure now, and the brief's
   instruction was that the photography grows rather than shrinks. 18rem
   minimum instead of 13 means three across on a laptop rather than five. */
.gallery {
  list-style: none;
  padding: 0;
  margin: var(--space-6) 0 var(--space-8);
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
}
.gallery img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: 8px;
  background: var(--surface-sunk);
}

/* One photograph on its own page keeps its real shape — there is no row for it
   to line up with. */
.job-photo {
  margin: var(--space-6) 0;
  max-width: 32rem;
}
.job-photo img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 8px;
}

/* A named feature and what it does — a definition list because that is what
   the pairs are. Only the shower toilet page uses it. */
.features {
  margin: var(--space-4) 0 var(--space-6);
}
.features dt {
  font-weight: 600;
  margin-top: var(--space-4);
}
.features dd {
  margin: var(--space-1) 0 0;
  color: var(--ink-muted);
}

/* Greg's own service wording, listed rather than written into a paragraph so
   each phrase stays exactly as he put it. */
.covers {
  list-style: none;
  padding: 0;
  margin: var(--space-4) 0 var(--space-6);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.covers li {
  padding: var(--space-1) var(--space-3);
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-size: var(--text-sm);
  color: var(--ink-muted);
}

.note {
  color: var(--ink-muted);
  font-size: var(--text-sm);
}

/* Greg's strapline, above the h1 rather than instead of it. */
.eyebrow {
  margin: 0 0 var(--space-1);
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--blue-700);
}

/* ---------------------------------------------------------------------------
   Small screens: the phone, and getting to it.

   This stylesheet had no media queries at all. That was survivable because the
   layout is fluid — but the header is a wrapping flex row carrying a brand,
   five links and the telephone number, and at 360px the number wrapped to the
   third line. The number is the most important control on the site and it was
   the last thing in the wrap order.

   Everything below is mechanism rather than claim: it changes how the page
   behaves on a phone and states nothing new about the business.
--------------------------------------------------------------------------- */

/* Invisible until focused, then the first thing in the tab order. Positioned
   rather than display:none, because a hidden element cannot take focus. */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--slate-950);
  color: #fff;
  z-index: 20;
}
.skip:focus {
  left: 0;
}

/* The wrapper holding main and the call bar — see src/layouts/layout.hbs. It is
   what gives the sticky bar something to be released by. */
.page {
  display: flex;
  flex-direction: column;
  /* Tall enough that a short page (404, thanks) still puts the bar at the foot
     of the screen rather than floating under two lines of text. */
  min-height: calc(100vh - 12rem);
}
.page > main {
  flex: 1 0 auto;
}

.callbar {
  position: sticky;
  bottom: 0;
  z-index: 10;
  display: flex;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--slate-950);
  /* The band is the logo's own ground, so the brand blue is readable on it and
     usable as a large fill here in a way it never is on white. */
  border-top: 3px solid var(--blue-500);
}
.callbar a {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  /* 44px, the smallest target that is reliably hit with a thumb. */
  min-height: 44px;
  padding: var(--space-2) var(--space-3);
  border-radius: 6px;
  font-weight: 700;
  text-decoration: none;
  text-align: center;
}
.callbar a {
  /* The two labels are short enough to sit on one line at 360px and are kept
     there: a wrapped label made the bar 91px tall, which is a ninth of a phone
     screen spent on two words. Verified against the narrowest width the site is
     designed for rather than assumed — if a label ever grows, re-measure, since
     nowrap on a flex item is what would push the page into horizontal scroll. */
  white-space: nowrap;
}
.callbar-primary {
  /* Two thirds of the bar: calling is the primary action, and the two are not
     offered as equals. */
  flex: 2;
  background: var(--flame-600);
  color: #fff;
}
.callbar-primary:hover,
.callbar-primary:active {
  background: var(--flame-700);
  color: #fff;
}
.callbar-secondary {
  background: transparent;
  border: 1px solid var(--slate-400);
  color: #fff;
}
.callbar-secondary:hover,
.callbar-secondary:active {
  background: var(--slate-800);
  color: #fff;
}

/* Above this width the header's own number is always in view, so the bar is
   only taking space. */
@media (min-width: 48em) {
  .callbar {
    display: none;
  }
  .page {
    min-height: 0;
  }
}

@media (max-width: 47.99em) {
  /* Row one is the brand and the number; the navigation drops to its own row
     underneath. Source order stays brand -> nav -> tel, which is the right
     order to read and to tab through; only the visual arrangement moves. */
  .site-header {
    gap: var(--space-2) var(--space-3);
    padding: var(--space-3) var(--space-4);
  }
  /* The brand and the number have to share the first row: measured at 360px,
     the header was 190px tall before a word of the page showed, because the
     brand at its desktop size pushed the number onto a row of its own. The mark
     stays legible at 32px and the wordmark at 1rem. */
  .brand {
    font-size: var(--text-base);
    gap: var(--space-2);
  }
  .brand img {
    width: 32px;
    height: 32px;
  }
  .site-header nav {
    order: 1;
    flex-basis: 100%;
  }
  .site-header nav ul {
    /* The row gap is --space-2 rather than --space-1 for one reason: measured at
       375px the five links come to 325px and stay on one row, so the row gap is
       only ever read below the 360px this site is designed down to -- and there
       it is the gap between two 40px targets stacked on top of each other. At
       --space-1 that gap is 4px, under the 8px two adjacent targets need to stop
       a thumb hitting the wrong one. The column gap is already 12px. */
    gap: var(--space-2) var(--space-3);
    font-size: var(--text-sm);
  }
  .site-header nav a {
    display: inline-block;
    /* Not the full 44px — these are secondary to the two bar actions, and a
       44px row of five links would push the page content off the screen. This
       is the compromise the bar exists to make safe. */
    padding: var(--space-2) 0;
  }
  .site-header .tel {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 var(--space-3);
    font-size: var(--text-sm);
    border: 1px solid var(--blue-600);
    border-radius: 6px;
  }
  main {
    padding: var(--space-6) var(--space-4) var(--space-8);
  }
  /* A full-width primary button is easier to hit than an inline one, and on a
     narrow screen there is nothing to sit beside it anyway. */
  .cta {
    gap: var(--space-3);
  }
  .cta .btn {
    display: block;
    width: 100%;
    min-height: 44px;
    text-align: center;
  }
}

/* ---------------------------------------------------------------------------
   The enquiry form.

   It asks for a telephone number rather than an email address, because that is
   how this business works, and it asks what the problem is and where you are,
   because those are the two things that decide whether the job is Greg's. The
   styling has one job beyond looking tidy: on a phone, every control has to be
   big enough to hit and the keyboard that comes up has to be the right one.
--------------------------------------------------------------------------- */
.contact-routes {
  list-style: none;
  padding: 0;
  margin: var(--space-6) 0 var(--space-8);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  color: var(--ink-muted);
}

.enquiry {
  max-width: 34rem;
  margin-bottom: var(--space-8);
}
.enquiry p {
  margin: 0 0 var(--space-5);
}
.enquiry select {
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--slate-400);
  border-radius: 4px;
  font: inherit;
  background: var(--surface);
  color: var(--ink);
}
/* 44px on every control, not just the button: a select that is 34px tall is one
   a thumb misses. */
.enquiry input,
.enquiry select,
.enquiry button {
  min-height: 44px;
}
.enquiry input[type='file'] {
  padding: var(--space-2);
  background: var(--surface-sunk);
}
.field-note {
  display: block;
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--ink-muted);
}
.optional {
  font-weight: 400;
  color: var(--ink-muted);
}
.enquiry button[type='submit'] {
  width: 100%;
}
@media (min-width: 30em) {
  .enquiry button[type='submit'] {
    width: auto;
    min-width: 12rem;
  }
}

/* The honeypot. Never shown, never announced, never in the tab order — the
   markup carries aria-hidden and tabindex="-1" as well, because display:none
   alone is what a competent bot checks for first. */
.hp {
  display: none;
}

/* ---------------------------------------------------------------------------
   The problem grid. Two columns on a phone, filling out on a wider screen.
   Tiles rather than a list, because the point is to be scannable at arm's
   length by somebody who is holding a bucket with the other hand.
--------------------------------------------------------------------------- */
.problems ul {
  list-style: none;
  padding: 0;
  margin: var(--space-4) 0 var(--space-8);
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
}
.problems a {
  display: flex;
  align-items: center;
  height: 100%;
  min-height: 56px;
  padding: var(--space-3) var(--space-3);
  background: var(--surface-sunk);
  border: 1px solid var(--rule);
  /* The brand blue as a fill, which is the one thing it is good at on white. */
  border-left: 4px solid var(--blue-500);
  border-radius: 0 6px 6px 0;
  font-weight: 600;
  line-height: 1.3;
  text-decoration: none;
}
.problems a:hover,
.problems a:active {
  background: var(--blue-50);
  border-left-color: var(--blue-700);
}
