/*  Specialty Coffee Repair - maqueta styles
 *  Ported verbatim from the Cursor mockup (D:\Website Cursor\maqueta\css\styles.css).
 *  Three changes only, all mechanical:
 *    - image urls repointed at assets/images/maqueta/*.webp
 *    - the .mock-banner rule removed (it labelled the mockup)
 *    - `.nav { display: none }` on mobile removed; the ported header has a
 *      real menu button, which the mockup never had.
 *  Fonts are self-hosted here rather than fetched from Google, which is how
 *  the rest of this theme already loads Inter and Source Serif.
 */

/*  NOTE ON @layer -- removed on purpose, do not put it back.
 *
 *  The mockup wrapped everything in @layer reset/base/theme/components/utilities.
 *  That is fine in a standalone page where nothing else is on it. Inside
 *  WordPress it is a trapdoor: unlayered CSS beats layered CSS outright, at any
 *  specificity, so a single `summary { color: #3a3330 }` from a plugin, from a
 *  block stylesheet, or from a host wrapper silently overrides this entire file.
 *  That is exactly what happened -- FAQ questions rendered near-black on the
 *  dark ground while the same markup looked correct served on its own.
 *
 *  The rules below are in the same order they were inside the layers, and the
 *  two selectors that appeared in two layers (body, html) resolve the same way
 *  by source order, so the cascade is unchanged.
 */

@font-face {
  font-family: "Inter";
  src: url("../fonts/inter.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("../fonts/sourceserif4-roman.woff2") format("woff2");
  font-weight: 200 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Source Serif 4";
  src: url("../fonts/sourceserif4-italic.woff2") format("woff2");
  font-weight: 200 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibmplexmono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "IBM Plex Mono";
  src: url("../fonts/ibmplexmono-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* was @layer reset */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

img,
svg {
  max-width: 100%;
  /* height:auto is the required companion to max-width:100%. Without it an
     <img> that carries width/height attributes keeps the attribute height
     while the width is capped, so the box distorts -- and any aspect-ratio
     set in CSS is ignored, because aspect-ratio only applies when height is
     auto. On the partner tiles that turned a 300x225 thumbnail into a
     908x1024 box, and object-fit:cover then magnified the photo to fill it.
     The mockup's own <img> tags carried no dimensions, so it never showed
     there; the shortcode that renders page images adds them for layout
     stability, which is what exposed this. */
  height: auto;
  display: block;
}

button,
input,
textarea,
select {
  font: inherit;
  color: inherit;
}

a {
  color: inherit;
}


/* was @layer theme */
:root {
  --bg: #0b0a08;
  --bg-deep: #070706;
  --panel: #14110e;
  --panel-warm: #1d150f;
  --raised: #18140f;
  --cream: #f4eee7;
  --copper: #c9763e;
  --copper-hot: #c98243;
  --gold: #e0aa62;
  --gold-soft: #d39249;
  --muted: #b8afa7;
  --line: rgba(208, 137, 62, 0.22);
  --line-soft: rgba(240, 220, 195, 0.11);
  --grid: rgba(224, 170, 98, 0.045);
  --sage: #8da477;
  --shadow: 0 28px 80px rgba(0, 0, 0, 0.35);
  --container: 1220px;
  --radius: 18px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}


/* was @layer base */
html {
  scroll-behavior: smooth;
}

body {
  min-height: 100dvh;
  background: var(--bg);
  color: var(--cream);
  font-family: Inter, Arial, sans-serif;
  font-size: 1.02rem;
  line-height: 1.6;
  letter-spacing: -0.011em;
}

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 3px;
}

h1,
h2,
h3 {
  font-family: "Source Serif 4", Georgia, serif;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.025em;
  text-wrap: balance;
  overflow: visible;
}

p {
  text-wrap: pretty;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--gold);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.eyebrow::before {
  content: "";
  width: 1.6rem;
  height: 1px;
  background: var(--copper);
}


/* was @layer components */
.wrap {
  width: min(100% - 2.4rem, var(--container));
  margin-inline: auto;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  backdrop-filter: blur(16px);
  background: color-mix(in srgb, var(--bg) 78%, transparent);
  border-bottom: 1px solid var(--line-soft);
}


.brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  text-decoration: none;
}

.brand img {
  width: 38px;
  height: 38px;
  object-fit: contain;
}


.nav {
  display: flex;
  align-items: center;
  gap: 1.15rem;
}

.nav a {
  text-decoration: none;
  color: color-mix(in srgb, var(--cream) 82%, var(--muted));
  font-size: 0.86rem;
}

.nav a[aria-current="page"],
.nav a:hover {
  color: var(--gold);
}


.hero {
  position: relative;
  overflow: clip;
  padding-block: 3.2rem 1.4rem;
  background:
    radial-gradient(circle at 72% 38%, rgba(153, 83, 31, 0.2), transparent 36%),
    linear-gradient(90deg, #0a0907 0%, #0c0a08 48%, #100d0a 100%);
}

.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 48px 48px;
  mask-image: linear-gradient(180deg, #000 40%, transparent);
  pointer-events: none;
}

.hero-grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 2rem;
  align-items: center;
}

.hero h1 {
  margin: 0.7rem 0 1rem;
  font-size: clamp(2.4rem, 5vw, 4.3rem);
  color: var(--cream);
}

.hero h1 em {
  display: block;
  font-style: italic;
  font-weight: 500;
  color: var(--copper-hot);
}

.lede {
  max-width: 38rem;
  color: color-mix(in srgb, var(--cream) 78%, var(--muted));
  margin-bottom: 1.4rem;
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.4rem;
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 48px;
  padding: 0.7rem 1.15rem;
  border-radius: 999px;
  text-decoration: none;
  border: 1px solid transparent;
  transition: transform 180ms var(--ease), background 180ms var(--ease);
}

.button:hover {
  transform: translateY(-1px);
}

.button-primary {
  background: linear-gradient(135deg, #c67a38, #a95e28);
  color: #fff;
}

.button-ghost {
  border-color: color-mix(in srgb, var(--cream) 28%, transparent);
  background: transparent;
}

.trust-list {
  display: grid;
  gap: 0.55rem;
  padding: 0;
  margin: 0;
  list-style: none;
  color: color-mix(in srgb, var(--cream) 86%, var(--muted));
  font-size: 0.92rem;
}

.trust-list li {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}

.trust-list svg {
  width: 16px;
  height: 16px;
  color: var(--gold);
  flex: none;
}

.cutaway {
  position: relative;
  min-height: 520px;
}

.cutaway-frame {
  position: relative;
  border-radius: 28px;
  overflow: hidden;
  background: #100d0a;
  box-shadow: var(--shadow);
  isolation: isolate;
}

.cutaway-frame img {
  width: 100%;
  height: 600px;
  object-fit: cover;
  object-position: 42% 55%;
}

.cutaway-badge {
  position: absolute;
  top: 1rem;
  left: 1rem;
  z-index: 2;
  padding: 0.45rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(10px);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
}

.cutaway-legend {
  position: absolute;
  top: 4.4rem;
  left: 0.85rem;
  z-index: 5;
  width: 9.6rem;
}

.cutaway-active {
  margin: 0.75rem 0 0;
  display: grid;
  gap: 0.15rem;
}

.cutaway-active strong {
  color: var(--gold);
  font-size: 0.92rem;
}

.cutaway-active span {
  color: var(--muted);
  font-size: 0.86rem;
  line-height: 1.45;
}

.cutaway-keys {
  display: grid;
  gap: 0.28rem;
}

.cutaway-key {
  width: 100%;
  min-height: 1.85rem;
  padding: 0.28rem 0.6rem;
  border: 1px solid rgb(255 255 255 / 0.12);
  border-radius: 8px;
  background: rgb(10 8 6 / 0.55);
  color: #fff;
  font-size: 0.76rem;
  text-align: start;
  cursor: pointer;
  backdrop-filter: blur(8px);
}

.cutaway-key.is-active,
.cutaway-key:hover {
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  background: rgb(29 22 15 / 0.82);
  color: var(--cream);
}

.spec-bar {
  margin-top: -1.2rem;
  position: relative;
  z-index: 5;
}

.spec-grid {
  display: grid;
  grid-template-columns: 1.1fr max-content 1.1fr 1.05fr;
  gap: 0;
  border: 1px solid var(--line);
  border-radius: 20px;
  overflow: hidden;
  background: linear-gradient(100deg, rgba(27, 22, 17, 0.98), rgba(20, 17, 14, 0.98));
}

.spec {
  padding: 1.05rem 1.15rem;
  border-inline-end: 1px solid var(--line-soft);
}

.spec:last-child {
  border-inline-end: 0;
}

.spec.featured {
  background:
    linear-gradient(180deg, rgba(201, 118, 62, 0.16), transparent 70%),
    #1a140f;
}

.spec dt {
  margin: 0 0 0.2rem;
  color: var(--gold);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.spec dd {
  margin: 0;
  font-size: 0.98rem;
  white-space: nowrap;
}

.section {
  padding-block: 5.25rem;
  scroll-margin-top: 5.5rem;
}

.section-head {
  max-width: 46rem;
  margin-bottom: 2.4rem;
}

.section h2 {
  margin: 0.65rem 0 1rem;
  padding-block-start: 0.08em;
  font-size: clamp(1.9rem, 3.6vw, 2.95rem);
}

.section h2 em {
  font-style: italic;
  color: var(--copper-hot);
}

.section-copy {
  color: var(--muted);
  max-width: 44rem;
  line-height: 1.72;
  font-size: 1.04rem;
}

.equip {
  background:
    radial-gradient(circle at 80% 20%, rgba(137, 72, 25, 0.16), transparent 32%),
    var(--bg);
}

.equip-layout {
  display: grid;
  grid-template-columns: 1.55fr 0.9fr;
  gap: 1rem;
}

.plate {
  position: relative;
  overflow: hidden;
  border-radius: 22px;
  border: 1px solid var(--line-soft);
  min-height: 280px;
  background: var(--panel);
}

.plate img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  min-height: 280px;
}


.plate figcaption,
.value-card{
  position: absolute;
  inset-inline: 1rem;
  bottom: 1rem;
  padding: 0.85rem 1rem;
  border-radius: 14px;
  background: color-mix(in srgb, #120e0b 82%, transparent);
  border: 1px solid var(--line);
  backdrop-filter: blur(12px);
}

.plate strong {
  display: block;
  font-size: 1.05rem;
}

.plate span,
.support-stack small {
  color: var(--gold);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.support-stack {
  display: grid;
  gap: 1rem;
}

.support-stack .plate {
  min-height: 168px;
}

.support-stack img {
  min-height: 168px;
  filter: saturate(0.85);
}

.values {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 0.9rem;
  margin-top: 1.4rem;
}

.value-card {
  position: static;
  background: linear-gradient(145deg, rgba(30, 23, 17, 0.92), rgba(16, 14, 12, 0.96));
}

.value-card h3 {
  margin: 0 0 0.4rem;
  font-size: 1.2rem;
  color: var(--gold);
}

.value-card p {
  margin: 0;
  color: var(--muted);
}

.systems {
  background: linear-gradient(120deg, #0a0907, #100d0a);
}


.checklist {
  display: grid;
  gap: 0.45rem;
  margin: 1.2rem 0 0;
  padding: 0;
  list-style: none;
}

.checklist li {
  padding-inline-start: 1.1rem;
  position: relative;
  color: color-mix(in srgb, var(--cream) 88%, var(--muted));
}

.checklist li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.55rem;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--copper);
}

.footnote {
  margin-top: 1rem;
  color: var(--muted);
  font-size: 0.92rem;
}


.photo-note {
  margin: 0;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--muted) 82%, var(--cream));
}


.services-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  grid-template-areas:
    "featured a b"
    "featured c d"
    "e e f";
  gap: 0.9rem;
}

