/* ==========================================================================
   site.css — neutral starter

   HOW TO USE THIS FILE
   1. Swap the tokens in :root for the client's brand. That is the whole job
      for colour and type; the components below all read from the tokens.
   2. Self-host fonts as woff2 (@fontsource), never the Google Fonts CDN.
   3. Do NOT hardcode a colour anywhere below :root. If you find yourself
      typing a hex value in a component, add a token instead — a hardcoded
      colour in a component silently overrides the palette on the next build
      and it is miserable to track down.
   4. After swapping tokens, check nothing is orphaned:
      grep -o 'var(--[a-z-]*' css/site.css | sort -u
   ========================================================================== */

/* @font-face { font-family: 'Display'; font-weight: 700; font-display: swap;
     src: url('../fonts/display-700.woff2') format('woff2'); } */

/* ---- Self-hosted woff2 via @fontsource. Never the Google Fonts CDN. ---- */
@font-face{font-family:'Oswald';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/oswald-latin-400-normal.woff2') format('woff2');}
@font-face{font-family:'Oswald';font-style:normal;font-weight:500;font-display:swap;
  src:url('../fonts/oswald-latin-500-normal.woff2') format('woff2');}
@font-face{font-family:'Oswald';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/oswald-latin-600-normal.woff2') format('woff2');}
@font-face{font-family:'Open Sans';font-style:normal;font-weight:400;font-display:swap;
  src:url('../fonts/open-sans-latin-400-normal.woff2') format('woff2');}
@font-face{font-family:'Open Sans';font-style:italic;font-weight:400;font-display:swap;
  src:url('../fonts/open-sans-latin-400-italic.woff2') format('woff2');}
@font-face{font-family:'Open Sans';font-style:normal;font-weight:600;font-display:swap;
  src:url('../fonts/open-sans-latin-600-normal.woff2') format('woff2');}
@font-face{font-family:'Open Sans';font-style:normal;font-weight:700;font-display:swap;
  src:url('../fonts/open-sans-latin-700-normal.woff2') format('woff2');}

:root {
  /* ---- Frontier Metal Stamping — PANTONE 285 / CMYK 91-43-0-0 ---- */
  --ink:        #1a1d21;   /* headings + primary text */
  --body-ink:   #2a2f36;   /* long-form body copy */
  --accent:     #0077C8;   /* PANTONE 285. CTAs, active states, rules */
  --accent-ink: #005a99;   /* hover / pressed */
  --link:       #1a1d21;
  --link-hover: #0077C8;
  --paper:      #ffffff;
  --panel:      #eef1f4;
  --rule:       #dde2e6;
  --soft:       #5a6470;
  --band:       #292929;   /* dark band, matches the masthead they keep */
  --band-text:  #f2f4f6;
  --band-body:  #e4e9ee;
  --panel-soft: #f6f8fa;
  --star:       #E8A317;

  /* ---- Type: Oswald headings, Open Sans body. Self-hosted woff2. ---- */
  --display: 'Oswald', 'Arial Narrow', Arial, sans-serif;
  --body:    'Open Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --body-size: 16px;
  --body-line-height: 28px;

  /* ---- Heading scale. Oswald 600, uppercase, per the measured original ---- */
  --h-weight: 600;
  --h1-size: 40px; --h2-size: 30px; --h3-size: 24px;
  --h4-size: 20px; --h5-size: 18px; --h6-size: 16px;
  --h1-letter-spacing: 0.005em;
  --h-letter-spacing: 0.01em;
  --h-margin-bottom: 1.5rem;
  --h-margin-top: 2.25rem;

  --wrap: 1140px;          /* matches the current site's content width */
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { font-family: var(--body); background: var(--paper); color: var(--body-ink);
  font-size: var(--body-size); line-height: var(--body-line-height);
  -webkit-font-smoothing: antialiased; }
img, svg { max-width: 100%; }
.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 28px; }

/* ---------- Headings ----------
   Bottom margin AND top margin. Bottom alone leaves every heading crowded
   against the paragraph above it, which reads as a bug on a real page. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--display); font-weight: var(--h-weight); color: var(--ink);
  letter-spacing: var(--h-letter-spacing); line-height: 1.4;
  margin-bottom: var(--h-margin-bottom); margin-top: var(--h-margin-top);
}
h1 { font-size: var(--h1-size); letter-spacing: var(--h1-letter-spacing); margin-top: 0; }
h2 { font-size: var(--h2-size); }
h3 { font-size: var(--h3-size); }
h4 { font-size: var(--h4-size); }
h5 { font-size: var(--h5-size); }
h6 { font-size: var(--h6-size); }
main > section > .wrap > *:first-child { margin-top: 0; }

p { margin: 0 0 1.1rem; }
p.lede { font-size: 1.06rem; color: var(--soft); max-width: 78ch; }
a { color: var(--link); }
a:hover { color: var(--link-hover); }
ul, ol { margin: 0 0 1.1rem 1.2rem; }
li { margin-bottom: .45rem; }

.skip { position: absolute; left: -9999px; top: 0; background: var(--accent);
  color: #fff; padding: 10px 18px; z-index: 200; font-weight: 700; }
.skip:focus { left: 0; }

/* ---------- Header ----------
   Mirrors the existing site: brushed-metal band, stacked logo left, quote
   button and phone right, dark nav strip with the cyan rule under it.
   Two deliberate departures, both in CHANGE-REGISTER.md:
     - the band compresses on scroll instead of holding 255px forever
     - it shrinks hard at mobile widths so the fold is not all chrome
   ------------------------------------------------------------------ */
/* White masthead. Mark's call, 26 Aug: the brushed metal competed with the
   blue mark and dated the page. On white the logo carries the header on its
   own. CHANGE-REGISTER.md entry 6. */
/* Scroll anchoring OFF for the document.
 *
 * The masthead is sticky at top:0, so its slot in flow sits above everything.
 * Compressing it removes 131px from that slot — 259px tall expanded, 128px
 * compact. Chrome reads that as "content above the viewport changed size" and
 * silently corrects scrollTop by the same 131px to hold the view steady.
 *
 * That correction is larger than the gap between the compress and expand
 * thresholds, so it throws the header across its own trigger: compact at 142,
 * anchoring drops you to 14, 14 expands it, anchoring puts you back at 145,
 * which compacts it again. The result is a header flickering at frame rate.
 *
 * Turning anchoring off is safe here specifically because every <img> on the
 * site carries intrinsic width and height, so images cannot reflow the page as
 * they load — which is the shift anchoring exists to absorb. Remove this and
 * the jitter comes straight back.
 */
html { overflow-anchor: none; }

#site-header { position: sticky; top: 0; z-index: 70; }

.masthead {
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
.masthead-in { display: flex; align-items: center; justify-content: space-between;
  gap: 20px; padding-top: 18px; padding-bottom: 16px;
  transition: padding .18s ease; }
.logo { display: block; line-height: 0; }
.logo svg, .logo img { display: block; height: 224px; width: auto;
  transition: height .18s ease; }

/* Blue lockup on white. No halo needed now the texture is gone. */

.masthead-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 12px; }
.btn-quote { background: var(--accent); color: #fff; border-color: var(--accent);
  /* Was .84rem lowercase in 11px/20px of padding, which made the primary call
     to action the smallest, lightest text in the header while occupying the
     largest block of colour. Uppercase, heavier, larger, and tighter padding:
     more word, less blue. */
  font-size: .98rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .05em; line-height: 1.15; text-align: center;
  padding: 12px 22px; }
.btn-quote:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
.phone-top { font-family: var(--display); font-weight: 600; font-size: 1.45rem;
  color: var(--ink); text-decoration: none; white-space: nowrap; }
.phone-top:hover { color: var(--accent); }
.phone-ico { margin-right: 8px; font-size: .95em; }

/* Compressed state, set by js/site.js once the page scrolls past the band. */
.hdr-compact .masthead-in { padding-top: 8px; padding-bottom: 7px; }
.hdr-compact .logo svg, .hdr-compact .logo img { height: 112px; }
.hdr-compact .masthead-actions { flex-direction: row; align-items: center; gap: 22px; }
.hdr-compact .phone-top { font-size: 1.2rem; }
.hdr-compact .btn-quote { padding: 10px 18px; font-size: .88rem; }
.hdr-compact .masthead { box-shadow: 0 6px 20px rgba(0,0,0,.10); }

/* A sticky header hides whatever an in-page link lands on. Every anchor target
   gets pushed clear of it, so /tooling/#break-even does not open with the
   calculator's heading under the nav strip. */
:target { scroll-margin-top: 200px; }
html { scroll-padding-top: 200px; }

.navbar { background: var(--band); z-index: 60;
  border-bottom: 3px solid var(--accent); }
.navbar nav { display: flex; gap: 44px; padding: 18px 0; flex-wrap: wrap; justify-content: center; }
.navbar a { color: #fff; text-decoration: none; font-family: var(--display);
  font-weight: 400; font-size: 1.05rem; letter-spacing: .03em; text-transform: uppercase; }
.navbar a:hover { color: #08C7FC; }
.navbar a[aria-current="page"] { color: #08C7FC; }
.navbar.stuck { box-shadow: 0 4px 18px rgba(0,0,0,.28); }
.nav-toggle { display: none; }

/* ---------- Interior page hero ---------- */
.page-hero { background: var(--ink); color: #fff; }
.page-hero .wrap { padding-top: 34px; padding-bottom: 34px; }
.page-hero h1 { color: #fff; margin-bottom: .6rem; max-width: 24ch; }
.page-hero .lede { color: var(--band-body); max-width: 62ch; margin-bottom: 0; }
.crumbs { font-size: .84rem; color: var(--band-text); margin-bottom: 14px; letter-spacing: .02em; }
.crumbs a { color: var(--band-text); text-decoration: none; }
.crumbs a:hover { color: #fff; text-decoration: underline; }
.crumbs .sep { opacity: .55; margin: 0 6px; }


/* ---------- Buttons ---------- */
.btn { display: inline-block; background: var(--accent); color: #fff; padding: 15px 28px;
  text-decoration: none; font-family: var(--display); font-weight: 700;
  letter-spacing: .03em; border-radius: 3px; border: 0; cursor: pointer;
  transition: background .15s ease, transform .15s ease; }
.btn:hover { background: var(--accent-ink); color: #fff; transform: translateY(-2px); }
.btn-sm { padding: 11px 20px; font-size: .92rem; }
.btn-ghost { background: transparent; color: var(--ink); box-shadow: inset 0 0 0 2px var(--ink); }
.btn-ghost:hover { background: var(--ink); color: #fff; }
/* On any dark band a ghost button must reverse, or it is invisible. This bit
   the promo band on the first build: dark text on a dark ground. */
.promo .btn-ghost { color: #fff; box-shadow: inset 0 0 0 2px rgba(255,255,255,.75); }
.promo .btn-ghost:hover { background: #fff; color: var(--ink); box-shadow: inset 0 0 0 2px #fff; }
.cta-row { display: flex; gap: 14px; flex-wrap: wrap; }

/* ---------- Sections ---------- */
section { padding: 44px 0; }
section.tint { background: var(--panel-soft); }
section.final { background: var(--ink); color: #fff; }
section.final h2 { color: #fff; }
section.final .lede { color: var(--band-text); }
section.final .btn-ghost { color: #fff; box-shadow: inset 0 0 0 2px #fff; }
section.final .btn-ghost:hover { background: #fff; color: var(--ink); }
.aside-note { font-size: .88rem; color: var(--band-text); margin-top: 14px; }

/* ---------- Cards ---------- */
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 22px; }
.card { border: 1px solid var(--rule); border-top: 4px solid var(--ink);
  border-radius: 4px; padding: 24px; background: var(--paper); }
.card h3 { margin-top: 0; }

/* ---------- Panel ---------- */
.panel { background: var(--panel); border-radius: 4px; padding: 22px 26px; margin: 22px 0; }
.panel > :last-child { margin-bottom: 0; }

/* ---------- Coverage bars ----------
   A picture made of real text. Search engines and AI assistants read every
   word of this, it weighs nothing, it stays sharp on any screen, and when the
   terms change it changes in one place. A JPEG of the same idea does none of
   those things. Widths are inline styles because they encode the DATA, not
   the design — 48 months is twice the bar of 24 months, and that proportion
   is the whole argument. */
.bars { margin: 28px 0; }
.bars .row { margin-bottom: 18px; }
.bars .row:last-child { margin-bottom: 0; }
.bars .lbl { display: flex; justify-content: space-between; gap: 12px; align-items: baseline;
  flex-wrap: wrap; margin-bottom: 6px; }
.bars .who { font-family: var(--display); font-weight: 700; font-size: 1.02rem; color: var(--ink); }
.bars .term { font-size: .92rem; color: var(--soft); font-weight: 600; }
.bars .track { background: var(--rule); border-radius: 3px; height: 26px; overflow: hidden; }
.bars .fill { height: 100%; background: var(--soft); border-radius: 3px; }
.bars .row.us .who { font-size: 1.18rem; }
.bars .row.us .term { color: var(--accent); font-weight: 700; }
.bars .row.us .fill { background: var(--accent); }
.bars .scale { display: flex; justify-content: space-between; font-size: .78rem; color: var(--soft);
  border-top: 1px solid var(--rule); padding-top: 6px; margin-top: 16px; letter-spacing: .03em; }

/* Photo with a caption that does work. A caption is the cheapest place on a
   page to put a fact, and it is read far more often than body copy. */
figure.shot { margin: 28px 0; }
figure.shot img { display: block; width: 100%; height: auto; border-radius: 4px; }
figure.shot figcaption { font-size: .9rem; color: var(--soft); line-height: 1.6; margin-top: 10px;
  border-left: 3px solid var(--accent); padding-left: 12px; }
figure.shot.right { float: right; width: 42%; margin: 6px 0 24px 36px; }
figure.shot.left  { float: left;  width: 42%; margin: 6px 36px 24px 0; }
@media (max-width: 780px) {
  figure.shot.right, figure.shot.left { float: none; width: 100%; margin: 28px 0; }
}

/* ---------- Star ratings ----------
   Two stacked rows of five stars; the gold row is clipped by percentage, so
   whole numbers and fractions use one code path. The stars are decorative and
   aria-hidden — the visible "4.6 out of 5" beside them carries the meaning for
   screen readers, crawlers and AI assistants alike. */
.rate { display: inline-flex; align-items: center; gap: 8px; }
.stars { position: relative; display: inline-block; line-height: 0; white-space: nowrap; }
.stars .s-bg, .stars .s-fg { display: block; white-space: nowrap; }
.stars .s-fg { position: absolute; inset: 0 auto 0 0; overflow: hidden; }
.stars svg { width: 17px; height: 17px; display: inline-block; }
.stars .s-bg svg { fill: var(--rule); }
.stars .s-fg svg { fill: var(--star); }
.rate-text { font-size: .84rem; font-weight: 700; color: var(--soft); white-space: nowrap; }

/* ---------- Review cards ---------- */
.revs { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 22px; margin-top: 26px; }
.rev { margin: 0; background: var(--paper); border: 1px solid var(--rule);
  border-top: 4px solid var(--star); border-radius: 4px; padding: 22px 24px;
  display: flex; flex-direction: column; }
.rev blockquote { margin: 14px 0 16px; }
.rev blockquote p { margin: 0; color: var(--body-ink); font-size: .97rem; line-height: 1.65; }
.rev blockquote p::before { content: "\201C"; }
.rev blockquote p::after { content: "\201D"; }
.rev figcaption { margin-top: auto; border-top: 1px solid var(--rule); padding-top: 12px; }
.rev figcaption b { display: block; font-family: var(--display); font-weight: 700;
  font-size: 1rem; color: var(--ink); }
.rev figcaption span { font-size: .82rem; color: var(--soft); }
.rev figcaption a, .rev blockquote a { color: var(--accent); font-weight: 600; }
.rev-all { margin: 22px 0 0; font-weight: 600; }

/* Placeholder standing in for artwork that has not arrived. Deliberately
   unmissable — nothing here should ever survive to launch by accident. */
.ph { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; text-align: center; padding: 18px; border: 2px dashed var(--accent);
  border-radius: 4px; background: repeating-linear-gradient(45deg,
    var(--panel-soft), var(--panel-soft) 12px, var(--paper) 12px, var(--paper) 24px); }
.ph b { font-family: var(--display); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--accent); font-size: 1rem; }
.ph span { font-size: .86rem; color: var(--soft); line-height: 1.4; max-width: 34ch; }
.ph .dim { font-weight: 700; letter-spacing: .06em; }

/* ---------- Coupons ----------
   Text, not a JPEG. The offer, the terms and the expiry are all real words a
   search engine and an AI assistant can read, and the code is something a
   customer says out loud to a service advisor instead of printing. */
.coupons { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 22px; margin-top: 28px; }
.coupon { background: var(--paper); border: 1px solid var(--rule);
  border-radius: 4px; overflow: hidden; display: flex; flex-direction: column; }
/* The red shout, at H1 size. This is the badge off the old print artwork,
   rebuilt as live text — same job, but readable by a search engine. */
.coupon .shout { background: var(--accent); color: #fff; padding: 16px 22px;
  font-family: var(--display); font-weight: var(--h-weight);
  font-size: var(--h1-size); line-height: 1.08; text-transform: uppercase;
  letter-spacing: var(--h1-letter-spacing); }
.coupon .cbody { padding: 22px 24px 24px; display: flex; flex-direction: column; flex: 1; }
.coupon h3 { margin: 0 0 .4rem; font-size: 1.15rem; }
.coupon .offer { font-family: var(--display); font-weight: 700; font-size: 1.6rem;
  line-height: 1.2; color: var(--accent); margin: 0 0 .9rem; }
.coupon .code { margin: 0 0 .9rem; font-size: .9rem; color: var(--soft); }
.coupon .code b { display: inline-block; font-family: var(--display); font-size: 1.15rem;
  letter-spacing: .12em; color: var(--ink); background: var(--panel);
  padding: 3px 12px; border-radius: 3px; margin-left: 6px; }
.coupon .code .ref { display: block; font-size: .72rem; color: var(--soft);
  letter-spacing: .04em; margin-top: 5px; font-weight: 600; }
.coupon .incl { list-style: none; margin: 0 0 .9rem; padding: 0; }
.coupon .incl li { font-size: .9rem; color: var(--body-ink); line-height: 1.5;
  padding-left: 16px; position: relative; margin-bottom: .28rem; }
.coupon .incl li::before { content: "\2713"; position: absolute; left: 0;
  color: var(--accent); font-weight: 700; }
.coupon .fine { font-size: .78rem; color: var(--soft); line-height: 1.5; margin: 0 0 .8rem; }
.coupon .exp { font-size: .82rem; color: var(--soft); margin: 0 0 1.1rem; font-weight: 600; }
.coupon .btn { margin-top: auto; align-self: flex-start; }
.coupon .copied { display: block; margin-top: 10px; font-size: .82rem; font-weight: 700;
  color: var(--accent); }
.coupon .copied[hidden] { display: none; }

/* ---------- Star ratings ----------
   Two stacked rows of five stars; the gold row is clipped by percentage, so
   whole numbers and fractions use one code path. The stars are decorative and
   aria-hidden — the visible "4.6 out of 5" beside them carries the meaning for
   screen readers, crawlers and AI assistants alike. */
.rate { display: inline-flex; align-items: center; gap: 8px; }
.stars { position: relative; display: inline-block; line-height: 0; white-space: nowrap; }
.stars .s-bg, .stars .s-fg { display: block; white-space: nowrap; }
.stars .s-fg { position: absolute; inset: 0 auto 0 0; overflow: hidden; }
.stars svg { width: 17px; height: 17px; display: inline-block; }
.stars .s-bg svg { fill: var(--rule); }
.stars .s-fg svg { fill: var(--star); }
.rate-text { font-size: .84rem; font-weight: 700; color: var(--soft); white-space: nowrap; }

/* ---------- Review cards ---------- */
.revs { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 22px; margin-top: 26px; }
.rev { margin: 0; background: var(--paper); border: 1px solid var(--rule);
  border-top: 4px solid var(--star); border-radius: 4px; padding: 22px 24px;
  display: flex; flex-direction: column; }
.rev blockquote { margin: 14px 0 16px; }
.rev blockquote p { margin: 0; color: var(--body-ink); font-size: .97rem; line-height: 1.65; }
.rev blockquote p::before { content: "\201C"; }
.rev blockquote p::after { content: "\201D"; }
.rev figcaption { margin-top: auto; border-top: 1px solid var(--rule); padding-top: 12px; }
.rev figcaption b { display: block; font-family: var(--display); font-weight: 700;
  font-size: 1rem; color: var(--ink); }
.rev figcaption span { font-size: .82rem; color: var(--soft); }
.rev figcaption a, .rev blockquote a { color: var(--accent); font-weight: 600; }
.rev-all { margin: 22px 0 0; font-weight: 600; }

/* Placeholder standing in for artwork that has not arrived. Deliberately
   unmissable — nothing here should ever survive to launch by accident. */
.ph { display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; text-align: center; padding: 18px; border: 2px dashed var(--accent);
  border-radius: 4px; background: repeating-linear-gradient(45deg,
    var(--panel-soft), var(--panel-soft) 12px, var(--paper) 12px, var(--paper) 24px); }
.ph b { font-family: var(--display); font-weight: 700; text-transform: uppercase;
  letter-spacing: .08em; color: var(--accent); font-size: 1rem; }
.ph span { font-size: .86rem; color: var(--soft); line-height: 1.4; max-width: 34ch; }
.ph .dim { font-weight: 700; letter-spacing: .06em; }

/* ---------- Coupons ----------
   Text, not a JPEG. The offer, the terms and the expiry are all real words a
   search engine and an AI assistant can read, and the code is something a
   customer says out loud to a service advisor instead of printing. */
.coupons { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 22px; margin-top: 28px; }
.coupon { background: var(--paper); border: 1px solid var(--rule);
  border-radius: 4px; overflow: hidden; display: flex; flex-direction: column; }
/* The red shout, at H1 size. This is the badge off the old print artwork,
   rebuilt as live text — same job, but readable by a search engine. */
.coupon .shout { background: var(--accent); color: #fff; padding: 16px 22px;
  font-family: var(--display); font-weight: var(--h-weight);
  font-size: var(--h1-size); line-height: 1.08; text-transform: uppercase;
  letter-spacing: var(--h1-letter-spacing); }
.coupon .cbody { padding: 22px 24px 24px; display: flex; flex-direction: column; flex: 1; }
.coupon h3 { margin: 0 0 .4rem; font-size: 1.15rem; }
.coupon .offer { font-family: var(--display); font-weight: 700; font-size: 1.6rem;
  line-height: 1.2; color: var(--accent); margin: 0 0 .9rem; }
.coupon .code { margin: 0 0 .9rem; font-size: .9rem; color: var(--soft); }
.coupon .code b { display: inline-block; font-family: var(--display); font-size: 1.15rem;
  letter-spacing: .12em; color: var(--ink); background: var(--panel);
  padding: 3px 12px; border-radius: 3px; margin-left: 6px; }
.coupon .code .ref { display: block; font-size: .72rem; color: var(--soft);
  letter-spacing: .04em; margin-top: 5px; font-weight: 600; }
.coupon .incl { list-style: none; margin: 0 0 .9rem; padding: 0; }
.coupon .incl li { font-size: .9rem; color: var(--body-ink); line-height: 1.5;
  padding-left: 16px; position: relative; margin-bottom: .28rem; }
.coupon .incl li::before { content: "\2713"; position: absolute; left: 0;
  color: var(--accent); font-weight: 700; }
.coupon .fine { font-size: .78rem; color: var(--soft); line-height: 1.5; margin: 0 0 .8rem; }
.coupon .exp { font-size: .82rem; color: var(--soft); margin: 0 0 1.1rem; font-weight: 600; }
.coupon .btn { margin-top: auto; align-self: flex-start; }
.coupon .copied { display: block; margin-top: 10px; font-size: .82rem; font-weight: 700;
  color: var(--accent); }
.coupon .copied[hidden] { display: none; }

/* ---------- Tables ---------- */
table.cmp { width: 100%; border-collapse: collapse; margin: 22px 0; font-size: .96rem; }
table.cmp th, table.cmp td { text-align: left; padding: 12px 14px; border-bottom: 1px solid var(--rule); }
table.cmp thead th { background: var(--ink); color: #fff; font-family: var(--display);
  font-weight: 700; letter-spacing: .03em; font-size: .88rem; }
table.cmp tr.us td { background: var(--panel-soft); font-weight: 600; }
table.cmp tr.us td:first-child { box-shadow: inset 4px 0 0 var(--accent); }

/* ---------- FAQ ---------- */
/* FAQs sit on the panel ground and inside the reading measure. Full-width
   answers across 1140px are a 130-character line, which nobody reads. */
.faqs { background: var(--panel-soft); }
.faqs h2 { margin-top: 0; }
.faq { border-top: 1px solid var(--rule); padding: 20px 0; }
.faq:last-child { border-bottom: 1px solid var(--rule); }
.faq h3 { margin: 0 0 .5rem; font-size: 1.08rem; line-height: 1.35; }
.faq p { color: var(--soft); margin: 0; line-height: 1.7; }

/* ---------- Footer ---------- */
footer { background: var(--panel-soft); border-top: 1px solid var(--rule); padding: 0 0 32px; }
.foot-grid { margin-top: 38px; display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap; align-items: flex-start; }
/* The 2016 lockup is 239x243, near square. The old 40px rule was written for
   a wide horizontal mark and clipped this one to a sliver. */
.foot-brand .logo svg, .foot-brand .logo img { height: 148px; width: auto; }

/* ---------- Footer certification bar ----------
   Bottom strip of every page, on white so the marks sit on their own ground
   rather than the footer's grey. Driven by CERT_LOGOS in siteconfig.

   The placeholder occupies the same height as the finished strip, so the
   footer will not jump when the real marks land. Held empty until Frontier
   supplies current ITAR and ISO documents; the ones on file expired in
   May 2026 and a badge linked to expired paperwork is worse than no badge. */
/* The certification strip breaks OUT of the content column deliberately.
   Seven marks inside the 1140px body width left each one small and the row
   crowded. 80% of the viewport gives the logos room to be read at a glance,
   which is the only job this band has. Capped so it does not sprawl on an
   ultrawide monitor, and released back to normal flow on narrow screens
   where 80vw would be narrower than the content column, not wider. */
/* Reads as the top of the footer rather than the last section of the page.
   The blue-grey ties it to the footer block below it, and the rule above is
   what separates it from whatever content section ends the page. */
/* White, deliberately. Customer and registrar marks are supplied on white and
   several carry their own white plate, which shows as a visible box on a tinted
   ground. It also separates the credentials from the footer without needing a
   rule between them -- the colour change does that job. */
.certbar { background: var(--paper); padding: 40px 0; }
.certbar > .wrap { width: 80vw; max-width: 1680px; }
.certbar-row { list-style: none; margin: 0; padding: 0; display: flex;
  flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 26px clamp(24px, 3vw, 60px); }
/* Tracking eases off as the size goes up. Uppercase at .1em is right at 11.8px
   and reads loose once the letters get bigger. */
.certbar-h { font-family: var(--display); font-size: .95rem; font-weight: 600;
  letter-spacing: .07em; text-transform: uppercase; color: var(--soft);
  margin: 0 0 24px; text-align: center; }

/* One line of detail under the marks: certificate numbers and the link to
   the certificate itself. Small, quiet, and the only place a number lives. */
.certbar-note { margin: 20px 0 0; text-align: center; font-size: .82rem;
  color: var(--soft); line-height: 1.7; }
.certbar-note strong { color: var(--ink); font-weight: 600; }
.certbar-note a { color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; }
.certbar-note a:hover { text-decoration: none; }
.certbar-sep { display: inline-block; width: 1px; height: .85em; margin: 0 14px;
  vertical-align: -1px; background: var(--rule); }

/* Height tracks the viewport so the seven marks stay on ONE line at any
   desktop width. The row is roughly 15.9x the logo height once the gaps are
   counted, and the band is 80vw, so 5vw is the height that just fits — which
   is why this is a vw and not a fixed pixel value. Clamped at both ends:
   never smaller than the old fixed size, never cartoonish on an ultrawide. */
.certbar-row img { display: block; height: clamp(56px, 5vw, 96px);
  width: auto; max-width: 100%; object-fit: contain; }
.certbar-row a { display: block; border-radius: 3px;
  transition: opacity .18s ease; }
.certbar-row a:hover { opacity: .72; }
.certbar-row a:focus-visible { outline: 3px solid var(--accent); outline-offset: 4px; }

.certbar-wait { padding: 0; background: var(--panel-soft); border-top: 0; }
.certbar-wait .wrap { border: 2px dashed var(--rule); border-radius: 4px;
  margin-top: 26px; margin-bottom: 26px; min-height: 126px;
  display: flex; align-items: center; justify-content: center; }
.certbar-wait p { margin: 0; font-family: var(--display); font-weight: 500;
  font-size: .84rem; letter-spacing: .16em; text-transform: uppercase;
  color: var(--soft); }

/* Below this the band goes back to the content column and the row is allowed
   to wrap. 80vw on a phone is NARROWER than the content width, not wider,
   which would be the opposite of the point. */
@media (max-width: 1200px) {
  .certbar > .wrap { width: auto; }
  .certbar-row img { height: 64px; }
  .certbar-row { gap: 22px 38px; }
}
@media (max-width: 700px) {
  .certbar-row { gap: 18px 30px; }
  .certbar-row img { height: 54px; }
  .certbar-wait .wrap { min-height: 96px; }
}
.foot-tag { margin-top: 12px; font-family: var(--display); font-weight: 700; color: var(--ink); max-width: 15em; }
.foot-nav { flex: 0 1 auto; text-align: center; }
.foot-nav-h { font-family: var(--display); font-size: .74rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--soft);
  margin: 0 0 12px; }
.foot-nav ul { list-style: none; margin: 0; padding: 0; }
.foot-nav li { margin: 0 0 7px; }
.foot-nav a { color: var(--link); text-decoration: none; font-size: .92rem;
  font-weight: 600; line-height: 1.5; }
.foot-nav a:hover { color: var(--link-hover); text-decoration: underline;
  text-underline-offset: 2px; }

.foot-meta { color: var(--soft); font-size: .92rem; text-align: right; line-height: 1.9; }
.foot-meta a { color: var(--link); text-decoration: none; font-weight: 600; }
/* Phone reads at masthead size. It is the primary conversion path on a B2B
   site and it was previously set smaller than the copyright line. */
/* line-height must be set explicitly: .foot-meta carries 1.9, and at 1.45rem
   that overflowed the footer's top edge and clipped the digits. */
.foot-phone { font-family: var(--display); font-weight: 600; font-size: 1.45rem;
  line-height: 1.25; color: var(--ink); text-decoration: none; white-space: nowrap;
  display: inline-block; margin-bottom: 6px; }
.foot-phone:hover { color: var(--accent); }
.foot-phone .phone-ico { margin-right: 8px; font-size: .95em; }
.foot-links { margin-top: 4px; }

/* ---------- Motion (all gated on prefers-reduced-motion in js/site.js) ---- */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity .5s ease, transform .5s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1 !important; transform: none !important; }
  .btn:hover { transform: none; }
  html { scroll-behavior: auto; }
}

/* ---------- Responsive ---------- */
@media (max-width: 860px) {
  .navbar .wrap { padding-top: 6px; padding-bottom: 6px; }
  :target, html { scroll-margin-top: 120px; scroll-padding-top: 120px; }
  .nav-toggle { display: inline-flex; align-items: center; gap: 10px; background: none;
    border: 0; color: #fff; font-family: var(--display); font-weight: 700;
    font-size: 1rem; padding: 10px 0; letter-spacing: .04em; }
  .bars { display: inline-block; width: 22px; height: 2px; background: #fff; position: relative; }
  .bars::before, .bars::after { content: ""; position: absolute; left: 0; width: 22px;
    height: 2px; background: #fff; }
  .bars::before { top: -7px; } .bars::after { top: 7px; }
  .navbar nav { display: none; flex-direction: column; gap: 0; padding: 0 0 10px; }
  .navbar.open nav { display: flex; }
  /* The open menu sits in flow inside the sticky header. With Capabilities
     expanded the nav runs ~1900px tall and everything below the fold is
     unreachable, because the header is pinned. Cap it and let it scroll.
     330px is the measured height of the header rows above the menu. */
  .navbar.open nav {
    /* nowrap is NOT optional. The nav is a column flexbox that inherits
       flex-wrap: wrap from the desktop rule. Unconstrained it never wraps.
       Give it a max-height and it wraps into COLUMNS: 1017px of content in a
       319px box, submenus side by side, a horizontal scrollbar. Found on the
       preview 4 Sep 2026. */
    flex-wrap: nowrap;
    /* justify-content: center comes from the desktop rule, where it is right.
       On a COLUMN flexbox that overflows, centering pushes the start of the
       content above the box, and overflow at the start edge cannot be scrolled
       to. Home, Capabilities and its whole submenu sat at -707px: rendered,
       and permanently unreachable. */
    justify-content: flex-start;
    max-height: calc(100dvh - 330px);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
  }
  .navbar nav a { padding: 12px 0; border-top: 1px solid rgba(255,255,255,.18); }
  .masthead-in { flex-direction: column; align-items: center; text-align: center;
    padding-top: 12px; padding-bottom: 12px; gap: 12px; }
  .logo svg, .logo img { height: 140px; }
  .hdr-compact .logo svg, .hdr-compact .logo img { height: 70px; }
  .masthead-actions { flex-direction: row; align-items: center; justify-content: center;
    width: 100%; gap: 14px; }
  .phone-top { font-size: 1.15rem; }
  /* On a phone the button and the phone number sit side by side. Matching
     their weight stops the CTA reading as the lesser of the two. Two lines is
     deliberate: it fills the box instead of padding it. */
  .btn-quote { font-size: 1.05rem; padding: 12px 18px; max-width: 8.5em;
    white-space: normal; }
  .foot-grid { flex-direction: column; }
  .foot-meta { text-align: left; }
  .foot-nav { text-align: left; }
}
@media (max-width: 620px) {
  table.cmp { display: block; overflow-x: auto; white-space: nowrap; font-size: .9rem; }
}
@media print {
  .navbar, .nav-toggle, .skip { display: none; }
  body { font-size: 12pt; }
}

/* ---------- Home hero slideshow ----------
   Mirrors the seven-panel rotator on the existing site. Captions are baked
   into the supplied JPEGs, so they are pixels rather than text — see
   CHANGE-REGISTER.md entry 5 for the recommendation to get clean plates.
   ---------------------------------------------------------------------- */
.hero { position: relative; overflow: hidden; background: var(--band);
  aspect-ratio: 2000 / 550; }
.hero-slide { position: absolute; inset: 0; opacity: 0; transition: opacity .7s ease;
  pointer-events: none; }
.hero-slide.on { opacity: 1; pointer-events: auto; }
.hero-slide img { width: 100%; height: 100%; object-fit: cover; display: block; }

.hero-prev, .hero-next { position: absolute; top: 50%; transform: translateY(-50%);
  z-index: 3; background: rgba(0,0,0,.34); border: 0; color: #fff; cursor: pointer;
  width: 46px; height: 64px; font-size: 26px; line-height: 1;
  display: flex; align-items: center; justify-content: center; }
.hero-prev { left: 0; } .hero-next { right: 0; }
.hero-prev:hover, .hero-next:hover { background: rgba(0,0,0,.55); }
.hero-prev:focus-visible, .hero-next:focus-visible,
.hero-dot:focus-visible { outline: 3px solid #08C7FC; outline-offset: 2px; }

.hero-dots { position: absolute; left: 0; right: 0; bottom: 12px; z-index: 3;
  display: flex; gap: 9px; justify-content: center; }
.hero-dot { width: 11px; height: 11px; border-radius: 50%; padding: 0; cursor: pointer;
  border: 1px solid rgba(255,255,255,.85); background: transparent; }
.hero-dot.on { background: var(--accent); border-color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .hero-slide { transition: none; }
}
/* Dots OFF on tablet and phone, at the same 900px the rest of the site breaks at.
   The hero holds aspect-ratio 2000/550, so on a 375px screen the band is only
   103px tall -- and the slide captions are baked into the JPEGs as pixels rather
   than being real text. At that height the dot row lands directly on top of the
   burned-in caption and makes it unreadable. The slideshow autoplays, so nothing
   is lost by removing them. The real fix is clean plates with no burned-in text;
   see the note at the top of this section. */
@media (max-width: 900px) {
  .hero-dots { display: none; }
}

@media (max-width: 720px) {
  .hero-prev, .hero-next { width: 36px; height: 50px; font-size: 20px; }
}

/* ---------- Break-even calculator ----------
   Built from Steve O'Donnell's own break-even spreadsheet. Colours read from
   the tokens; nothing hardcoded below :root.
   -------------------------------------------------------------------------- */
.calc-band { background: var(--panel-soft); }
.calc { margin-top: 26px; }
.calc-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px 26px; }
.calc fieldset { border: 1px solid var(--rule); border-radius: 8px;
  padding: 18px 20px 20px; margin: 0; background: var(--paper); }

/* A <legend> straddles the fieldset border by default and cannot be aligned
   with padding, which is why these labels appeared to float outside the box.
   Floating it takes it out of that special rendering and puts it in normal
   flow inside the panel, where it belongs. width:100% keeps the fields on the
   line below rather than beside it. */
.calc legend { float: left; width: 100%; padding: 0; margin: 0 0 4px;
  font-family: var(--display); font-weight: 600; font-size: .82rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent); }
.calc legend + * { clear: both; }

.calc label { display: block; font-weight: 600; font-size: .92rem; margin: 14px 0 5px; }
.calc label:first-of-type { margin-top: 12px; }
.calc .hint { display: block; font-weight: 400; color: var(--soft); font-size: .8rem; margin-top: 2px; }
.calc-field { position: relative; }
.calc-field .pre { position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  color: var(--soft); pointer-events: none; }
.calc input[type=number] { width: 100%; padding: 11px 12px 11px 26px; font-family: var(--body);
  font-weight: 600; font-size: 1rem; color: var(--ink); background: var(--paper);
  border: 1px solid var(--rule); border-radius: 6px; -moz-appearance: textfield; }
.calc input[type=number]::-webkit-outer-spin-button,
.calc input[type=number]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.calc input[type=number]:focus { outline: 2px solid var(--accent); outline-offset: 1px;
  border-color: var(--accent); }
.calc input.nopre { padding-left: 12px; }
.calc input[aria-invalid="true"] { border-color: #c0392b; }
.eau-label { margin-top: 18px !important; }
.eau-field { max-width: 260px; }

.calc-result { margin-top: 24px; padding: 22px 26px; border-radius: 8px;
  background: var(--accent); color: #fff; }
.calc-result .k { font-family: var(--display); font-weight: 600; font-size: .78rem;
  letter-spacing: .13em; text-transform: uppercase; opacity: .9; }
.calc-result .v { font-family: var(--display); font-weight: 600; font-size: 2.7rem;
  line-height: 1.05; margin: 8px 0 2px; }
.calc-result .v small { font-size: 1.1rem; font-weight: 400; opacity: .9; margin-left: 6px; }
.calc-result p { margin: 10px 0 0; font-size: .95rem; line-height: 1.55; opacity: .96; max-width: 62ch; }
.calc-result.warn { background: #8a6d1f; }
.calc-result.bad  { background: #7d3a32; }

.calc-chart { margin-top: 24px; border: 1px solid var(--rule); border-radius: 8px;
  padding: 18px 16px 10px; background: var(--paper); overflow-x: auto; }
.calc-chart h3 { font-size: .82rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--soft); margin: 0 0 14px; }
.calc-chart svg { display: block; width: 100%; min-width: 460px; height: auto; }
.calc-key { display: flex; gap: 20px; flex-wrap: wrap; margin-top: 10px;
  font-size: .85rem; color: var(--soft); }
.calc-key i { display: inline-block; width: 22px; height: 3px; border-radius: 2px;
  vertical-align: 3px; margin-right: 7px; }
.calc-key .k-lv { background: var(--soft); }
.calc-key .k-hv { background: var(--accent); }

.calc-tablewrap { overflow-x: auto; margin-top: 22px; }
.calc tr.cross td { background: var(--panel-soft); font-weight: 600; }
.calc tr.cross td:first-child::after { content: " \2190 break-even";
  color: var(--accent); font-weight: 600; }
.calc-note { margin-top: 22px; padding-left: 14px; border-left: 3px solid var(--rule);
  color: var(--soft); font-size: .9rem; max-width: 66ch; }

@media (max-width: 680px) {
  .calc-grid { grid-template-columns: 1fr; }
  .calc-result .v { font-size: 2.1rem; }
}

/* ---------- Homepage promo band for the calculator ---------- */
.promo { background: var(--band); color: var(--band-body); }
.promo .wrap { display: flex; align-items: center; gap: 34px; flex-wrap: wrap;
  padding-top: 44px; padding-bottom: 44px; }
.promo-copy { flex: 1 1 420px; }
.promo h2 { color: #fff; margin-top: 0; }
.promo p { margin-bottom: 0; max-width: 58ch; }
.promo-fig { flex: 0 0 300px; background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.16); border-radius: 10px; padding: 22px 24px; }
.promo-fig .k { font-family: var(--display); font-weight: 600; font-size: .74rem;
  letter-spacing: .13em; text-transform: uppercase; color: #08C7FC; }
.promo-fig .v { font-family: var(--display); font-weight: 600; font-size: 2.4rem;
  line-height: 1.05; color: #fff; margin: 6px 0 4px; }
.promo-fig .s { font-size: .86rem; color: var(--band-body); opacity: .85; }
.promo .cta-row { margin-top: 20px; }
/* Inline links inside the dark promo band. Without this they inherit the body
   ink (#1a1d21) on a #292929 ground: 1.16:1, effectively invisible. */
.promo-copy a:not(.btn) { color: #7cc4f5;
  text-decoration-color: rgba(124,196,245,.55); }
.promo-copy a:not(.btn):hover { color: #a8d9fa; }
@media (max-width: 760px) { .promo-fig { flex: 1 1 100%; } }

/* ---------- Click-to-load video ----------
   A raw YouTube embed pulls ~1MB of player script on every page load whether
   anyone presses play or not. This shows a still; the iframe is only created
   on click. CHANGE-REGISTER.md entry 7.
   ---------------------------------------------------------------------- */
.vid { position: relative; margin: 8px 0 4px; }
.vid-btn { display: block; width: 100%; padding: 0; border: 0; cursor: pointer;
  background: var(--band); position: relative; overflow: hidden; line-height: 0; }
.vid-btn img { width: 100%; height: 100%; aspect-ratio: 16/9; object-fit: cover;
  display: block; filter: brightness(.82);
  transition: filter .2s ease, transform .4s ease; }
.vid-btn:hover img { filter: brightness(.95); transform: scale(1.015); }
.vid-btn:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.vid-play { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 84px; height: 84px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 6px 26px rgba(0,0,0,.4); }
.vid-play::after { content: ""; position: absolute; left: 54%; top: 50%;
  transform: translate(-50%,-50%); border-style: solid; border-width: 15px 0 15px 25px;
  border-color: transparent transparent transparent #fff; }
.vid-btn:hover .vid-play { background: var(--accent-ink); }
.vid iframe { width: 100%; aspect-ratio: 16/9; border: 0; display: block; }
@media (max-width: 700px) {
  .vid-play { width: 58px; height: 58px; }
  .vid-play::after { border-width: 10px 0 10px 17px; }
}
@media (prefers-reduced-motion: reduce) {
  .vid-btn img { transition: none; }
  .vid-btn:hover img { transform: none; }
}

/* ---------- Feature tiles ----------
   Mirrors the existing site: photograph, blue caption bar, and a description
   panel that rolls up over the image on hover.

   The panel is VISIBLE by default and only hidden inside @media (hover:hover).
   A reveal-on-hover pattern that starts hidden strands every touch user with
   a photo and four words, so the default state has to be the readable one.
   ---------------------------------------------------------------------- */
/* Two by two. Four tiles across left an orphan at 1140px and squeezed the
   hover panel narrower than its own copy, which is what was clipping the text.
   A 2x2 block divides evenly, reads as one unit, and gives the panel room.
   Wider than the text column but capped: at full viewport the photographs
   would be 900px+ tall and swamp the section. */
.ftiles { display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 22px; margin-top: 28px; padding: 0 20px;
  max-width: 1400px; margin-left: auto; margin-right: auto; }

.ftile { position: relative; display: block; overflow: hidden; text-decoration: none;
  background: var(--band); border-radius: 4px; }
/* 3:2 matches the source photographs exactly, so nothing is cropped. */
.ftile-img { display: block; aspect-ratio: 3 / 2; overflow: hidden; }
.ftile-img img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s ease; }
.ftile:hover .ftile-img img { transform: scale(1.04); }
.ftile-ph { display: block; width: 100%; height: 100%;
  background: repeating-linear-gradient(135deg, #e9edf1 0 14px, #e2e7ec 14px 28px); }

.ftile-bar { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  background: var(--accent); color: #fff; text-align: center;
  font-family: var(--display); font-weight: 500; font-size: 1.02rem;
  letter-spacing: .04em; text-transform: uppercase; line-height: 1.3;
  padding: 14px 16px; transition: background .2s ease; }
.ftile:hover .ftile-bar { background: var(--accent-ink); }

/* Full tile height, copy centred. Anchored to the bottom edge only, the panel
   was as tall as its own text and anything longer than the photograph had its
   first lines clipped off the top by the tile's overflow. Covering the tile
   means the copy has the whole frame and cannot be cut. */
.ftile-panel { position: absolute; inset: 0; z-index: 1;
  display: flex; flex-direction: column; justify-content: center;
  background: rgba(26,29,33,.94); color: var(--band-body);
  padding: 26px 30px 78px; font-size: .95rem; line-height: 1.6; }
.ftile-copy { display: block; }
.ftile-more { display: inline-block; margin-top: 14px; color: #fff;
  font-family: var(--display); font-weight: 600; font-size: .86rem;
  letter-spacing: .05em; text-transform: uppercase; }
.ftile-more::after { content: " \2192"; }

/* Mouse and trackpad only: hide the panel, roll it up on hover or focus. */
@media (hover: hover) and (pointer: fine) {
  .ftile-panel { transform: translateY(100%); transition: transform .38s ease; }
  .ftile:hover .ftile-panel,
  .ftile:focus-visible .ftile-panel { transform: translateY(0); }
}
.ftile:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

@media (prefers-reduced-motion: reduce) {
  .ftile-panel { transition: none; }
  .ftile-img img { transition: none; }
  .ftile:hover .ftile-img img { transform: none; }
}
@media (max-width: 640px) {
  .ftiles { grid-template-columns: 1fr; gap: 20px; }
  .ftile-bar { font-size: .92rem; padding: 12px 14px; }
  .ftile-panel { padding: 18px 18px 62px; font-size: .9rem; }
}

/* ---------- Testimonial ---------- */
.quote { margin: 24px 0 34px; padding: 0 0 0 26px; border-left: 4px solid var(--accent); }
.quote p { font-size: 1.12rem; line-height: 1.7; color: var(--ink); max-width: 68ch; }
.quote footer { margin-top: 12px; color: var(--soft); font-size: .95rem; }

/* ---------- Testimonials ----------
   Two of them side by side, one written and one on video, each carrying the
   name of the person actually speaking. Previously a written quote from Mike
   Meier sat directly above a video of a different customer entirely, under a
   hero-slide poster with an unrelated section title burned into it. Three
   things that read as one broken thing. */
.tst-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 40px;
  align-items: start; margin-top: 38px; }
.tst { margin: 0; }
.tst-quote { padding-left: 26px; border-left: 4px solid var(--accent); }
.tst-quote p { font-size: 1.08rem; line-height: 1.7; color: var(--ink); margin: 0; }
.tst-quote p::before { content: "\201C"; }
.tst-quote p::after  { content: "\201D"; }

/* Name and title on the left, the customer's own mark on the right, baselines
   aligned. Every logo in img/customers sits on the same 340x100 canvas with
   the mark fitted inside, so one fixed height gives both testimonials equal
   optical weight without per-logo tuning.
   Note this is a div, not a <footer>: a nested <footer> inherited the global
   page-footer rule and drew a grey panel behind the attribution. */
.tst-by { display: flex; align-items: center; justify-content: space-between;
  gap: 20px; margin-top: 18px; font-size: .95rem; line-height: 1.45; }
.tst-who strong { display: block; color: var(--ink); font-weight: 700; }
.tst-who span { color: var(--soft); }
.tst-logo { height: 40px; width: auto; flex: none; }

/* The video sits low in its column next to a quote that starts at the top;
   nudge the eyebrow up so the two headline rows read as one line. */
.tst-video .vid { margin: 0; }
.tst-quote { padding-top: 2px; }

@media (max-width: 860px) {
  .tst-grid { grid-template-columns: 1fr; gap: 30px; }
}

/* ---------- Credentials list ---------- */
.creds { list-style: none; margin: 20px 0 0; padding: 0; display: flex;
  flex-wrap: wrap; gap: 10px 12px; }
.creds li { border: 1px solid var(--rule); border-radius: 100px;
  padding: 8px 18px; font-size: .9rem; font-weight: 600; color: var(--ink);
  background: var(--paper); }

/* ---------- Customer logo rows ----------
   Third-party marks, authorised for use subject to each brand's guidelines.
   The treatment is deliberately plain and that is the point: white tile,
   generous clear space, uniform optical size, no tint, no crop, no overlap,
   nothing sitting on a busy ground. That is what almost every brand guideline
   asks for, and it is also what reads as confident rather than cluttered.

   Logos are constrained by HEIGHT, not width, so a wide wordmark and a square
   badge end up looking the same weight instead of one dwarfing the other.
   ---------------------------------------------------------------------- */
/* Home page section rhythm, bottom third:
       specstrip   blue-grey
       customers   WHITE      <- was blue-grey, and sat flush against the new
                                 spec strip above it as one undifferentiated band
       posts       blue-grey
   Alternating so each section reads as its own thing. */
.customers { background: #fff; }
.logo-row { list-style: none; margin: 0 auto; padding: 0 20px; max-width: 1820px;
  display: flex; flex-wrap: wrap; justify-content: center;
  align-items: center; gap: 12px; }
/* Sized so NINE tiles sit on one line at desktop: tile = 148 img + 34 padding
   + 2 border = 184px; 9 x 184 + 8 x 12 = 1752, inside the 1780px of usable row
   width. Eight today, room for one more in each row without reflowing. */
/* The rows sit OUTSIDE .wrap so they run the full viewport width rather than
   stopping at the 1140px content column. On a wide monitor that turns two
   cramped rows into a proper band. */
.logo-row li { background: var(--paper); border: 1px solid var(--rule);
  border-radius: 6px; padding: 15px 17px; display: flex; align-items: center;
  justify-content: center; }
/* Every logo file is a uniform 340x100 canvas with the mark fitted and centred,
   so the tiles need no per-logo compensation. One width, one height, done. */
.logo-row img { display: block; width: 148px; height: 44px; object-fit: contain; }
.logo-row .logo-name { font-family: var(--display); font-weight: 500;
  font-size: 1rem; letter-spacing: .03em; text-transform: uppercase;
  color: var(--ink); text-align: center; width: 148px; height: 44px;
  display: flex; align-items: center; justify-content: center; }

/* The lead row sits above the heading and carries the marquee names, so it
   runs slightly larger. */
.logo-row-lead { margin-bottom: 44px; }




.customers h2 { text-align: center; margin-top: 0; }
.customers .logo-row:last-child { margin-top: 4px; }
.customers .lede { text-align: center; margin: 0 auto 40px; max-width: 72ch; }

@media (max-width: 700px) {
  .logo-row li { padding: 10px 12px; }
  .logo-row img, .logo-row .logo-name { width: 122px; height: 36px; }
  .logo-row .logo-name { font-size: .78rem; }
}

/* ---------- Column list ---------- */
ul.cols { columns: 2; column-gap: 34px; }
ul.cols li { break-inside: avoid; }
@media (max-width: 640px) { ul.cols { columns: 1; } }

/* ---------- Table wrapper ---------- */
.tablewrap { overflow-x: auto; margin: 22px 0; }


/* ---------- Blog cards ----------
   Same component on the homepage feed and the /blog/ index, so the two can
   never drift apart. Mirrors the current site: photo on top, title, date,
   excerpt, outlined Read more. The whole card is one link; the "Read more"
   is styled to look like the old button but is a span, because a link inside
   a link is invalid and screen readers announce it twice. */
.pcards { display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 26px; margin-top: 28px; }
.pcard { background: #fff; border: 1px solid var(--rule); border-radius: 4px;
  overflow: hidden; display: flex; }
.pcard-link { display: flex; flex-direction: column; width: 100%;
  text-decoration: none; color: inherit; }
.pcard-img { display: block; aspect-ratio: 3 / 2; overflow: hidden;
  background: var(--panel-soft); }
.pcard-img img { width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s ease; }
.pcard-link:hover .pcard-img img { transform: scale(1.04); }
.pcard-noimg { background: repeating-linear-gradient(135deg,
  #e9edf1 0 14px, #e2e7ec 14px 28px); }
.pcard-body { display: flex; flex-direction: column; flex: 1;
  padding: 22px 22px 24px; }
.pcard-title { font-family: var(--display); font-weight: var(--h-weight);
  font-size: 1.1rem; line-height: 1.3; letter-spacing: .01em;
  text-transform: uppercase; color: var(--ink); margin: 0; }
.pcard-link:hover .pcard-title { color: var(--accent); }
.pcard-date { display: block; margin-top: 10px; font-size: .86rem;
  color: var(--soft); }
.pcard-ex { display: block; margin-top: 12px; font-size: .95rem;
  line-height: 1.6; color: var(--body-ink, var(--ink)); flex: 1; }
.pcard-more { display: inline-block; align-self: flex-start; margin-top: 18px;
  border: 1px solid var(--accent); color: var(--accent); border-radius: 3px;
  padding: 9px 20px; font-family: var(--display); font-weight: 600;
  font-size: .82rem; letter-spacing: .06em; text-transform: uppercase;
  transition: background .18s ease, color .18s ease; }
.pcard-link:hover .pcard-more { background: var(--accent); color: #fff; }
.pcard-link:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }

.posts .cta-row { margin-top: 30px; }

@media (max-width: 980px) { .pcards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .pcards { grid-template-columns: 1fr; } }

@media (prefers-reduced-motion: reduce) {
  .pcard-img img { transition: none; }
  .pcard-link:hover .pcard-img img { transform: none; }
}

/* ---------- Post page ---------- */
/* Interior content runs the full 1140px column, same as the breadcrumbs, the
   hero and the footer. It was capped at 760 for reading measure, which left
   every interior page looking narrower than its own chrome. Mark's call,
   26 Aug: match the rest of the site.

   The measure is now held on the TEXT rather than the container, so paragraphs
   stay readable while headings, lists, tables and figures use the full width.
   That keeps both things true instead of trading one for the other. */
.wrap-read { max-width: var(--wrap); }
.wrap-read .prose > p,
.wrap-read .prose > ul,
.wrap-read .prose > ol { max-width: 88ch; }
.post-hero { margin: 0 0 26px; }
.post-hero img { width: 100%; height: auto; display: block; border-radius: 4px; }
.post-meta { color: var(--soft); font-size: .92rem; margin: 0 0 22px; }
.prose h2 { font-size: 1.5rem; margin: 34px 0 12px; }
.prose h3 { font-size: 1.2rem; margin: 28px 0 10px; }
.prose p { margin: 0 0 16px; line-height: 1.75; }
.prose ul, .prose ol { margin: 0 0 18px; padding-left: 24px; line-height: 1.75; }
.prose li { margin-bottom: 8px; }
/* Inline links in body copy are brand blue. Buttons are NOT inline links:
   .prose a was repainting .btn text blue on a blue ground, which made every
   button inside prose invisible. Restated here rather than raising .btn's
   specificity, so the rule that caused it sits next to the rule that fixes it. */
.prose a { color: var(--accent); }
.prose .btn { color: #fff; }
.prose .btn:hover { color: #fff; }
.prose .btn-ghost { color: var(--ink); }
.prose .btn-ghost:hover { color: #fff; }
.prose img { max-width: 100%; height: auto; border-radius: 4px; }


/* ---------- Environmental Leadership award ----------
   Rebuilt to resemble the section on the current site, which Frontier is
   rightly proud of: centred heading, the story on the left with the ELP mark
   and its explanation beneath it, the banquet photograph on the right.
   The previous version was a paragraph and a row of chips, which buried a real
   award under the same treatment as a membership. */
/* One line at desktop. The 22ch measure that keeps ordinary headings readable
   broke this one into a four-line stack, which read as four separate shouts.
   Oswald is condensed enough that all 66 characters clear 1140px at 30px;
   the fluid size holds it on one line down to about 1000px, below which it is
   allowed to wrap normally rather than shrink into illegibility. */
.award-head { text-align: center; max-width: none; margin: 0 auto 36px;
  text-transform: uppercase; letter-spacing: .015em; line-height: 1.22;
  white-space: nowrap; font-size: min(var(--h2-size), 2.62vw); }
@media (max-width: 1000px) {
  .award-head { white-space: normal; font-size: var(--h2-size);
    max-width: 26ch; }
}
.award-grid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 44px;
  align-items: start; }
.award-copy p { line-height: 1.75; }
.award-elp { display: grid; grid-template-columns: 130px 1fr; gap: 22px;
  align-items: start; margin-top: 26px; }
.award-elp p { margin: 0; font-size: .95rem; line-height: 1.7; }
.award-elp-logo { display: block; width: 130px; height: auto; border-radius: 8px; }
.award-fig img, .award-fig .art-wait { width: 100%; height: auto; display: block;
  border-radius: 4px; }
.award .creds { margin-top: 40px; justify-content: center; }

@media (max-width: 900px) {
  .award-head { max-width: none; margin-bottom: 26px; }
  .award-grid { grid-template-columns: 1fr; gap: 30px; }
  .award-fig { order: -1; }
}
@media (max-width: 520px) {
  .award-elp { grid-template-columns: 1fr; gap: 14px; }
  .award-elp-logo { width: 110px; }
}

/* ---------- Placeholder for artwork not yet supplied ----------
   Holds the exact aspect ratio of the photo it stands in for, so the page can
   be reviewed and signed off before every asset has arrived. */
.art-wait { display: flex; align-items: center; justify-content: center;
  width: 100%; border: 2px dashed var(--rule); border-radius: 4px;
  background: repeating-linear-gradient(135deg,
    #eef1f4 0 12px, #e7ebef 12px 24px); }
.art-wait span { font-family: var(--display); font-weight: 500; font-size: .74rem;
  letter-spacing: .14em; text-transform: uppercase; color: var(--soft); }

/* ---------- Hub cards ----------
   /capabilities/, /industries/ and /resources/. The whole card is the link;
   "Read more" is a span styled as a cue, because a link inside a link is
   invalid and gets announced twice by a screen reader. */
.hubcards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 22px;
  margin-top: 28px; }
.hubcard { display: flex; flex-direction: column; background: #fff;
  border: 1px solid var(--rule); border-left: 4px solid var(--accent);
  border-radius: 4px; padding: 24px 24px 22px; text-decoration: none;
  color: inherit; transition: box-shadow .18s ease, transform .18s ease; }
.hubcard:hover { box-shadow: 0 8px 26px rgba(0,0,0,.10); transform: translateY(-2px); }
.hubcard:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.hubcard h3 { font-family: var(--display); font-weight: var(--h-weight);
  font-size: 1.14rem; line-height: 1.3; margin: 0 0 10px; color: var(--ink); }
.hubcard:hover h3 { color: var(--accent); }
.hubcard p { margin: 0; font-size: .95rem; line-height: 1.65; flex: 1; }
.hubcard-more { margin-top: 16px; font-family: var(--display); font-weight: 600;
  font-size: .8rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--accent); }
.hubcard-more::after { content: " \2192"; }
@media (max-width: 980px) { .hubcards { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px) { .hubcards { grid-template-columns: 1fr; } }

/* ---------- Link grids ---------- */
.linkgrid { list-style: none; margin: 18px 0 30px; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px 24px; }
.linkgrid li { border-bottom: 1px solid var(--rule); }
.linkgrid a { display: block; padding: 10px 2px; text-decoration: none;
  color: var(--ink); font-weight: 600; font-size: .96rem; }
.linkgrid a:hover { color: var(--accent); }
.linkgrid-tight a { font-weight: 400; font-size: .9rem; }
@media (max-width: 860px) { .linkgrid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .linkgrid { grid-template-columns: 1fr; } }

/* ---------- Spec lists ----------
   Equipment, parts, finishes. These are scanned, not read: a buyer looks for
   one press size or one MIL spec. Two columns, tight leading, no bullets
   competing with the text. */
.speclist { list-style: none; margin: 18px 0 26px; padding: 0; }
.speclist li { position: relative; padding: 7px 0 7px 20px; line-height: 1.55;
  border-bottom: 1px solid var(--rule); font-size: .95rem; }
.speclist li::before { content: ""; position: absolute; left: 0; top: 15px;
  width: 7px; height: 7px; background: var(--accent); border-radius: 1px; }
.speclist-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 36px; }
@media (max-width: 720px) { .speclist-2 { grid-template-columns: 1fr; } }

.fineprint { font-size: .86rem; color: var(--soft); line-height: 1.6; }

/* ---------- Quote page ---------- */
.quote-grid { display: grid; grid-template-columns: 1fr 1.05fr; gap: 48px;
  align-items: start; }
.quote-copy h2:first-child { margin-top: 0; }
.quote-copy ul { line-height: 1.7; padding-left: 20px; }
.quote-copy li { margin-bottom: 10px; }
.quote-contact { font-size: 1.05rem; line-height: 1.9; }
.quote-contact a { font-family: var(--display); font-weight: 600;
  font-size: 1.4rem; color: var(--ink); text-decoration: none; }
.quote-contact a:hover { color: var(--accent); }
.quote-contact .soft { font-size: .9rem; color: var(--soft); }

.qform { background: var(--panel-soft); border: 1px solid var(--rule);
  border-radius: 4px; padding: 28px 28px 30px; }
.qform h2 { margin-top: 0; }
.qform label { display: block; margin: 16px 0 6px; font-weight: 600;
  font-size: .92rem; color: var(--ink); }
.qform .req { color: var(--accent); }
.qform input[type=text], .qform input[type=email], .qform input[type=tel],
.qform textarea, .qform select, .qform input[type=file] {
  width: 100%; padding: 11px 13px; border: 1px solid var(--rule);
  border-radius: 3px; background: #fff; font: inherit; font-size: .97rem;
  color: var(--ink); }
.qform textarea { resize: vertical; min-height: 130px; }
.qform input:focus, .qform textarea:focus, .qform select:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(0,119,200,.18); }
.qrow { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; }
.qform .hint { display: block; margin-top: 6px; font-size: .83rem;
  color: var(--soft); line-height: 1.5; }
/* Conditional follow-up under "How did you hear about us?". Indented and
   ruled so it reads as a child of the answer above it rather than as another
   question in the stack. [hidden] needs restating because the display rule
   on the wrapper would otherwise win. */
.qfollow { margin-top: 4px; padding-left: 14px;
  border-left: 3px solid var(--accent); }
.qfollow[hidden] { display: none; }
.qfollow label { margin-top: 10px; font-weight: 500; color: var(--soft); }

/* Chosen files, listed back to the customer. A file input says "4 files"
   and nothing else, which is no help at all when one of them is wrong. */
.filelist { list-style: none; margin: 10px 0 0; padding: 10px 12px;
  background: var(--panel-soft); border-left: 3px solid var(--accent);
  font-size: .84rem; line-height: 1.6; }
.filelist li { color: var(--ink); }
.filelist li + li { margin-top: 2px; }
.filelist .filelist-err { color: #b3261e; font-weight: 600; }

.qform .btn { margin-top: 22px; }
.qform .fineprint { margin-top: 14px; }
/* Honeypot. Off-screen rather than display:none, which some bots check for. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px;
  overflow: hidden; }
@media (max-width: 900px) {
  .quote-grid { grid-template-columns: 1fr; gap: 34px; }
  .qrow { grid-template-columns: 1fr; }
}

/* The blog feed on the home page. Only feed() in blog.py renders .posts, and
   only the home page calls it, so this cannot leak onto the blog index. */
.posts { background: var(--panel-soft); }


/* Intro block. The lede is capped at a readable measure, which left a dead
   gutter beside it in a 1140px wrap. The building shot fills that honestly:
   it is proof, it carries the street address on the monument sign, and it sits
   next to the paragraph that says where the shop is. Proportions and breakpoint
   deliberately match .award-grid so the page keeps one two-column rhythm. */
.introgrid { display: grid; grid-template-columns: 1.15fr 1fr; gap: 44px;
  align-items: start; margin-top: 4px; }
.introgrid .lede { max-width: none; }        /* the column is the measure now */
.introcopy p:last-child { margin-bottom: 0; }
.introfig { margin: 0; }
.introfig img { width: 100%; height: auto; display: block; border-radius: 4px; }

@media (max-width: 900px) {
  .introgrid { grid-template-columns: 1fr; gap: 26px; }
}

/* ---------- Materials table ----------
   table-layout: fixed with a colgroup, because auto layout lets the longest
   string in a column decide that column's width. The first build had
   white-space: nowrap on the dimension cells, whose longest string was a whole
   phrase — those two columns took the width and the grade list collapsed into
   a vertical ribbon roughly 200px tall per row. Fixed layout honours the
   percentages regardless of content.

   The table carries facts only. Explanation lives below it, where a sentence
   has room to be a sentence. */
/* The caveats are about the table, so they share its band rather than sitting
   on white below it. Extra top margin stands in for the section padding that
   used to separate them. */
.mattable-notes { margin-top: 34px; }

.matwrap { overflow-x: auto; margin: 22px 0 0; -webkit-overflow-scrolling: touch; }
.mattable { display: table; width: 100%; min-width: 620px;
  border-collapse: collapse;
  table-layout: fixed; font-size: .92rem; }
.mattable col.c1 { width: 17%; }
.mattable col.c2 { width: 45%; }
.mattable col.c3 { width: 19%; }
.mattable col.c4 { width: 19%; }
.mattable thead th { text-align: left; font-family: var(--display);
  font-size: .72rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: #fff; background: var(--accent);
  padding: 9px 13px; }
.mattable tbody th { text-align: left; font-family: var(--display);
  font-weight: 700; color: var(--ink); vertical-align: top; padding: 12px 13px;
  line-height: 1.35; }
.mattable td { vertical-align: top; padding: 12px 13px; line-height: 1.5; }
.mattable td.num { color: var(--soft); font-variant-numeric: tabular-nums; }
.mattable tbody tr { border-bottom: 1px solid var(--rule); }
.mattable tbody tr:nth-child(even) { background: #fff; }

/* ---------- Home page spec strip ----------
   The Foundation Build Order asked for the press list, size range and material
   range on the home page as real numbers. A buyer qualifying a shop wants the
   range before they click anything, so these are set large enough to read at a
   glance and the prose is kept short — the numbers are the content. */
.specstrip { background: var(--panel-soft); }
.specgrid { list-style: none; margin: 26px 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px 34px; }
.specgrid li { border-left: 3px solid var(--accent); padding-left: 16px; }
.spec-n { display: block; font-family: var(--display); font-weight: 700;
  font-size: 1.9rem; line-height: 1.15; color: var(--ink);
  font-variant-numeric: tabular-nums; }
.spec-l { display: block; margin-top: 4px; font-size: .88rem; color: var(--soft);
  line-height: 1.45; }
.spec-presses { margin-top: 26px; font-size: .92rem; color: var(--soft);
  line-height: 1.7; }
.spec-presses strong { color: var(--ink); }
.spec-presses a { color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; }
.spec-presses a:hover { text-decoration: none; }
@media (max-width: 900px) {
  .specgrid { grid-template-columns: repeat(2, 1fr); gap: 22px 24px; }
  .spec-n { font-size: 1.6rem; }
}
@media (max-width: 560px) {
  .specgrid { grid-template-columns: 1fr; }
}

/* ---------- Dropdown navigation ----------
   Every parent is a real page. The dropdown is an accelerator, not the only
   route in, which is why this degrades correctly with JS off: the parent link
   still works and the panel simply never opens.

   Opens on hover for a mouse, on click for touch and keyboard. The hover rule
   is fenced behind (hover: hover) so a tap on a phone does not fire a hover
   state that then sticks. */
.navbar nav { position: relative; }
.navitem { position: relative; display: flex; align-items: center; gap: 2px; }
.navitem > a { display: inline-block; }
.navcaret { background: none; border: 0; padding: 4px 2px 4px 4px; cursor: pointer;
  line-height: 0; color: #fff; }
.navcaret span { display: block; width: 0; height: 0;
  border-left: 4.5px solid transparent; border-right: 4.5px solid transparent;
  border-top: 5px solid currentColor; transition: transform .18s ease; }
.navcaret:hover { color: #08C7FC; }
.navcaret:focus-visible { outline: 2px solid #08C7FC; outline-offset: 2px; }
.navitem.on > a { color: #08C7FC; }

/* Continuous with the bar it drops from, not a white sheet floating off it.
   The mobile menu was already dark with a #08C7FC hover; this brings desktop
   into line rather than running two treatments for one component.

   NO border-top here. The navbar already carries a 3px accent rule along its
   bottom edge, so the panel's own added up to 6px of stacked blue -- most of
   what made it feel heavy. The panel now hangs off the line that already
   exists. Depth comes from being a shade darker than the bar plus the shadow. */
.navdrop { position: absolute; top: 100%; left: -18px; z-index: 80;
  min-width: 268px; margin: 0; padding: 6px 0; list-style: none;
  background: #1e2126; border: 1px solid rgba(255,255,255,.07);
  border-top: 0; border-radius: 0 0 3px 3px;
  box-shadow: 0 18px 42px rgba(0,0,0,.5);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .16s ease, transform .16s ease, visibility .16s; }
.navdrop li { margin: 0; }
.navdrop a { display: block; padding: 9px 22px; color: rgba(255,255,255,.86);
  font-family: var(--body); font-weight: 500; font-size: .9rem;
  letter-spacing: 0; text-transform: none; line-height: 1.45;
  transition: background .12s ease, color .12s ease; }
.navdrop a:hover { background: rgba(255,255,255,.06); color: #08C7FC; }
.navdrop a[aria-current="page"] { color: #08C7FC; }

.navitem.open .navdrop { opacity: 1; visibility: visible; transform: translateY(0); }
.navitem.open .navcaret span { transform: rotate(180deg); }
@media (hover: hover) and (pointer: fine) {
  .navitem:hover .navdrop,
  .navitem:focus-within .navdrop { opacity: 1; visibility: visible;
    transform: translateY(0); }
  .navitem:hover .navcaret span { transform: rotate(180deg); }
}

/* Panels near the right edge would run off screen. The last two open leftward. */
.navbar nav > .navitem:nth-last-child(2) .navdrop { left: auto; right: -18px; }

@media (max-width: 900px) {
  /* Stacked mobile menu. Children are always visible under their parent
     rather than needing a second tap: a tap that opens a menu on a phone and
     a tap that follows a link are indistinguishable to the user, and getting
     it wrong strands them. */
  .navitem { display: block; }
  .navcaret { display: none; }
  .navdrop { position: static; opacity: 1; visibility: visible; transform: none;
    min-width: 0; background: none; border: 0; box-shadow: none;
    padding: 0 0 6px 0; }
  .navdrop a { color: rgba(255,255,255,.82); padding: 9px 0 9px 18px;
    font-size: .9rem; font-weight: 400; }
  .navdrop a:hover { background: none; color: #08C7FC; }
  .navdrop li { border-top: 1px solid rgba(255,255,255,.10); }
}

/* ---------- Case studies ---------- */
.csmeta { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0 30px;
  border-top: 3px solid var(--accent); border-bottom: 1px solid var(--rule);
  padding: 20px 0; }
.csmeta > div { display: flex; flex-direction: column; gap: 5px; }
.csmeta .k { font-family: var(--display); font-weight: 600; font-size: .72rem;
  letter-spacing: .13em; text-transform: uppercase; color: var(--soft); }
.csmeta .v { font-size: .96rem; line-height: 1.45; color: var(--ink);
  font-weight: 600; }
@media (max-width: 860px) { .csmeta { grid-template-columns: 1fr 1fr; gap: 20px 24px; } }
@media (max-width: 480px) { .csmeta { grid-template-columns: 1fr; } }

.csgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 28px;
  align-items: start; }
.csfig { margin: 0; }
.csfig img { width: 100%; height: auto; display: block; border-radius: 4px; }
.csfig figcaption { margin-top: 10px; font-size: .88rem; color: var(--soft);
  line-height: 1.5; }
@media (max-width: 760px) { .csgrid { grid-template-columns: 1fr; gap: 24px; } }

/* The customer's own account. Long, and it is the point of the page, so it
   gets the reading measure and a quieter ground rather than being squeezed
   into a pull-quote treatment. */
.csquote { margin: 22px 0 0; max-width: none; padding: 26px 34px;
  background: var(--panel-soft); border-left: 4px solid var(--accent);
  border-radius: 0 4px 4px 0; }
.csquote p { font-size: 1.02rem; line-height: 1.75; color: var(--ink);
  margin: 0 0 15px; max-width: 88ch; }
.csquote p:first-child::before { content: "\201C"; }
.csquote p:nth-last-of-type(1)::after { content: "\201D"; }
.csquote .tst-by { margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--rule); }

/* ---------- Page photography ----------
   The lead sits directly under the hero band and overlaps it slightly, so the
   navy block reads as a caption bar for the photograph rather than as a
   separate slab stacked on top of one. */
.lead-shot { margin-top: -34px; margin-bottom: 8px; position: relative; z-index: 2; }
.lead-shot img { width: 100%; height: auto; display: block; border-radius: 4px;
  box-shadow: 0 16px 40px rgba(0,0,0,.22); }
@media (max-width: 700px) { .lead-shot { margin-top: -18px; } }


/* Floated photographs use the scaffold's figure.shot.right / .left, defined
   once near the top of this file. Nothing to add here but the clearfix, so a
   float can never escape its own prose block into the next section. */
.prose::after { content: ""; display: block; clear: both; }

/* Two photographs side by side, for pages where a pair says more than one. */
.shotpair { display: grid; grid-template-columns: 1fr 1fr; gap: 24px;
  margin: 28px 0; }
.shotpair .shot { margin: 0; }
@media (max-width: 700px) { .shotpair { grid-template-columns: 1fr; gap: 20px; } }

/* Quote form error, shown when the server redirects back with ?err=.
   Red on a tinted ground, but it also carries role="alert" so a screen reader
   announces it rather than relying on the colour to communicate. */
.qerr { margin: 0 0 20px; padding: 14px 18px; border-radius: 4px;
  background: #fdecec; border-left: 4px solid #c0392b; color: #7d2018;
  font-size: .95rem; line-height: 1.6; }