.service-card {
  padding: 1.2rem;
  border-radius: 18px;
  border: 1px solid var(--line-soft);
  background: linear-gradient(145deg, rgba(28, 22, 17, 0.97), rgba(16, 14, 12, 0.98));
  min-height: 100%;
}

.service-card h3 {
  margin: 0 0 0.5rem;
  font-size: 1.25rem;
}

.service-card p {
  color: var(--muted);
  margin: 0 0 1rem;
}

.service-card a {
  color: var(--gold);
  text-decoration: none;
}

.service-card.featured {
  position: relative;
  grid-area: featured;
  min-height: 420px;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  background:
    linear-gradient(180deg, transparent 15%, rgba(10, 8, 6, 0.88) 72%),
    url("../images/maqueta/mod-front-a.webp") center / cover;
  border-color: var(--line);
}

.service-card.featured h3,
.service-card.featured p,
.service-card.featured a {
  color: var(--cream);
}

.service-card.featured a {
  color: var(--gold);
}

.service-card:nth-child(2) { grid-area: a; }
.service-card:nth-child(3) { grid-area: b; }
.service-card:nth-child(4) { grid-area: c; }
.service-card:nth-child(5) { grid-area: d; }
.service-card:nth-child(6) { grid-area: e; }
.service-card:nth-child(7) { grid-area: f; }

.split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 2.2rem;
  align-items: center;
}

.split-visual {
  position: relative;
  min-height: 420px;
  border-radius: 22px;
  overflow: hidden;
  border: 1px solid var(--line);
}


.split-visual img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  min-height: 420px;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1rem;
}

.chip {
  appearance: none;
  background: transparent;
  cursor: pointer;
  font: inherit;
  padding: 0.4rem 0.7rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--cream);
  font-size: 0.86rem;
}

.process {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}

.ticket {
  display: flex;
  flex-direction: column;
  padding: 1.25rem 1.2rem 1.4rem;
  min-height: 100%;
  border-radius: 16px;
  background: var(--raised);
  border: 1px dashed color-mix(in srgb, var(--gold) 28%, transparent);
}

.ticket .num {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  color: var(--gold);
  font-size: 0.8rem;
}

.ticket h3 {
  margin: 0.4rem 0 0.45rem;
  font-size: 1.15rem;
}

.ticket p {
  margin: 0;
  color: var(--muted);
}

.partners {
  display: block;
  padding: 1.6rem 1.8rem;
  border-radius: 22px;
  border: 1px solid var(--line);
  background:
    linear-gradient(100deg, rgba(12, 10, 8, 0.94) 0%, rgba(12, 10, 8, 0.88) 42%, rgba(12, 10, 8, 0.35) 68%, rgba(12, 10, 8, 0.15) 100%),
    url("../images/maqueta/mod-hydro-clean.webp") 78% 50% / cover;
}

.partners > div {
  max-width: 34rem;
}

.partners .section-copy {
  max-width: 28rem;
}

.partners .checklist {
  display: grid;
  gap: 0.55rem;
}

.partners .checklist li {
  white-space: nowrap;
}

.coverage-visual {
  display: grid;
  grid-template-columns: 0.85fr 1.15fr;
  gap: 1.2rem;
  align-items: stretch;
}

.coverage-visual.wide {
  grid-template-columns: 1fr;
}

.county-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.map-frame {
  min-height: 560px;
  border-radius: 22px;
  border: 1px solid var(--line);
  background:
    radial-gradient(circle at 72% 28%, rgba(201, 118, 62, 0.16), transparent 26%),
    linear-gradient(#12100d, #0a0908);
  position: relative;
  overflow: hidden;
}


.county {
  cursor: pointer;
  stroke-width: 1.2;
  transition: fill 160ms var(--ease), stroke 160ms var(--ease);
}

.county.primary {
  fill: rgba(201, 118, 62, 0.42);
  stroke: #c98243;
}


.county:hover,
.county:focus-visible,
.county.is-active {
  fill: rgba(224, 170, 98, 0.62);
  stroke: #e0aa62;
  outline: none;
}


.chip.is-active,
.county-card.is-active {
  border-color: var(--gold);
  color: var(--cream);
}

.dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  display: inline-block;
  margin-inline-end: 0.3rem;
}

.dot.primary { background: var(--copper); }


.contact-grid {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: 1.2rem;
}

.form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.8rem;
  padding: 1.2rem;
  border-radius: 20px;
  background: var(--panel);
  border: 1px solid var(--line-soft);
}

.field {
  display: grid;
  gap: 0.35rem;
}

.field.full {
  grid-column: 1 / -1;
}

.field span {
  font-size: 0.82rem;
  color: var(--muted);
}

.field input,
.field textarea {
  width: 100%;
  border: 1px solid var(--line-soft);
  background: #100e0c;
  border-radius: 12px;
  padding: 0.75rem 0.8rem;
}

.field textarea {
  min-height: 120px;
  resize: vertical;
}

.contact-aside {
  display: grid;
  gap: 0.8rem;
}

.aside-card {
  padding: 1rem;
  border-radius: 16px;
  background: var(--raised);
  border: 1px solid var(--line-soft);
}

.aside-card h3 {
  margin: 0 0 0.35rem;
  font-size: 1.1rem;
}

.aside-card p,
.aside-card a {
  margin: 0;
  color: var(--muted);
  text-decoration: none;
}

.aside-card a {
  color: var(--gold);
}

.site-footer {
  padding-block: 2.4rem 1.4rem;
  border-top: 1px solid var(--line-soft);
  background: var(--bg-deep);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr 1fr 1fr;
  gap: 1.4rem;
}

.footer-grid h3 {
  margin: 0 0 0.6rem;
  font-size: 0.95rem;
  font-family: Inter, sans-serif;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.footer-grid a,
.footer-grid p {
  display: block;
  color: var(--muted);
  text-decoration: none;
  margin: 0 0 0.35rem;
}

.legal {
  margin-top: 1.6rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line-soft);
  color: var(--muted);
  font-size: 0.82rem;
}

.photo-frame {
  position: relative;
  display: block;
  overflow: hidden;
  line-height: 0;
}

.photo-frame img {
  display: block;
  width: 100%;
}

.split-visual > .photo-frame,
.plate > .photo-frame,
.cutaway-frame > .photo-frame{
  height: 100%;
}

.photo-info,
.photo-info-tip {
  position: absolute;
  right: 0.55rem;
  bottom: 0.55rem;
  z-index: 8;
  margin: 0;
  color: #fff;
  cursor: pointer;
}

.photo-info {
  display: grid;
  place-items: center;
  width: auto;
  height: auto;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
  font-family: "Source Serif 4", Georgia, serif;
  font-size: 0.78rem;
  font-style: italic;
  font-weight: 600;
  line-height: 1;
  text-shadow: 0 1px 6px rgb(0 0 0 / 0.7);
}

.photo-info:hover,
.photo-info:focus-visible {
  color: #fff;
  opacity: 0.8;
}

.photo-info-tip {
  display: none;
  width: max-content;
  max-width: none;
  padding: 0.12rem 0.32rem;
  border: 0;
  border-radius: 4px;
  background: rgb(0 0 0 / 0.55);
  font-family: Inter, Arial, sans-serif;
  font-size: 0.58rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.photo-frame.is-open > .photo-info,
.page-hero.is-open > .photo-info,
.service-card.featured.is-open > .photo-info {
  display: none;
}

.photo-frame.is-open > .photo-info-tip,
.page-hero.is-open > .photo-info-tip,
.service-card.featured.is-open > .photo-info-tip {
  display: block;
}


@media (max-width: 980px) {
  .hero-grid,
  .equip-layout,
  .split,
  .partners,
  .coverage-visual,
  .contact-grid,
  .footer-grid,
  .spec-grid,
  .values,
  .process,
  .form {
    grid-template-columns: 1fr;
  }
  .services-grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "featured"
      "a" "b" "c" "d" "e" "f";
  }
  .cutaway-frame img,
  .map-frame {
    height: 420px;
    min-height: 420px;
  }
  
  .spec dd { white-space: normal; }
  .partners .checklist li { white-space: normal; }
  .cutaway-legend {
    position: static;
    width: auto;
    margin: 0.75rem 0.75rem 0.85rem;
  }
  .cutaway-keys {
    grid-template-columns: 1fr 1fr;
  }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { animation: none !important; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(16px); }
  to { opacity: 1; transform: translateY(0); }
}

.reveal {
  animation: rise 700ms var(--ease) both;
  animation-timeline: view();
  animation-range: entry 8% cover 28%;
}


  .page-hero {
    position: relative;
    overflow: visible;
    padding-block: 5.4rem 4.4rem;
    background:
      /* Option B. The mockup faded to 28% at the right edge, where the lede
         still runs; over the lit chrome of the machines that dropped the
         worst pixel to 3.2:1 against a 4.5:1 minimum. Measured across the
         twelve inner pages, 16 of 48 page/text combinations failed there
         and 1 fails here, while the photograph stays readable. */
      linear-gradient(90deg, rgba(8, 7, 6, 0.92) 0%, rgba(8, 7, 6, 0.70) 48%, rgba(8, 7, 6, 0.45) 100%),
      var(--page-hero-image, url("../images/maqueta/mod-hero.webp")) center / cover;
  }

  /* The hero photograph variants are prefixed. They used to be bare words --
 * .page-hero.partners -- and `partners` is also the mockup's class for the
 * panel on the home page, whose `.partners > div { max-width: 34rem }`
 * then caught the hero's .wrap and squeezed the whole For Partners hero
 * into a 544px column in the middle of the page. */
.page-hero.hero-partners {
    --page-hero-image: url("../images/maqueta/mod-hydro-clean.webp");
  }

  /* Its own crop, not the shared mod-front-a. In the shared framing the
     machine's left edge lands at hero x=381 while the text starts at 343 --
     the hardest vertical edge in the picture, a luminance jump of 77 against
     30-odd for every other, sitting directly under the first word. Shifted
     150 px, a tenth of the width, it moves to 214 and the heading begins on
     flat bodywork. background-position cannot do this: at wide sizes cover
     scales these images by width, so they fill the frame exactly and there is
     no slack to pan into. Regenerate with tools/shift-hero.py. */
  .page-hero.hero-services {
    --page-hero-image: url("../images/hero-services.webp");
  }

  .page-hero.hero-about {
    --page-hero-image: url("../images/maqueta/mod-tech.webp");
  }

  .page-hero.hero-coverage {
    --page-hero-image: url("../images/maqueta/mod-lineup.webp");
  }

  .page-hero.hero-contact {
    --page-hero-image: url("../images/maqueta/sa-front.webp");
  }

  .page-hero h1 {
    max-width: 18ch;
    margin: 0.7rem 0 1rem;
    padding-block-start: 0.08em;
    font-size: clamp(2.2rem, 4.6vw, 3.7rem);
    line-height: 1.12;
  }

  .page-hero .lede {
    max-width: 42rem;
    line-height: 1.7;
    font-size: 1.08rem;
    color: color-mix(in srgb, var(--cream) 88%, var(--muted));
  }

  .system-tiles {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1.1rem;
  }

  .system-tile {
    container-type: inline-size;
    overflow: hidden;
    border-radius: 18px;
    border: 1px solid var(--line-soft);
    background: var(--panel);
  }

  .system-tile img {
    inline-size: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
  }

  .system-tile div {
    padding: 0.95rem 1rem 1.1rem;
  }

  .system-tile h3 {
    margin: 0 0 0.35rem;
    font-size: 1.15rem;
  }

  .system-tile p {
    margin: 0;
    color: var(--muted);
    font-size: 0.9rem;
  }

  .workorder {
    display: grid;
    grid-template-columns: 0.95fr 1.05fr;
    gap: 1.4rem;
    align-items: stretch;
  }

  .workorder-sheet {
    padding: 1.2rem 1.25rem;
    border-radius: 18px;
    background: #16110d;
    border: 1px solid var(--line);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.78rem;
    color: var(--muted);
  }

  .workorder-sheet header {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
    color: var(--gold);
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .workorder-sheet ol {
    margin: 0;
    padding-inline-start: 1.1rem;
    display: grid;
    gap: 0.55rem;
  }

  .workorder-sheet li {
    color: color-mix(in srgb, var(--cream) 86%, var(--muted));
    font-family: Inter, sans-serif;
    font-size: 0.92rem;
  }

  .photo-steps {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.7rem;
  }

  .photo-steps figure {
    margin: 0;
    position: relative;
    overflow: hidden;
    border-radius: 16px;
    border: 1px solid var(--line-soft);
    min-height: 160px;
  }

  .photo-steps img {
    width: 100%;
    height: 100%;
    min-height: 160px;
    object-fit: cover;
  }

  .photo-steps figcaption {
    position: absolute;
    inset-inline: 0.6rem;
    bottom: 0.6rem;
    padding: 0.35rem 0.55rem;
    border-radius: 999px;
    background: color-mix(in srgb, #100c09 78%, transparent);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.68rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--gold);
  }

  .county-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
  }

  .county-card {
    padding: 1.1rem;
    border-radius: 16px;
    background: var(--raised);
    border: 1px solid var(--line-soft);
  }

  .county-card span {
    color: var(--gold);
    font-family: "IBM Plex Mono", ui-monospace, monospace;
    font-size: 0.68rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
  }

  .county-card h3 {
    margin: 0.4rem 0 0.4rem;
    font-size: 1.2rem;
  }

  .county-card p {
    margin: 0;
    color: var(--muted);
  }

  .faq {
    display: grid;
    gap: 0.7rem;
  }

  .faq details {
    padding: 0.95rem 1rem;
    border-radius: 14px;
    border: 1px solid var(--line-soft);
    background: var(--panel);
  }

  .faq summary {
    cursor: pointer;
    font-weight: 600;
  }

  .faq p {
    margin: 0.6rem 0 0;
    color: var(--muted);
  }

  .cta-band {
    display: grid;
    grid-template-columns: 1.2fr auto;
    gap: 1.6rem;
    align-items: center;
    padding: 1.7rem 1.8rem;
    border-radius: 20px;
    border: 1px solid var(--line);
    background: linear-gradient(120deg, #1a140f, #100d0a);
  }

  .page-partners {
    --container: 1180px;
  }

  .page-partners .split-visual {
    min-height: 380px;
  }

  .page-partners .split-visual img {
    min-height: 380px;
    aspect-ratio: 4 / 3;
  }

  .page-partners .split-compact {
    margin-top: 2.8rem;
    align-items: center;
  }

  .page-partners .split-compact .split-visual,
  .page-partners .split-compact .split-visual img {
    min-height: 260px;
    aspect-ratio: 16 / 10;
  }

  .page-partners .split-compact h3 {
    margin: 0 0 0.7rem;
    font-size: clamp(1.45rem, 2.2vw, 1.85rem);
  }

  .page-partners .section-inset {
    background: #090807;
  }

  .page-partners .list-heading {
    margin: 1.5rem 0 0.7rem;
    font-size: 1.15rem;
    font-family: Inter, sans-serif;
    letter-spacing: 0.02em;
  }

  .page-partners .section-cta {
    padding-block: 0 5.25rem;
  }

  .page-partners .section-cta h2 {
    margin: 0.45rem 0 0.65rem;
    font-size: clamp(1.7rem, 3vw, 2.45rem);
  }

  

  .page-partners .system-tile div {
    padding: 1.1rem 1.15rem 1.25rem;
  }

  .page-partners .ticket h3 {
    font-size: 1.12rem;
    line-height: 1.28;
  }

  .page-partners .cta-row {
    margin-top: 1.5rem;
  }

  @media (max-width: 1100px) {
    .process {
      grid-template-columns: 1fr 1fr;
    }
  }

  @media (max-width: 980px) {
    .system-tiles,
    .county-grid,
    .workorder,
    .photo-steps,
    .cta-band {
      grid-template-columns: 1fr;
    }

    .page-partners .split,
    .page-partners .split-compact {
      gap: 1.4rem;
    }
  }

/* was @layer utilities */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}


/* ==========================================================================
   Additions made during the port. Nothing above this line was authored here.
   ========================================================================== */

/* was @layer components */
/* ---- Mobile navigation -------------------------------------------------
   The mockup simply hid .nav below 980px, which left a phone with no way
   to reach any page but the one it landed on. This is that menu, drawn
   with the mockup's own tokens so it reads as part of the same design. */

.menu-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  /* flex: the header is a flex row and would otherwise shrink this below
     the 44px minimum touch target. */
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--cream);
  cursor: pointer;
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}

.menu-toggle:hover,
.menu-toggle[aria-expanded="true"] {
  color: var(--gold);
  border-color: var(--gold-soft);
}

.menu-toggle svg {
  width: 20px;
  height: 20px;
  stroke: currentColor;
  stroke-width: 1.9;
  fill: none;
  stroke-linecap: round;
}

.menu-toggle .icon-close { display: none; }
.menu-toggle[aria-expanded="true"] .icon-open { display: none; }
.menu-toggle[aria-expanded="true"] .icon-close { display: block; }

@media (max-width: 980px) {
  .menu-toggle { display: inline-flex; }

  

  .nav {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.5rem 0 0.9rem;
    background: color-mix(in srgb, var(--bg) 97%, transparent);
    backdrop-filter: blur(16px);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow);
  }

  .nav.is-open { display: flex; }

  .nav a {
    padding: 0.85rem calc((100vw - min(100vw - 2.4rem, var(--container))) / 2 + 0.1rem);
    min-height: 44px;
    display: flex;
    align-items: center;
    font-size: 0.95rem;
    border-bottom: 1px solid var(--line-soft);
  }

  .nav a:last-child { border-bottom: 0; }

  
}

@media (max-width: 460px) {
  
  .brand img { width: 32px; height: 32px; }
}

/* ---- Legacy page compatibility ----------------------------------------
   Seven pages still carry the previous theme's markup: the five individual
   service pages, Resources and Privacy Policy. The mockup never covered
   them, so until each one is rebuilt these rules map the old class names
   onto the new tokens. They are a bridge, not a design — delete each block
   as its page gets ported. */

.content-section {
  width: min(100% - 2.4rem, var(--container));
  margin-inline: auto;
  padding-block: 3.25rem;
}

.content-section + .content-section { padding-top: 0; }

.card-kicker {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  margin-bottom: 0.55rem;
  color: var(--gold);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.content-section > h2,
.content-split > div > h2 {
  font-family: "Source Serif 4", Georgia, serif;
  font-size: clamp(1.7rem, 3vw, 2.45rem);
  line-height: 1.14;
  letter-spacing: -0.01em;
  margin: 0 0 0.9rem;
}

.content-section h3 {
  font-family: "Source Serif 4", Georgia, serif;
  font-size: 1.2rem;
  margin: 0 0 0.5rem;
}

.content-lead {
  color: color-mix(in srgb, var(--cream) 88%, var(--muted));
  max-width: 46rem;
  font-size: 1.12rem;
  line-height: 1.7;
}

/* Some seeds put content-lead on the <section> itself. Left alone, the
   46rem reading measure then shrinks the whole band instead of the prose
   inside it, and the section stops lining up with its neighbours. */
.content-section.content-lead { max-width: none; }
.content-section.content-lead > * { max-width: 46rem; }

.content-section p { color: var(--muted); line-height: 1.72; }

.content-split {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 2.2rem;
  align-items: start;
}

.content-card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

.content-card-grid--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.content-card,
.content-panel {
  padding: 1.2rem;
  border-radius: var(--radius);
  border: 1px solid var(--line-soft);
  background: linear-gradient(145deg, rgba(28, 22, 17, 0.97), rgba(16, 14, 12, 0.98));
}

.check-list,
.issue-list {
  display: grid;
  gap: 0.45rem;
  margin: 1.1rem 0 0;
  padding: 0;
  list-style: none;
}

.check-list li,
.issue-list li {
  position: relative;
  padding-inline-start: 1.1rem;
  color: color-mix(in srgb, var(--cream) 88%, var(--muted));
}

.check-list li::before,
.issue-list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.62em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--copper);
}

.faq-section details {
  border-bottom: 1px solid var(--line-soft);
  padding: 0.95rem 0;
}

.faq-section summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 44px;
  font-family: "Source Serif 4", Georgia, serif;
  font-size: 1.08rem;
  color: var(--cream);
}

.faq-section summary::-webkit-details-marker { display: none; }

.faq-section summary::after {
  content: "+";
  color: var(--gold);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 1.2rem;
  line-height: 1;
}

.faq-section details[open] summary::after { content: "\2212"; }

.faq-section details > p { margin: 0.6rem 0 0; }

.legal-content { max-width: 46rem; }
.legal-content h2 { margin-top: 2rem; }


.button--whatsapp {
  background: #1f7a4d;
  color: #fff;
  border-color: transparent;
}

@media (max-width: 980px) {
  .content-split,
  .content-card-grid,
  .content-card-grid--three {
    grid-template-columns: 1fr;
  }
}


/* was @layer components */
/* ---- Working-form parts the mockup had no equivalent for --------------- */

/* Bot bait. Must stay reachable to a script and invisible to a person, so
   it is moved off-canvas rather than display:none. */
.form-honeypot {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-success,
.form-error {
  margin: 0 0 1rem;
  padding: 0.9rem 1.05rem;
  border-radius: 14px;
  border: 1px solid var(--line-soft);
  line-height: 1.6;
}

.form-success {
  background: rgba(141, 164, 119, 0.12);
  border-color: rgba(141, 164, 119, 0.4);
  color: var(--cream);
}

.form-error {
  background: rgba(201, 118, 62, 0.12);
  border-color: rgba(201, 118, 62, 0.45);
  color: var(--cream);
}

.photo-upload input[type="file"] {
  width: 100%;
  padding: 0.65rem 0.8rem;
  border: 1px dashed var(--line);
  border-radius: 12px;
  background: #100e0c;
  color: var(--muted);
  font-size: 0.86rem;
}

.photo-upload small {
  display: block;
  margin-top: 0.35rem;
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.5;
}

/* The button sits in a .field, which is a grid; without this it stretches
   the full column width instead of sizing to its label. */
.form .field.full > .button { justify-self: start; }

/* ---- Skip link --------------------------------------------------------- */
/* .sr-only hides it until a keyboard reaches it, which is the whole point. */
.sr-only:focus-visible {
  position: fixed;
  top: 0.7rem;
  left: 0.7rem;
  z-index: 60;
  width: auto;
  height: auto;
  clip: auto;
  padding: 0.7rem 1rem;
  border-radius: 999px;
  background: var(--copper);
  color: #fff;
  text-decoration: none;
}

/* ---- Visible keyboard focus -------------------------------------------- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}


/* was @layer components */
/* ======================================================================
   Three pieces the previous theme had and the mockup never drew. Restored
   at the user's request, styled with the mockup's own tokens.
   ====================================================================== */

/* ---- Breadcrumbs ------------------------------------------------------ */

.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-bottom: 1rem;
  /* Was IBM Plex Mono. A monospaced breadcrumb reads as a file path rather
     than as a trail through the site, and at 11px the mono face is the least
     legible thing on the page. */
  font-family: Inter, Arial, sans-serif;
  font-size: 0.8rem;
  font-weight: 500;
  letter-spacing: 0.01em;
  color: var(--muted);
}

.breadcrumbs a {
  /* --muted alone measured 4.30:1 against the brightest part of the
     Coverage hero photograph, just under the 4.5 minimum. Lifting it
     a quarter of the way to cream clears every hero at 5.1:1, and the
     trail still reads as secondary to the headline. */
  color: color-mix(in srgb, var(--cream) 30%, var(--muted));
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color 180ms var(--ease), border-color 180ms var(--ease);
}

.breadcrumbs a:hover {
  color: var(--gold);
  border-bottom-color: var(--gold-soft);
}

/* 55% of an already mid grey measured 3.42:1 -- the one outright AA
   failure left on the site. It is a slash, but it is still read. */
.breadcrumbs > span[aria-hidden] { color: color-mix(in srgb, var(--cream) 20%, var(--muted)); }

.breadcrumbs > span:last-child { color: color-mix(in srgb, var(--cream) 75%, var(--muted)); }

/* ---- Card marks in the footer ----------------------------------------- */

.site-footer .legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.1rem;
}

.card-marks {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.card-mark {
  display: block;
  width: 38px;
  height: 24px;
  border-radius: 3.2px;
  /* The marks are drawn on white by the networks' own guidelines; on this
     ground they need the faint edge or they float. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12);
}

/* ---- Quick Chat -------------------------------------------------------- */

.chat-widget {
  position: fixed;
  right: 1.15rem;
  bottom: 1.15rem;
  z-index: 45;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.6rem;
}

.chat-launcher {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 48px;
  padding: 0.7rem 1.15rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: linear-gradient(135deg, #c67a38, #a95e28);
  color: #fff;
  font-size: 0.88rem;
  font-weight: 600;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: transform 180ms var(--ease);
}

.chat-launcher:hover { transform: translateY(-1px); }

.chat-launcher-icon {
  display: inline-flex;
  width: 18px;
  height: 18px;
}

.chat-launcher-icon svg { width: 100%; height: 100%; fill: currentColor; }

.chat-panel {
  width: min(21rem, calc(100vw - 2.3rem));
  border-radius: 20px;
  border: 1px solid var(--line);
  background: var(--panel);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.chat-panel[hidden] { display: none; }

.chat-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.95rem 1.05rem;
  border-bottom: 1px solid var(--line-soft);
  background: var(--panel-warm);
}

.chat-header strong { display: block; font-size: 0.92rem; }

.chat-header span {
  display: block;
  margin-top: 0.15rem;
  color: var(--muted);
  font-size: 0.76rem;
}

.chat-close {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font-size: 1.2rem;
  line-height: 1;
  cursor: pointer;
}

.chat-close:hover { color: var(--gold); }

.chat-body { padding: 1.05rem; }

.chat-bubble {
  padding: 0.75rem 0.85rem;
  border-radius: 14px 14px 14px 4px;
  background: var(--raised);
  border: 1px solid var(--line-soft);
  color: color-mix(in srgb, var(--cream) 88%, var(--muted));
  font-size: 0.88rem;
  line-height: 1.6;
}

.chat-form { display: grid; gap: 0.45rem; margin-top: 0.85rem; }

.chat-form label {
  color: var(--muted);
  font-size: 0.78rem;
}

.chat-form textarea {
  width: 100%;
  border: 1px solid var(--line-soft);
  background: #100e0c;
  border-radius: 12px;
  padding: 0.65rem 0.75rem;
  font-size: 0.9rem;
  resize: vertical;
}

.chat-send { width: 100%; cursor: pointer; }

.chat-body small {
  display: block;
  margin-top: 0.6rem;
  color: var(--muted);
  font-size: 0.74rem;
  line-height: 1.5;
}

/* The launcher would otherwise sit on top of the closing call to action on
   a narrow screen, which is the one button the page is asking for. */
@media (max-width: 640px) {
  .chat-widget { right: 0.8rem; bottom: 0.8rem; }
  .chat-launcher { padding: 0.7rem 0.95rem; font-size: 0.82rem; }
}

.site-footer { padding-bottom: 5.5rem; }


/* was @layer components */
/* ======================================================================
   HEADER RESTORED FROM THE PREVIOUS SITE
   The mockup replaced the logo lockup with a small bean and a line of
   letterspaced type, and dropped Resources from the bar. These are the
   values that were live, copied across: the crop geometry of both halves
   of the lockup, the bar colours, the gold rule under the current page and
   the outlined phone pill. Only two things differ on purpose -- the bar is
   sticky rather than fixed, which needs no compensating padding on every
   page below it, and the menu button carries a close icon.
   ====================================================================== */

.site-header {
  /* was rgba(11,10,8,.96) over a fixed bar; sticky reaches the same place */
  background: rgba(11, 10, 8, 0.96);
  border-bottom: 1px solid rgba(208, 137, 62, 0.2);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.28);
  backdrop-filter: blur(14px);
}

.nav-wrap {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  min-height: 76px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  min-width: 0;
  text-decoration: none;
}

.brand-symbol,
.brand-wordmark {
  position: relative;
  flex: 0 0 auto;
  display: block;
  overflow: hidden;
  background: transparent;
}

.brand-symbol { width: 43px; height: 50px; }

.brand-symbol img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: contain;
  /* No filter. The two tints are baked into the file, because a CSS filter
     cannot colour two parts of one raster differently: the artwork carries
     gold for the bean outline and near-white for the machine drawn inside it.
     An earlier draft of this port copied the gold filter from the previous
     stylesheet and missed the `filter: none` that overrode it further down,
     which flattened both tints into one gold and lost the machine. */
}

.brand-wordmark { width: 194px; height: 44px; }

.brand-wordmark img {
  position: absolute;
  left: -27px;
  top: -229px;
  width: 243px;
  max-width: none;
  height: auto;
  filter: brightness(0) invert(1);
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 21px;
}

.nav-links a {
  color: #e8e1da;
  font-size: 0.84rem;
  font-weight: 600;
  text-decoration: none;
  transition: color 180ms var(--ease);
}

.nav-links a:hover { color: #d39249; }

/* The page you are on. A colour change alone is a contrast judgement the
   reader has to make against six other items, so it also carries a rule
   under it -- and aria-current means a screen reader says "current page". */
.nav-links a[aria-current="page"] {
  position: relative;
  color: #d39249;
  font-weight: 700;
}

.nav-links a[aria-current="page"]::after {
  content: "";
  position: absolute;
  right: 0;
  bottom: -7px;
  left: 0;
  height: 2px;
  border-radius: 2px;
  background: #bd7333;
}

.nav-links .nav-call {
  padding: 11px 19px;
  border: 1px solid rgba(208, 137, 62, 0.35);
  border-radius: 999px;
  color: #fff;
  font-size: 0.82rem;
  font-weight: 650;
}

.nav-links .nav-call[aria-current="page"]::after { content: none; }
.nav-links .nav-call:hover { border-color: rgba(208, 137, 62, 0.6); color: #fff; }

@media (max-width: 1100px) {
  .brand-wordmark { width: 165px; }
  .brand-wordmark img { left: -22px; top: -190px; width: 205px; }
  .nav-links { gap: 12px; }
  .nav-links a { font-size: 0.75rem; }
  .nav-links .nav-call { padding: 9px 14px; }
}

@media (max-width: 900px) {
  .nav-wrap { min-height: 68px; }
  .brand-symbol { width: 39px; height: 45px; }
  .brand-wordmark { width: 178px; height: 42px; }
  .brand-wordmark img { left: -24px; top: -206px; width: 220px; }

  .menu-toggle { display: inline-flex; order: 3; }

  .nav-links {
    position: absolute;
    top: 68px;
    right: 0;
    left: 0;
    display: none;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: 0.5rem 0 0.9rem;
    border-bottom: 1px solid rgba(208, 137, 62, 0.21);
    background: rgba(11, 10, 8, 0.98);
    box-shadow: var(--shadow);
  }

  .nav-links.is-open { display: flex; }

  .nav-links a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0.85rem 0;
    color: #eee7df;
    font-size: 0.84rem;
    border-bottom: 1px solid var(--line-soft);
  }

  .nav-links a:last-child { border-bottom: 0; }

  /* The rule under the current item belongs beside six siblings, not
     stacked in a column where every row already has a divider. */
  .nav-links a[aria-current="page"]::after { content: none; }

  .nav-links .nav-call {
    align-self: flex-start;
    margin-top: 0.7rem;
    min-height: 44px;
    border-bottom: 1px solid rgba(208, 137, 62, 0.35);
  }
}

@media (max-width: 620px) {
  .brand-wordmark { display: block; width: 142px; height: 38px; }
  .brand-wordmark img { left: -19px; top: -164px; width: 177px; }
  .brand-symbol { width: 35px; height: 42px; }
}


/* ---- Footer wordmark ----------------------------------------------------
   Same crop as the header, from the same file, painted white. The mockup put
   the whole lockup in a plain <img> at 120px with no filter -- the artwork is
   dark strokes on transparency, so on this ground it was invisible. */

.footer-mark {
  position: relative;
  display: block;
  width: 194px;
  height: 44px;
  margin-bottom: 0.9rem;
  overflow: hidden;
}

.footer-mark img {
  position: absolute;
  left: -27px;
  top: -229px;
  width: 243px;
  max-width: none;
  height: auto;
  filter: brightness(0) invert(1);
}

@media (max-width: 620px) {
  .footer-mark { width: 165px; height: 38px; }
  .footer-mark img { left: -22px; top: -190px; width: 205px; }
}

/* ---- Hero cutaway: caption vs the spec bar -------------------------------
   Two faults, one visible symptom -- the caption under the hero photograph
   colliding with the spec bar below it.

   1. photo-note.js wraps every image in a .photo-frame at runtime, and that
      wrapper is height:100% of .cutaway-frame. Below 980px the legend leaves
      absolute positioning and joins the flow, so the frame becomes auto-height
      and the percentage turns circular: grid sized the row at 603px while the
      column actually laid out at 787px, and the 92px difference spilled over
      the spec bar. Sizing the wrapper to its image removes the circularity.

   2. .spec-bar carries margin-top:-1.2rem by design, which rode 3px over the
      caption even in the original mockup. The caption now reserves its own
      room instead. */

@media (max-width: 980px) {
  .cutaway-frame > .photo-frame { height: auto; }
}

.cutaway-active { margin-bottom: 1.4rem; }

/* ==========================================================================
   FOOTER RESTORED FROM THE PREVIOUS SITE
   Five columns instead of the mockup's four: Coverage comes back, which is
   where the county names sit on every page. Contact carries its icons again,
   and the bottom bar its copyright, card marks and legal links. Values copied
   from the stylesheet that was live.
   ========================================================================== */

.site-footer {
  padding: 52px 0 0;
  border-top: 1px solid rgba(208, 137, 62, 0.21);
  background: #0a0907;
  color: #aa9f95;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.55fr 0.95fr 0.95fr 0.95fr 1.15fr;
  gap: 40px;
}

.footer-intro p {
  max-width: 250px;
  margin-top: 16px;
  color: #a29890;
  font-size: 0.86rem;
  line-height: 1.65;
}

.footer-grid strong {
  display: block;
  margin-bottom: 18px;
  color: var(--gold-soft);
  font-family: Inter, Arial, sans-serif;
  font-size: 0.76rem;
  font-weight: 800;
  /* line box pinned so the five columns stay aligned */
  line-height: 1.056rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.footer-links,
.footer-contact {
  display: grid;
  align-content: start;
  gap: 11px;
}

.footer-links a,
.footer-links--coverage span {
  color: #cfc6be;
  font-size: 0.86rem;
  text-decoration: none;
}

.footer-links--coverage a {
  margin-top: 5px;
  color: var(--gold-soft);
}

.footer-contact a,
.footer-contact > span {
  display: flex;
  gap: 11px;
  align-items: flex-start;
  color: #cfc6be;
  font-size: 0.86rem;
  line-height: 1.45;
  text-decoration: none;
}

.footer-contact svg {
  flex: 0 0 auto;
  width: 15px;
  height: 15px;
  margin: 2px 0 0;
  color: var(--gold-soft);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* The WhatsApp glyph is a filled path, not a stroked one. */
.footer-contact .button-icon {
  fill: currentColor;
  stroke: none;
}

.site-footer a:hover { color: var(--gold-soft); }

.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 25px;
  margin-top: 46px;
  /* the extra bottom room clears the Quick Chat launcher */
  padding: 20px 0 5.2rem;
  border-top: 1px solid rgba(208, 137, 62, 0.16);
  color: #8e847b;
  font-size: 0.8rem;
  line-height: 1.152rem;
}

.footer-legal { display: flex; gap: 30px; }
.site-footer .footer-bottom a { color: #8e847b; font-size: 0.8rem; text-decoration: none; }
.site-footer .footer-bottom a:hover { color: var(--gold-soft); }

/* The card acceptance marks are trademarks and are not ours to rescale on a
   whim; 38x24 is the box the networks publish them in. */
.card-marks { display: flex; gap: 8px; align-items: center; }
.card-mark {
  display: block;
  width: 38px;
  height: 24px;
  border-radius: 3.2px;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.12);
}

.footer-mark { margin-bottom: 0; }

@media (max-width: 1100px) {
  .footer-grid { grid-template-columns: 1.35fr 1fr 1fr; gap: 34px 30px; }
}

@media (max-width: 620px) {
  .footer-grid { grid-template-columns: 1fr; gap: 30px; }
  .footer-bottom { align-items: flex-start; flex-direction: column; gap: 12px; }
  .footer-legal { gap: 24px; }
}

/* ==========================================================================
   COVERAGE MAP
   Redrawn from real coordinates and styled after the previous site's coverage
   artwork: near-black water, a thin glowing copper shoreline, the covered
   counties washed in warm light that falls off inland, city nodes that glow.
   The mockup's flat eight-point blob is gone.
   ========================================================================== */


/* the peninsula itself, a shade above the water so the coast reads even
   where no county sits on top of it */


/* ---- regions ------------------------------------------------------------ */

.county {
  cursor: pointer;
  transition: opacity 220ms var(--ease), filter 220ms var(--ease);
}

.county.primary {
  fill: url(#wash-primary);
  stroke: rgba(232, 167, 101, 0.45);
  stroke-width: 0.9;
}


/* the Keys are a chain, so their region is the stroke, not a fill */


.county:hover,
.county:focus-visible,
.county.is-active {
  opacity: 1;
  filter: brightness(1.35);
  outline: none;
}

.counties:hover .county:not(:hover) { opacity: 0.55; }

/* ---- city nodes --------------------------------------------------------- */


.city text {
  fill: #cfc6be;
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 9.5px;
  letter-spacing: 0.06em;
}


.city.is-active text { fill: var(--cream); }

/* ---- readout and legend ------------------------------------------------- */

.map-frame {
  position: relative;
  overflow: hidden;
  border-radius: 22px;
  border: 1px solid var(--line);
  background: #080706;
}


@media (max-width: 620px) {
  
  
  .city text { font-size: 12px; }
}

/* .county.appoint is two classes and beat the single-class .county-line, so the
   Keys chain was picking up the dashed fill meant for an area region. */


/* The peninsula is tall; without a cap the map runs to 1128px on the coverage
   page and pushes everything below it off the first two screens. */

/* The mockup pinned .map-frame and .map-svg to 420px below 980px, sized for a
   raster tile map. The traced SVG has its own aspect ratio, so the frame now
   follows the drawing instead of cropping 40px off the Keys. */
@media (max-width: 980px) {
  .map-frame { height: auto; min-height: 0; }
  
}

/* ==========================================================================
   FAQ QUESTIONS
   The body sets letter-spacing:-0.011em, which suits Inter at text sizes and
   is wrong for Source Serif at 17px: the serifs already close the gaps, and
   negative tracking on top of that is what made these read as cramped. The
   questions also inherited weight 400, which is thin for a serif on a dark
   ground. Tracking back to normal, weight up to the 600 the rest of the
   site's serif headings use, and the rows given room to breathe.

   Covers both markups: .faq-section on the pages still carrying the previous
   theme's HTML, and .faq on the ones ported from the mockup.
   ========================================================================== */

/* Two different objects, and they were sharing a box model they should not.
   .faq-section, on the pages still carrying the previous theme's HTML, is a
   list of questions separated by rules. .faq, from the mockup, is a stack of
   cards with a background and rounded corners. Setting `padding: .35rem 0` on
   both gave the cards the list's padding: no horizontal room at all, so the
   question sat flush against the edge of its own card. */

.faq-section details {
  border-bottom: 1px solid var(--line-soft);
  padding: 0.35rem 0;
}

.faq details {
  padding: 0.35rem 1.15rem 0.55rem;
  border-radius: 14px;
  border: 1px solid var(--line-soft);
  background: var(--panel);
}

.faq-section summary,
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  min-height: 44px;
  padding: 0.85rem 0;
  cursor: pointer;
  list-style: none;
  font-family: "Source Serif 4", Georgia, serif;
  font-size: 1.16rem;
  font-weight: 600;
  line-height: 1.42;
  letter-spacing: normal;
  color: var(--cream);
  transition: color 180ms var(--ease);
}

.faq-section summary:hover,
.faq summary:hover { color: var(--gold); }

.faq-section summary::-webkit-details-marker,
.faq summary::-webkit-details-marker { display: none; }

.faq-section summary::after,
.faq summary::after {
  content: "+";
  flex: 0 0 auto;
  color: var(--gold);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1;
  transition: transform 200ms var(--ease);
}

.faq-section details[open] summary::after,
.faq details[open] summary::after { content: "\2212"; }

.faq-section details > p,
.faq details > p {
  max-width: 68ch;
  margin: 0 0 0.9rem;
  padding-right: 2.5rem;
  color: var(--muted);
  font-size: 1rem;
  line-height: 1.72;
}

.faq-section h2,
.faq h2 { margin-bottom: 0.6rem; }

/* ==========================================================================
   TRACKING ON SMALL SERIF HEADINGS
   h1/h2/h3 all carry letter-spacing:-0.025em. That is right for the display
   sizes -- a 50px headline needs the gaps closed -- and wrong once the same
   rule lands on an 18px card title, where Source Serif's own serifs already
   fill the space. Card and panel titles get their tracking back.

   Same reasoning as the FAQ questions: the negative tracking is a display
   setting that leaked down into text sizes.
   ========================================================================== */

.value-card h3,
.aside-card h3,
.service-card h3,
.system-tile h3,
.ticket h3,
.county-card h3,
.content-card h3,
.content-panel h3,
.footer-grid h3,
.chat-header strong,
.cutaway-active strong,
.spec dd {
  letter-spacing: normal;
}

/* Anything serif under ~28px is text, not display. This catches the headings
   the list above does not name, without touching the big ones. */
h3 { letter-spacing: -0.008em; }

/* The lede and card copy sit at text sizes too; the body's -0.011em is a
   little tight on the serif italic used in the hero. */
.hero h1 em { letter-spacing: -0.015em; }

/* ==========================================================================
   COVERAGE MAP -- built over the artwork
   The photograph already carries the coastline, the county tints and the
   glowing nodes. This layers invisible hit areas over the counties and labels
   over the nodes, so the picture behaves like a map without redrawing it.
   Overlay coordinates are the artwork's own pixel space (1672x941).
   ========================================================================== */


/* Invisible until pointed at. The artwork already shows which counties are
   covered; the overlay is for picking one, not for re-colouring the map. */


/* ---- node labels -------------------------------------------------------- */


/* the artwork's own glow sits under this, so the ring only needs to mark the
   exact point the label belongs to */


/* labels on the Atlantic side read outward, the Gulf one reads inward */

/* The frame no longer needs a fixed height: the figure carries the artwork's
   aspect ratio, so it sizes itself. */
.map-frame { height: auto; min-height: 0; padding: 0; }


@media (max-width: 980px) {
  .map-frame { height: auto; min-height: 0; }
}


/* ==========================================================================
   SERVICE-AREA MAP
   Artwork + HTML. The picture carries the geography, the two service rings and
   the city dots; every piece of type over it is markup, so it scales,
   translates, responds to a reader's own font size and gets indexed. The
   illustration arrives with its lettering burned in and
   tools/strip-map-text.py takes it back out.

   Sizes are in cqw -- percent of the map's own width, not the window's. The
   map is half a column on the front page and a full one on the service-area
   page, and a label has to stay the same size relative to the dot it names in
   both. clamp() then holds the ends: no label smaller than it can be read at,
   none larger than the artwork can carry.
   ========================================================================== */

.map-frame--html { height: auto; min-height: 0; padding: 0; border: 0; background: none; }

.coverage-map { margin: 0; display: grid; gap: 1.25rem; }

.coverage-map__canvas {
  position: relative;
  aspect-ratio: 1672 / 941;
  border-radius: 20px;
  overflow: hidden;
  border: 1px solid var(--line-soft);
  background: #070605;
}

.coverage-map__artwork {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
}

/* The figure is the container the type measures itself against, and the frame
   the caption is positioned inside. */
.coverage-map--satellite {
  display: block;
  position: relative;
  container-type: inline-size;
}

/* ---- city labels -------------------------------------------------------- */

/* Set in the body face, sentence case, the way the hero's proof list is set --
   David picked that off the live page. Uppercase mono read as a schematic
   legend; these are place names, and place names have shapes a reader
   recognises before reading them. It is also about a fifth narrower, which is
   what lets seventeen of them sit on a corrected map that is tighter than the
   illustration was. */
.coverage-map__node {
  position: absolute;
  transform: translate(0, -50%);
  pointer-events: none;
  white-space: nowrap;
  font-family: Inter, Arial, sans-serif;
  font-size: clamp(0.72rem, 1.5cqw, 0.92rem);
  letter-spacing: 0.005em;
  line-height: 1;
  /* The artwork under a label runs from black water to lit coastline, so the
     shadow does the work a plate would: two of them, one tight for the edge
     and one wide for the ground. */
  text-shadow: 0 1px 4px #000, 0 0 10px rgba(0, 0, 0, 0.92);
  padding-left: 0.78cqw;
}

.coverage-map__node--left {
  transform: translate(-100%, -50%);
  padding-left: 0;
  padding-right: 0.78cqw;
}

/* The dot is in the picture. Tinting the name to match it means a reader never
   has to carry a colour back to the key. */
.coverage-map__node--in { color: #fff7e6; }
/* Outside the ring. Dimmer, and still on the map, because these are places the
   company travels to by appointment rather than places it refuses -- deleting
   them would say the wrong thing. */
.coverage-map__node--out { color: #c9c1b8; }
.coverage-map__node b { font-weight: 500; }

/* The artwork gives Miami the larger dot. The name follows it, so the eye
   lands on the middle of the market first. */
.coverage-map__node--key { font-size: clamp(0.84rem, 1.78cqw, 1.08rem); }
.coverage-map__node--key b { font-weight: 600; }

/* ---- the two seas ------------------------------------------------------- */

.coverage-map__sea {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 9cqw;
  min-width: 5.5rem;      /* two lines, never three */
  text-align: center;
  pointer-events: none;
  font-family: Inter, Arial, sans-serif;
  font-size: clamp(0.6rem, 1.1cqw, 0.78rem);
  font-style: italic;
  letter-spacing: 0.3em;
  text-indent: 0.3em;       /* tracking hangs off the last letter; recentre it */
  line-height: 2.2;
  color: rgba(190, 209, 228, 0.5);
}

/* ---- title and key ------------------------------------------------------ */

.coverage-map--satellite .coverage-map__copy {
  /* Below the map, not on it. It sat over the Gulf while the ground was a
     fixed picture and there was reliably nothing under it; on a map the reader
     can pan, every position is eventually the wrong one -- the block ends up
     covering the very streets somebody zoomed in to read. Out here it also
     stops competing with the two rings, which are the only marks on the figure
     that carry information. */
  position: static;
  width: auto;
  margin-top: 1.15rem;
  /* Inset from the frame. .map-frame clips whatever leaves it, and this block
     used to start at exactly its left edge -- so the key's ring, which carries a
     2px spread and a 10px glow, had all twelve of those pixels cut off down one
     side. The bottom was flush too. Padding is the fix rather than unclipping
     the frame: that clip is what keeps the map's corners inside the radius. */
  padding: 0 clamp(0.9rem, 2.2cqw, 1.5rem) clamp(0.85rem, 2cqw, 1.35rem);
}

.coverage-map__rule {
  display: block;
  position: relative;
  height: 1px;
  background: linear-gradient(90deg, rgba(224, 170, 98, 0.9), rgba(224, 170, 98, 0));
}

.coverage-map__rule::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: #fff8ec;
  transform: translate(0, -50%);
  box-shadow: 0 0 8px rgba(255, 240, 214, 0.85);
}

.coverage-map--satellite .coverage-map__title {
  margin: 0.55rem 0 0;
  font-size: clamp(1.3rem, 3.1cqw, 2rem);
  /* Room for descenders. This title is painted with background-clip: text, so a
     glyph is only visible where the element's own background box reaches -- and
     at line-height 1.05 the tail of a "g" fell outside it and simply was not
     drawn. It went unnoticed for as long as the title read "Service Area",
     which has no descender in it; "Coverage" was the first. */
  line-height: 1.2;
  padding-bottom: 0.18em;
  letter-spacing: -0.005em;
  color: var(--cream);
}

/* The reference artwork set this title in brushed metal. Kept, but only where
   the browser can clip a gradient to the glyphs -- without the guard an
   unsupporting one paints transparent text on a dark map. */
@supports (background-clip: text) or (-webkit-background-clip: text) {
  .coverage-map--satellite .coverage-map__title {
    background: linear-gradient(178deg, #fbf5ea 0%, #e4d5bb 38%, #b39d7c 72%, #8a7457 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
  }
}

.coverage-map__legend { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.8rem; }

.coverage-map--satellite .coverage-map__legend {
  margin-top: 1.1rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 0.9rem 1.8rem;
  align-items: start;
}

.coverage-map__legend-item {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  column-gap: 1.5cqw;
  row-gap: 0.2rem;
  font-size: clamp(0.8rem, 1.3cqw, 0.95rem);
  color: var(--muted);
  line-height: 1.45;
}

.coverage-map__legend-item i {
  width: 2cqw;
  min-width: 13px;
  aspect-ratio: 1;
  border-radius: 50%;
  background: none;
}

/* Two cues, not one: the ring colour differs and so does its weight, so the
   pair survives a reader who cannot separate gold from ember. */
.coverage-map__legend-item--area i {
  border: 2px solid #ef7a1e;
  box-shadow: 0 0 0 2px rgba(239, 122, 30, 0.28), 0 0 10px rgba(239, 122, 30, 0.4);
}

.coverage-map__legend-item b {
  font-family: Inter, Arial, sans-serif;
  font-weight: 600;
  letter-spacing: 0.005em;
  color: var(--cream);
  white-space: nowrap;
}

/* ---- narrow maps --------------------------------------------------------
   Keyed to the map, not the window: on the front page it is a 680 px column at
   a 1440 px window, and a window-width rule would have called that desktop.

   Under 560 px the caption cannot sit on the artwork -- there is no water left
   to put it on -- so it drops underneath and goes back to fixed sizes. */

@container (max-width: 520px) {
  .coverage-map--satellite .coverage-map__copy {
    position: static;
    width: auto;
    margin-top: 1.15rem;
  }
  .coverage-map--satellite .coverage-map__title { margin-top: 0.5rem; font-size: 1.5rem; }
  .coverage-map--satellite .coverage-map__legend { margin-top: 1rem; gap: 0.9rem; }
  .coverage-map__legend-item { column-gap: 0.6rem; font-size: 0.9rem; }
  .coverage-map__legend-item i { width: 13px; }
  .coverage-map__rule { max-width: 8rem; }
  /* Eighteen names will not fit across a phone. The secondary ones go; the
     full list stays in the key underneath, which is what a screen reader and a
     search engine were reading anyway. */
  .coverage-map__node--minor { display: none; }
  .coverage-map__node { font-size: 0.58rem; letter-spacing: 0.04em; }
  .coverage-map__sea { display: none; }
}

/* ==========================================================================
   VERTICAL GRIDS BESIDE A TALLER COLUMN
   A grid column stretches to its sibling's height by default, and auto rows
   then divide that height between them. Beside the contact form -- which is
   tall -- that gave four cards a quarter of the column each, so "Email" was a
   heading, one line, and a hand of empty space underneath.

   align-content: start makes the rows size to their content and leaves the
   surplus at the foot of the column, where it reads as the sidebar simply
   being shorter than the form rather than as four half-empty boxes.
   ========================================================================== */

.contact-aside,
.trust-list {
  align-content: start;
}

/* ==========================================================================
   TWO-COLUMN SPLITS
   .split centred its two columns against each other. Beside a photograph that
   is right -- an image and a paragraph of different heights look wrong flush
   at the top. Beside another column of text it is not: the two headings start
   at different heights and the section reads as though it slipped.

   So the default is now top-aligned and centring is the exception, asked for
   by the presence of a visual. If :has() is unavailable the whole thing falls
   back to top-aligned, which is the safe way round.
   ========================================================================== */

.split { align-items: start; }

.split:has(> .split-visual),
.split:has(> figure) {
  align-items: center;
}

/* ==========================================================================
   PHONE
   Measured at 375x812 against the live site. Nothing here changes how the
   site looks on a desktop; it fixes things that only go wrong under a thumb.
   ========================================================================== */

/* ---- the (i) badge --------------------------------------------------------
   It is drawn as a bare italic "i" with no box, which is 3.6 x 12.5 px -- too
   small to hit on any screen, and this is the control that tells a visitor the
   photographs are illustrations. The glyph stays exactly as it is; what grows
   is the invisible area around it. It is anchored bottom-right, so the box
   expands up and left into the picture and lands on nothing else. */

.photo-info {
  min-width: 44px;
  min-height: 44px;
}

@media (max-width: 900px) {

  /* ---- touch targets ------------------------------------------------------
     The phone number, the e-mail and the WhatsApp link are the actions a
     visitor standing next to a dead machine actually wants, and they were
     20 px tall. The six system keys and the county chips were 30 and 37. */

  .aside-card a,
  .service-card a,
  .cutaway-key,
  .chip {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* The footer columns are a compromise, and worth saying why.
     
     At 44 px the links were comfortably hittable and the column looked wrong
     next to Coverage, whose county names are spans rather than links and so
     stayed at 22 -- two rhythms in one footer, which is what the user kept
     seeing. Matching them at 22 would read correctly and drop every footer
     link below the 24 px minimum for a touch target, on the one screen where
     they are actually touched.

     34 px is the settlement: every row in all four columns is the same height,
     the column reads as one block again, and each link is still comfortably
     over the minimum. Applied to the spans too, so the rhythm comes from the
     row and not from what happens to be inside it. */
  .footer-links > *,
  .footer-contact > * {
    min-height: 34px;
    display: flex;
    align-items: center;
    width: 100%;
  }

  .footer-links,
  .footer-contact {
    gap: 0;
  }

  /* The column heading is not a row of the list and does not need the height. */
  .footer-links > strong,
  .footer-contact > strong,
  .footer-grid h3 {
    min-height: 0;
  }

  .cutaway-key,
  .chip {
    justify-content: center;
  }

}

/* ==========================================================================
   THE COVERAGE MAP ON A PHONE
   At 352 px wide the 16:9 artwork is a 198 px strip and a city label computes
   to 8.7 px, which is not reading, it is decoration pretending to be
   information. So the names go and the frame gets taller, which lets the
   picture be read at all.

   4:3 rather than the portrait crop the drawn artwork took, because this one
   has content edge to edge: at this aspect the background covers to 469 px and
   40% shows the artwork from x=167 to x=1422 -- Key West at one end, Port St.
   Lucie at the other. A 3:4 crop centred on the peninsula would have thrown
   away the Keys, which is half of what the map is here to say.

   Nothing is lost. Which cities are same-day and which are next-day is spelled
   out in the section's own copy directly above, in real text.

   Asked of the map and not the window, because the two stopped agreeing when
   the map became half a column on the front page and a whole one on the
   service-area page.
   ========================================================================== */

@container (max-width: 420px) {
  .coverage-map__canvas { aspect-ratio: 4 / 3; }
  .coverage-map__artwork { background-position: 40% center; }
  .coverage-map__node,
  .coverage-map__sea { display: none; }
  /* The key is the whole of the map's information here, so it gets the room it
     needs rather than being squeezed under the picture. */
  .coverage-map--satellite .coverage-map__legend { gap: 0.95rem; }
  .coverage-map__legend-item { font-size: 0.9rem; }
}

/* ==========================================================================
   FOOTER COLUMN SPACING
   The link lists ran a 39 px pitch on 13.8 px text: small type with large air
   between it, which reads as four loose lists rather than four columns. Closing
   the gap groups each column into one block the eye takes in at once.

   Scoped above the phone breakpoint on purpose -- under it the opposite is
   wanted, where each row has to be big enough to hit. That rule sits earlier in
   this file, so this one has to say where it applies or it would override it.
   ========================================================================== */

@media (min-width: 901px) {
  .footer-links,
  .footer-contact {
    row-gap: 4px;
  }

  /* The column heading sat 18 px clear of its first link, which is more space
     than separates the links from each other once they are closed up. */
  .footer-links strong,
  .footer-contact strong,
  .footer-grid h3 {
    margin-bottom: 10px;
  }
}

/* ==========================================================================
   A SECTION HEADING INSIDE A COLUMN
   47 px is the size of a section head on this site, and it is right when the
   heading owns the full width with a photograph beside it -- which is every
   other .split on the site. The FAQ on Services is the one place where both
   columns carry a heading, and there it sat at 47 px next to a 19 px one: two
   and a half times the size, so the pair read as a page title beside a caption
   rather than as two columns of the same section.

   2rem is not a new size -- it is the one .cta-band already uses for a heading
   that sits below a section head rather than being one.
   ========================================================================== */

.split .faq h2 {
  font-size: 2rem;
  line-height: 1.22;
}

/* ==========================================================================
   THE SYSTEM CAPTION ESCAPED ITS PICTURE ON A PHONE

   .system-visual is sticky on a desktop, and sticky makes it the containing
   block for the caption inside it, which is absolutely positioned at the foot
   of the photograph. The phone rule turned it static to stop it sticking --
   and static is not a containing block, so the caption stopped resolving
   against its own figure and resolved against a distant ancestor instead.

   It landed 2,700 px above where it belongs, floating over the hero image:
   "Pumps - boilers - pressure" sitting on a photograph it has nothing to do
   with, while its own picture had no caption at all.

   relative instead of static: it still does not stick, and it is a containing
   block again. Nothing else on the site has this problem -- the other three
   static overrides have no absolutely positioned children.
   ========================================================================== */

@media (max-width: 980px) {
  /* top:auto matters. The base rule pairs sticky with top:92px, and top only
     takes effect on a sticky box once it sticks -- but on a relative box it
     offsets it always. Without this the figure sits 92 px lower than its own
     row, which is a gap of dead space above the photograph. */
  
}

/* The caption sits on a photograph, so it needs its own ground to be read
   against -- the same treatment the hero badge already uses. */


/* ==========================================================================
   THE FOOTER LINKS CARRIED A MARGIN THE SPANS DID NOT
   .footer-grid a still had margin-bottom .35rem from before these columns were
   grids. Once they became grids with their own row-gap the margin stacked on
   top of it, so the three columns made of links ran a 31.6 px pitch while the
   Coverage column -- whose county names are spans, not links -- ran 26. Same
   markup intent, two different rhythms, side by side.
   ========================================================================== */

.footer-links a,
.footer-contact a,
.footer-links--coverage span {
  margin-bottom: 0;
}

/* The one link in the Coverage column is set off from the county names above
   it on purpose; it keeps its own space. */
.footer-links--coverage a { margin-top: 6px; }

/* ==========================================================================
   SECTION RHYTHM ON A PHONE
   5.25rem top and bottom is the desktop measure, and two of them meeting adds
   up to 168 px of nothing between one section and the next on a 375 px screen
   -- most of a phone's height spent scrolling past a gap. Two thirds of it
   reads the same on that screen without running the sections together.
   ========================================================================== */

@media (max-width: 700px) {
  
  .hero { padding-block: 2rem 1rem; }
}

/* ==========================================================================
   SPACE BETWEEN SECTIONS
   Sections carried 5.25rem top and bottom, so every seam between two of them
   was 168 px on a desktop and 104 px on a phone. Eight seams on the home page
   is over a thousand pixels of nothing, and the reader pays for it in scroll
   before reaching anything.

   3.75rem and 2.25rem: the seams become 120 and 72, still wide enough that one
   section clearly ends before the next begins, without the page pausing.
   scroll-margin-top follows so the in-page anchors still clear the sticky
   header by the same margin they always did.
   ========================================================================== */

.section {
  padding-block: 3.75rem;
  scroll-margin-top: 5.5rem;
}

@media (max-width: 700px) {
  .section { padding-block: 2.25rem; }
}

/* ==========================================================================
   THE HERO VEIL WAS A RAMP WHERE IT NEEDED TO BE A PLATEAU

   NOTE: keep the fallback inside var(--page-hero-image, url(...)). Only five
   of the twelve inner pages set that custom property; on the other seven the
   var resolves to nothing, which makes the whole background shorthand invalid
   at computed-value time and the hero renders with no photograph at all. This
   rule shipped without it once and Resources, Privacy and the five service
   pages lost their image.
   The overlay ran .92 at the left edge to .45 at the right, evenly. Measured
   against the artwork behind it, that leaves the background under the heading
   swinging from 0.003 to 0.023 in luminance -- the photograph's own bright
   panel showing through the middle of the text. Contrast was never the problem
   (12:1 at the worst point); evenness was. A headline crossing from black onto
   a lit panel reads as an edge running through the words.

   So the veil is now flat across the column the text occupies and only opens
   up past it. The picture still breathes on the right, where nothing is set.
   ========================================================================== */

.page-hero {
  background:
    linear-gradient(90deg,
      rgba(8, 7, 6, 0.94) 0%,
      rgba(8, 7, 6, 0.91) 45%,
      rgba(8, 7, 6, 0.62) 72%,
      rgba(8, 7, 6, 0.34) 100%),
    var(--page-hero-image, url("../images/maqueta/mod-hero.webp")) center / cover;
}

/* On a phone the text runs the full width of the hero, so it crosses the whole
   ramp -- the veil that is right behind a 1220 px column centred in 1920 is the
   wrong shape when the column is the screen. Nearly flat there. Legibility was
   never at risk either way (8.4:1 at the worst point measured), but the text
   should not sit on a background that visibly brightens under its own last
   few words. */

@media (max-width: 700px) {
  .page-hero {
    background:
      linear-gradient(90deg,
        rgba(8, 7, 6, 0.93) 0%,
        rgba(8, 7, 6, 0.90) 60%,
        rgba(8, 7, 6, 0.82) 100%),
      var(--page-hero-image, url("../images/maqueta/mod-hero.webp")) center / cover;
  }
}

/* Inside a card the paragraph already has the card's own right padding; the
   2.5rem was reserving room for the +/- marker in the borderless list. */
.faq details > p { padding-right: 0.5rem; }

/* 21 px between a 32 px heading and the first card read as the two touching. */
.faq h2 { margin-bottom: 1rem; }

/* ==========================================================================
   THE PREPARE / FAQ SPLIT ON SERVICES
   Three things were fighting each other here.

   The proportions were backwards. .split runs 1.15fr / 0.85fr, so the wide
   column held six short bullets -- about 280 px of text in a 622 px column --
   while the FAQ, which is the only thing on the row with paragraphs in it, was
   squeezed into 563. Flipped for this row, the list gets a sane measure and
   the answers stop wrapping early.

   The two column headings sat at different ranks: an h3 at 19 px beside an h2
   at 32. They are the same kind of thing to a reader -- the title of a column
   -- so they are now the same size. 1.75rem clears the 18.6 px questions and
   the 16.3 px bullets by enough to lead them without shouting.

   And the bullets are held to a readable measure instead of running the full
   width of whatever column they land in.
   ========================================================================== */

.split:has(> .faq) {
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
}

.split:has(> .faq) > div > h2,
.split:has(> .faq) > div > h3,
.split .faq h2 {
  font-size: 1.75rem;
  line-height: 1.24;
  letter-spacing: normal;
  margin-bottom: 1rem;
}

.split:has(> .faq) .checklist {
  max-width: 34ch;
}

@media (max-width: 980px) {
  /* One column below here, so the proportions stop mattering and the list can
     have the width back. */
  .split:has(> .faq) { grid-template-columns: minmax(0, 1fr); }
  .split:has(> .faq) .checklist { max-width: none; }
}

/* ==========================================================================
   LINE LENGTH
   Three paragraphs were running the full 1220 px of their container: the
   coverage footnote at 166 characters a line, the "commercial environments"
   note on the espresso page at 150, and the copy in the featured service card
   at 100. Somewhere past about 80 the eye starts losing its place on the
   return sweep and rereads a line, which is the thing that makes long copy
   feel like work.

   Capped in ch rather than px so the measure holds when the type scales.
   max-width only ever narrows, so inside an already-narrow column these are
   no-ops -- nothing else on the site moves.
   ========================================================================== */

.content-section > p,
.content-section > .content-lead {
  max-width: 72ch;
}

.footnote {
  max-width: 68ch;
}

/* The featured card spans two columns of the services grid, so its paragraph
   gets twice the width of every card beside it. */
.service-card p {
  max-width: 52ch;
}

/* ==========================================================================
   THE (i) ON THE PAGE HERO, ON A PHONE
   It marks a photograph as an illustration so nobody reads it as a record of
   real work. On a phone the hero photograph is under a 93%-82% veil, and
   measured against the artwork that leaves the background varying 1.9x across
   the whole hero with every value within a hair of pure black -- 0.0028 to
   0.0053, against 0.0022 for the bare colour. There is no picture to mistake.
   On a desktop the same hero runs 6.1x and the photograph plainly reads, so
   the badge stays there.

   It also had nowhere to sit: with the veil that heavy the hero is mostly
   empty below the buttons, and the badge floated 40 px under the last thing
   on the page, attached to nothing.

   Only the hero. Every badge over a photograph that is actually visible on a
   phone -- the machines, the system tiles, the work-order shots -- stays.
   ========================================================================== */

@media (max-width: 700px) {
  .page-hero > .photo-info,
  .page-hero > .photo-info-tip {
    display: none;
  }
}

/* ==========================================================================
   THE HERO'S OWN PADDING ON A PHONE
   5.4rem top and 4.4rem bottom is a desktop measure, where the hero carries a
   breadcrumb, a kicker, a heading, a lede and two buttons across 1220 px and
   the air is proportionate. On a phone the same padding leaves 93 px of empty
   hero under the buttons, and the section below adds its own 36 on top of
   that: 129 px between the last thing a reader can act on and the next thing
   worth reading.

   3.5rem and 1.75rem. The top still clears the sticky header comfortably --
   56 px below a 69 px bar -- and the foot stops running on. Desktop is
   untouched; the user checked it and it is right there.
   ========================================================================== */

@media (max-width: 700px) {
  .page-hero {
    padding-block: 3.5rem 1.75rem;
  }
}

/* ==========================================================================
   WHATSAPP
   Green because the reader recognises it before reading the label, which for
   somebody standing next to a machine that stopped is the point.

   Outlined rather than filled on the page buttons, on purpose. Two filled
   buttons side by side are two primary actions, and a page with two primary
   actions has none -- the copper stays the one filled thing and the green
   says what the second one is instead of being a grey ghost.

   Two different greens, because they do different jobs. WhatsApp's own
   #25D366 is built for white backgrounds and gives 2.0:1 with white text on
   this ground -- it fails outright. So does the site's --sage at 2.7:1.

     text on the dark ground   #5f9e57   6.1:1   (#4a7c45 falls to 4.0:1)
     fill under white text     #42734a   5.6:1, and 3.6:1 against the page

   The launcher is filled: it is WhatsApp and nothing else, it competes with
   nothing beside it, and it was wearing copper -- the colour this site uses
   for its primary action -- while not being one.
   ========================================================================== */

:root {
  --wa-line: #5f9e57;
  --wa-fill: #42734a;
  --wa-fill-deep: #35603c;
}

.button-ghost[href*="wa.me"],
.button--whatsapp {
  border-color: color-mix(in srgb, var(--wa-line) 62%, transparent);
  color: var(--wa-line);
  background: transparent;
}

.button-ghost[href*="wa.me"]:hover,
.button--whatsapp:hover {
  border-color: var(--wa-line);
  background: color-mix(in srgb, var(--wa-fill) 18%, transparent);
  color: #86bd7c;
}

.button-ghost[href*="wa.me"] .button-icon,
.button--whatsapp .button-icon {
  fill: currentColor;
}

/* ---- the floating launcher --------------------------------------------- */

.chat-launcher {
  background: linear-gradient(135deg, var(--wa-fill), var(--wa-fill-deep));
}

.chat-send {
  background: linear-gradient(135deg, var(--wa-fill), var(--wa-fill-deep));
  color: #fff;
}

/* ==========================================================================
   THE FORM'S OWN NOTICES
   The shortcode emits the notice and the form as siblings, and they land
   inside a two-column grid -- so after a successful send the notice took the
   first cell as a tall, nearly empty box and pushed the form into the second,
   with the contact cards dropped underneath. The message that matters most on
   that screen looked like a layout accident.

   Spanning every column puts it where a banner belongs: across the top, with
   the form and the cards back in their own columns underneath.
   ========================================================================== */

/* The notice now lives inside .form-column with the form it belongs to, so it
   no longer needs to span the grid -- it sits directly above the form, which
   is where it reads best anyway. */

.form-column {
  display: grid;
  align-content: start;
  gap: 0.9rem;
}

/* ==========================================================================
   LIVE SERVICE-AREA MAP
   The Google map that maqueta-coverage-live.js builds over the artwork. It
   loads with the page, so this is what a reader normally sees; the artwork
   underneath is the fallback for no key, spent quota or an unreachable Google,
   and in each of those cases the class below is never added and none of these
   rules apply.
   ========================================================================== */

.map-live {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: var(--bg-deep);
}

/* The city names are pinned to the artwork's fixed projection -- they would be
   pointing at the wrong places one drag into a live map. They go only once the
   map is really there, so a reader who never gets Google keeps them, and they
   stay in the markup either way. */
.coverage-map--live .coverage-map__node,
.coverage-map--live .coverage-map__sea {
  display: none;
}

/* The city names drawn on the live map. Google gives the label element this
   class and nothing else, so the shadow has to come from here -- and it has to,
   because these sit on ground that runs from black water to a lit coastline and
   a plain fill disappears over half of it. */
.map-live__label {
  text-shadow: 0 1px 3px #000, 0 0 9px rgba(0, 0, 0, 0.95);
}

/* Google's own zoom control, toned down to the site's palette. Left alone it
   is a white pill on a dark map, which is the brightest thing on the figure. */
.map-live .gm-bundled-control button {
  background: rgba(13, 11, 9, 0.9) !important;
}
.map-live .gm-bundled-control img { filter: invert(1) opacity(0.75); }

/* ---- map key: radii and the third line ---------------------------------- *
   The key gained a description under each title when the circles started being
   drawn from real numbers. The number is the point: "within 66 miles of Miami"
   is a promise a reader can hold the map to, which "the yellow zone" never was.

   The item is a two-column grid -- swatch, then title -- so the description has
   to be told to skip the swatch column or it lands underneath it. */
.coverage-map__legend-item span {
  grid-column: 2;
  font-size: 0.86em;
  line-height: 1.4;
  color: var(--muted);
  text-wrap: pretty;
}

/* Not a zone, so not a ring. A reader who has just learned that a circle means
   a service level should not meet a third circle that means something else;
   the rule reads as "and beyond this", which is what it is. */
.coverage-map__legend-item--beyond i {
  aspect-ratio: auto;
  height: 2px;
  border-radius: 1px;
  align-self: center;
  background: linear-gradient(90deg, var(--gold-soft), rgba(211, 146, 73, 0.15));
}

.coverage-map__legend-item--beyond b { color: var(--gold); }

@media (max-width: 900px) {
  /* On a phone the map is cropped and the key carries the whole message, so
     the first two descriptions are worth their room. The third is a sentence
     of prose; it stays, because it is the only line here aimed at the reader
     who is outside both circles. */
  .coverage-map__legend-item span { font-size: 0.82em; }
}
