/* ============================================================================
   theme.css - Moore Brothers Print Co.
   Single styling source of truth for the entire site.

   To REBRAND: edit site-config.php -> 'theme' (primary, accent, neutral, bg).
   bootstrap.php injects those as --brand-* custom props into <head>; everything
   below derives from them via color-mix. To restyle a section, edit its block.

   Custom components are namespaced .mbp-*. There is deliberately NO
   `.mbp-page` wrapper: every token lives in :root, so the header, footer, and
   mobile drawer resolve the same variables the page body does. This sidesteps
   the Spark scoping trap (page-scoped --c-* tokens failing on chrome elements
   and silently rendering an invisible nav button).
   ============================================================================ */

/*
  DESIGN DIRECTION - Be Moore Design
  Rebranded 2026-09-08 from Moore Brothers Print Co. Same shop, same six
  services, same one-man operation. Brady Moore trades under his own name now.

  Personality:      rugged, neighborly, fast. Unchanged - only the surface moved.
  Inspiration:      cut vinyl and a squeegee. The mark is white artwork with
                    clipped corners and hard angles, drawn for a dark ground.
                    Sections read as material stacked on a workbench: a deep
                    ground, raised graphite panels, one red mark where it counts.
  Hero pattern:     F "The Card Grid Hero" is retained - the shop still sells six
                    distinct things and a fire chief and a car club president each
                    need to find theirs in one glance.
  Signature moment: the monogram, ghosted large into the hero's top right at low
                    opacity, the way a decal looks on its backing before it is
                    weeded. Replaces the old M5 Mask-Reveal, which filled the word
                    "everything" with a photo of the press. That belonged to the
                    letterpress idea and did not survive the rebrand.
  Section order:    HERO(headline + 6 tiles) -> REBRAND NOTICE -> WHO WE PRINT FOR
                    -> PROBLEM -> HOW IT WORKS (3 steps) -> PROOF -> DECAL
                    SHOWCASE -> DELIVERY PROMISE -> CTA band.
  Font pair:        Chakra Petch (squared display) + Work Sans (body). Both
                    self-hosted. Replaces Alfa Slab One, whose woodtype slab
                    serifs fought the mark's flat terminals.
  Color recipe:     Ink & Vinyl - ink #15171B, graphite #282C34, press red
                    #D62828 carried over, steel #6B6B6B lifted from the logo
                    artwork's own background, stock #F2F0EB for light panels.
  Shape language:   sharp 2px radii, 3px solid rules, flat cards, zero drop shadow.
                    Unchanged, and it suits the new mark better than the old one.
*/

/* ============================================================================
   Fonts - SELF-HOSTED, latin subset only (67KB total).

   Not loaded from Google. Three reasons:
     1. The Google Fonts stylesheet is render-blocking and cost ~670ms.
     2. The late swap from the fallback face shifted every heading on this
        type-heavy design, pushing CLS past 0.1 on mobile and dropping the
        performance score below the gate.
     3. It removes the site's only third-party origin, so nothing about a
        visitor reaches Google. The privacy policy says so - keep it true.

   Preloaded in includes/header.php. `swap` still applies for the brief window
   before the preload lands; the fallback stacks below are chosen to be close
   in width so any flash barely moves.
   ============================================================================ */
/* Chakra Petch is NOT a variable face, so 600 and 700 are two files. Together
   they are 20KB, smaller than the single Alfa Slab One file they replace. */
@font-face {
  font-family: "Chakra Petch";
  src: url("../fonts/chakra-petch-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Chakra Petch";
  src: url("../fonts/chakra-petch-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  /* Variable face: one file covers 400 through 700. */
  font-family: "Work Sans";
  src: url("../fonts/work-sans.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* DARK ONLY. The seeds below ARE the dark scheme. Paired with
     <meta name="color-scheme" content="light"> in header.php and the absence
     of a 'theme_dark' map in site-config.php. The template's dark @media block
     has been removed on purpose - do not reintroduce one without all three. */
  color-scheme: dark;

  /* Brand seeds - DEFAULTS only. bootstrap.php overrides these from config.
     Don't edit values here; edit site-config.php -> 'theme'. */
  --brand-primary:    #D62828;  /* press red */
  --brand-accent:     #D62828;  /* press red */
  --brand-neutral:    #F2F0EB;  /* stock - body type */
  --brand-bg:         #15171B;  /* ink - graphite ground */
  --brand-on-primary: #ffffff;  /* 5.01:1 on press red */

  /* Brand - derived */
  --color-primary:        var(--brand-primary);
  /* Primary and accent are the SAME red now, so the template's original
     color-mix of one into the other returned press red unchanged and buttons
     had no hover state at all. Explicit value instead. It goes DARKER, not
     lighter: lightening press red drops white label contrast below AA almost
     immediately (#E13030 lands on exactly 4.50, and anything lighter fails).
     This clears 6.45:1 against white. */
  --color-primary-hover:  #B81F1F;
  --color-primary-soft:   color-mix(in oklch, var(--brand-primary) 8%, transparent);
  --color-primary-ring:   color-mix(in oklch, var(--brand-primary) 35%, transparent);
  --color-accent:         var(--brand-accent);
  --color-accent-soft:    color-mix(in oklch, var(--brand-accent) 10%, transparent);

  /* Press red is AA-safe as a FILL behind white text (5.01:1) and NOT as text.
     On the graphite ground it lands at 3.58:1 and fails AA for body sizes. Use
     --color-accent for rules, dots and fills; use --color-accent-text for any
     red WORDING. The lightened value below was chosen to clear 4.5:1 against
     BOTH the page ground and the raised card fill, because eyebrows appear on
     both: 6.41:1 on --color-bg, 5.00:1 on --color-bg-elev. Do not darken it
     back toward #D62828 without re-measuring against the card fill. */
  --color-accent-text:    #FF6B5A;

  /* Neutrals. Every value here was measured against both --color-bg and
     --color-bg-elev, since cards sit on the page and text sits on cards.
     --color-text-muted is a warm grey rather than a neutral one, so it belongs
     to the same family as the stock colour. 7.38:1 on the ground,
     5.76:1 on a card. */
  --color-text:        var(--brand-neutral);
  --color-text-muted:  #A9A69E;
  --color-bg:          var(--brand-bg);
  /* Explicit, not a color-mix: mixing stock into ink in oklch drifts blue and
     the banded sections read colder than the cards they sit beside. */
  --color-bg-alt:      #1D2026;
  --color-bg-elev:     #282C34;
  --color-border:      #343943;
  /* Structural, NOT the accent. This token draws the 2px card borders, image
     frames and FAQ dividers in roughly 28 places. Pointing it at press red
     floods the page with red and kills the one-spot-colour rule. The
     deliberate red rules use --color-accent directly. */
  --color-rule:        #565E6B;

  /* The "ink block" surfaces: footer, CTA band, consent bar, work-order
     ticket, flip-card backs. Under Paper & Press these were --brand-primary,
     because primary WAS ink and the page was cream. Primary is now press red,
     so reusing it would render a solid red footer. They get their own token,
     set deeper than the page ground so the blocks still read as separate
     objects now that the whole site is dark. */
  --color-surface-deep: #0F1115;

  /* Status */
  --color-success: #0B7A55;
  --color-error:   #B3261E;

  /* Typography - Chakra Petch (squared display) + Work Sans (body). Both are
     SELF-HOSTED and preloaded in header.php, never fetched from Google.
     Chakra Petch has clipped corners and flat terminals, which is the same
     construction as the logo wordmark. Alfa Slab One, the woodtype face this
     replaces, fought the mark. Fallbacks are condensed-ish so the swap does
     not shift layout. */
  --font-sans:    "Work Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  --font-display: "Chakra Petch", "Arial Narrow", "Roboto Condensed", Impact, sans-serif;
  --font-mono:    ui-monospace, "SF Mono", Menlo, Monaco, Consolas, monospace;

  --fs-display: clamp(2.5rem, 4.4vw + 1rem, 4.25rem);
  --fs-h1: clamp(2rem, 3.4vw + 1rem, 3.125rem);
  --fs-h2: clamp(1.625rem, 2.2vw + 0.9rem, 2.375rem);
  --fs-h3: clamp(1.25rem, 1.2vw + 0.95rem, 1.5rem);
  --fs-h4: 1.0625rem;
  --fs-body: 1.0625rem;
  --fs-lead: 1.1875rem;
  --fs-small: 0.875rem;
  --fs-eyebrow: 0.75rem;

  --lh-tight: 1.06;
  --lh-snug: 1.3;
  --lh-normal: 1.65;

  /* Spacing scale */
  --sp-1: 0.25rem;  --sp-2: 0.5rem;  --sp-3: 0.75rem;
  --sp-4: 1rem;     --sp-5: 1.25rem; --sp-6: 1.5rem;
  --sp-8: 2rem;     --sp-10: 2.5rem; --sp-12: 3rem;
  --sp-16: 4rem;    --sp-20: 5rem;   --sp-24: 6rem;
  --sp-32: 8rem;

  /* Layout */
  --content-max: 74rem;
  --reading-max: 42rem;

  /* Shape language: sharp. The mark has clipped corners, so the page does
     too. No pills anywhere. */
  --radius-sm: 2px;
  --radius-md: 2px;
  --radius-lg: 2px;
  --radius-xl: 2px;
  --rule-weight: 3px;

  /* Header */
  --nav-height: 76px;
  --nav-bg:     color-mix(in oklch, var(--brand-bg) 88%, transparent);
  --nav-blur:   10px;
  /* Was --brand-neutral, which is now the near-white stock colour and would
     draw a 3px white bar under the header. Structural steel instead. */
  --nav-border: var(--color-rule);

  /* Shadows: flat by design. Kept as tokens so template components that
     reference them collapse to nothing instead of breaking. */
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: none;

  /* Motion */
  --ease: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 140ms;
  --dur-base: 240ms;
  --dur-slow: 620ms;
}

/* ============================================================================
   Reset + base
   ============================================================================ */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  scroll-padding-top: calc(var(--nav-height) + 1rem);
}

body {
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-normal);
  color: var(--color-text);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  /* Tooth: a barely-there speckle so the ground reads as a surface rather
     than flat black. --brand-neutral is now the stock colour, so the same two
     gradients that darkened the cream page now lift the dark one. Kept at 4%
     and 3%; anything stronger reads as noise on a dark ground. No image
     request either way. */
  background-image:
    radial-gradient(circle at 1px 1px, color-mix(in oklch, var(--brand-neutral) 4%, transparent) 1px, transparent 0),
    radial-gradient(circle at 1px 1px, color-mix(in oklch, var(--brand-neutral) 3%, transparent) 1px, transparent 0);
  background-size: 22px 22px, 37px 37px;
  background-position: 0 0, 11px 19px;
}

img, picture, video, canvas, svg { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }

body.is-locked { overflow: hidden; }

.skip-link {
  position: absolute; left: -9999px;
  background: var(--color-primary); color: var(--brand-on-primary);
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-sm);
  font-weight: 600;
  z-index: 100;
}
.skip-link:focus { left: var(--sp-4); top: var(--sp-4); }

/* ============================================================================
   Typography
   ============================================================================ */
h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: var(--lh-tight);
  /* Chakra Petch is wide and squared. A touch of negative tracking at display
     sizes closes the gaps between the flat terminals; without it the headings
     read as spaced-out lettering rather than a set headline. */
  letter-spacing: -0.01em;
  /* Only 600 and 700 are self-hosted. Asking for 400 makes the browser pick
     the nearest face on its own, so state the weight rather than inherit it. */
  font-weight: 700;
  color: var(--color-text);
}
h1 { font-size: var(--fs-h1); margin-block: var(--sp-6) var(--sp-4); }
h2 { font-size: var(--fs-h2); margin-block: var(--sp-12) var(--sp-5); }
h3 { font-size: var(--fs-h3); margin-block: var(--sp-8) var(--sp-3); }
h4 { font-size: var(--fs-h4); margin-block: var(--sp-5) var(--sp-2); font-family: var(--font-sans); font-weight: 700; }

p { margin-block: 0 var(--sp-4); max-width: 68ch; }

a {
  color: var(--color-primary);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 3px;
  text-decoration-color: var(--color-accent);
  transition: color var(--dur-fast) var(--ease), text-decoration-color var(--dur-fast) var(--ease);
}
a:hover { color: var(--color-accent-text); text-decoration-color: var(--color-accent-text); }
a:focus-visible {
  outline: 3px solid var(--color-accent);
  outline-offset: 2px;
  border-radius: 0;
}
::selection { background: var(--color-accent); color: #ffffff; }

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--color-bg-alt);
  padding: 0.15em 0.4em;
  border: 1px solid var(--color-border);
}

/* ============================================================================
   Layout
   ============================================================================ */
.container {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--sp-6);
}

main { display: block; min-height: 60vh; }
section + section { margin-top: var(--sp-16); }

.eyebrow {
  display: inline-block;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: var(--fs-eyebrow);
  font-weight: 700;
  font-family: var(--font-sans);
  color: var(--color-accent-text);
  margin-bottom: var(--sp-4);
  padding-bottom: var(--sp-2);
  border-bottom: var(--rule-weight) solid var(--color-accent);
}

/* ============================================================================
   Header / nav
   ============================================================================ */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--nav-height);
  background: var(--nav-bg);
  backdrop-filter: blur(var(--nav-blur)) saturate(140%);
  -webkit-backdrop-filter: blur(var(--nav-blur)) saturate(140%);
  border-bottom: var(--rule-weight) solid var(--nav-border);
}
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--sp-6);
}

.brand {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.25rem;
  letter-spacing: 0;
  color: var(--color-text);
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  text-decoration: none;
}
.brand:hover { text-decoration: none; color: var(--color-accent-text); }
.brand__mark { display: inline-flex; flex-shrink: 0; }
.brand__mark svg { width: 34px; height: 34px; border-radius: 2px; }
/* The mark is a raster <img> since the 2026-09-08 rebrand, in the header and
   the footer. Height-driven with width:auto so the monogram's 646:821 ratio is
   never squashed. The markup still carries width/height attributes so the box
   is reserved before the image lands and the header does not shift on load. */
.brand__mark img { height: 34px; width: auto; display: block; }

.nav-desktop { display: none; }
@media (min-width: 1040px) {
  .nav-desktop { display: flex; align-items: center; gap: var(--sp-2); }
}
.nav-desktop ul {
  list-style: none; padding: 0; margin: 0;
  display: flex; align-items: center; gap: var(--sp-1);
}
.nav-desktop a {
  color: var(--color-text);
  font-weight: 600;
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  text-decoration: none;
  padding: var(--sp-2) var(--sp-3);
  border-radius: 0;
  border-bottom: 2px solid transparent;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.nav-desktop a:hover {
  color: var(--color-accent-text);
  border-bottom-color: var(--color-accent);
  text-decoration: none;
}
.nav-desktop a[aria-current="page"] {
  color: var(--color-text);
  border-bottom-color: var(--color-accent);
}
.nav-desktop a.cta {
  background: var(--color-primary);
  color: var(--brand-on-primary);
  margin-left: var(--sp-4);
  padding: var(--sp-3) var(--sp-5);
  border-bottom-color: transparent;
}
.nav-desktop a.cta:hover {
  background: var(--color-primary-hover);
  color: #ffffff;
  border-bottom-color: transparent;
}

/* Desktop dropdowns */
.has-dropdown { position: relative; }
.has-dropdown > a::after {
  content: "";
  display: inline-block;
  width: 0; height: 0;
  margin-left: 0.45em;
  border-left: 3.5px solid transparent;
  border-right: 3.5px solid transparent;
  border-top: 4px solid var(--color-accent);
  vertical-align: middle;
}
.dropdown {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 250px;
  background: var(--color-bg-elev);
  border: 2px solid var(--color-rule);
  border-radius: 0;
  padding: var(--sp-2);
  list-style: none !important;
  display: flex !important;
  flex-direction: column;
  gap: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition:
    opacity var(--dur-base) var(--ease),
    transform var(--dur-base) var(--ease-out),
    visibility 0s linear var(--dur-base);
}
.has-dropdown:hover > .dropdown,
.has-dropdown:focus-within > .dropdown {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}
/* .nav-desktop ul centres its items, which the dropdown inherited: each link
   shrank to its text, so the hover fill was a small box floating in the panel.
   Stretch the rows so the fill spans the whole panel width. */
.nav-desktop .dropdown { align-items: stretch; }
.dropdown > li { width: 100%; }
.dropdown a {
  display: block;
  padding: var(--sp-3) var(--sp-4);
  font-size: 0.8125rem;
  text-align: left;
  border-bottom: none;
}
.dropdown a:hover { background: var(--color-primary); color: var(--brand-on-primary); }

/* Hamburger */
.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px; height: 46px;
  border: 2px solid var(--color-rule);
  background: transparent;
  border-radius: 0;
  cursor: pointer;
  color: var(--color-text);
}
.nav-toggle:hover { background: var(--color-primary); color: var(--brand-on-primary); }
@media (min-width: 1040px) { .nav-toggle { display: none; } }
.nav-toggle svg { width: 22px; height: 22px; }

/* Mobile drawer - Popover API. Slides + fades; never snaps. */
.nav-mobile {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(360px, 90vw);
  height: 100vh;
  height: 100dvh;
  margin: 0;
  border: none;
  border-left: var(--rule-weight) solid var(--color-rule);
  padding: var(--sp-16) var(--sp-6) var(--sp-6);
  background: var(--color-bg);
  color: var(--color-text);
  overflow-y: auto;
  transform: translateX(100%);
  opacity: 0;
  transition:
    transform var(--dur-base) var(--ease-out),
    opacity   var(--dur-base) var(--ease-out),
    overlay   var(--dur-base) var(--ease-out) allow-discrete,
    display   var(--dur-base) var(--ease-out) allow-discrete;
}
.nav-mobile:popover-open { transform: translateX(0); opacity: 1; }
@starting-style {
  .nav-mobile:popover-open { transform: translateX(100%); opacity: 0; }
}
.nav-mobile::backdrop {
  background: rgba(17,17,17,0);
  transition:
    background var(--dur-base) var(--ease),
    overlay    var(--dur-base) var(--ease) allow-discrete,
    display    var(--dur-base) var(--ease) allow-discrete;
}
.nav-mobile:popover-open::backdrop { background: rgba(17,17,17,0.55); }
@starting-style {
  .nav-mobile:popover-open::backdrop { background: rgba(17,17,17,0); }
}
.nav-mobile__close {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 42px; height: 42px;
  background: transparent; border: 2px solid var(--color-rule);
  border-radius: 0;
  font-size: 1.5rem; line-height: 1; cursor: pointer; color: var(--color-text);
}
.nav-mobile__close:hover { background: var(--color-primary); color: var(--brand-on-primary); }
.nav-mobile ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 0; }
.nav-mobile a {
  display: block;
  padding: var(--sp-3) var(--sp-2);
  border-bottom: 1px solid var(--color-border);
  color: var(--color-text);
  font-weight: 600;
  font-size: 1rem;
  text-decoration: none;
}
.nav-mobile a:hover { color: var(--color-accent-text); text-decoration: none; }
.nav-mobile a[aria-current="page"] { color: var(--color-accent-text); }
.nav-mobile details summary {
  padding: var(--sp-3) var(--sp-2);
  cursor: pointer;
  border-bottom: 1px solid var(--color-border);
  font-weight: 600;
  list-style: none;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.nav-mobile details summary::-webkit-details-marker { display: none; }
.nav-mobile details summary::after {
  content: "+";
  font-size: 1.25rem;
  font-weight: 400;
  color: var(--color-accent-text);
  transition: transform var(--dur-base) var(--ease);
}
.nav-mobile details[open] summary::after { transform: rotate(45deg); }
.nav-mobile details[open] summary { color: var(--color-accent-text); }
.nav-mobile details ul { padding-left: var(--sp-4); margin-bottom: var(--sp-2); }

/* ============================================================================
   Footer - ink block. Everything here must be explicitly re-colored: the page
   tokens assume ink-on-paper, and this section inverts that.
   ============================================================================ */
.site-footer {
  background: var(--color-surface-deep);
  color: #E6E2D8;
  border-top: none;
  padding-block: var(--sp-20) var(--sp-8);
  margin-top: var(--sp-20);
}
.site-footer__grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: var(--sp-12);
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--sp-6);
}
@media (max-width: 900px) { .site-footer__grid { grid-template-columns: 1fr 1fr; gap: var(--sp-8); } }
@media (max-width: 520px) { .site-footer__grid { grid-template-columns: 1fr; } }

/* These three were `color: var(--brand-bg)`. Under Paper & Press --brand-bg
   was bone paper sitting on an ink footer, so it read as near-white. After the
   2026-09-08 rebrand --brand-bg IS the dark ground, which put dark text on a
   darker footer and made the wordmark, the phone link and the social glyphs
   effectively invisible. Same defect as the work-order ticket header. */
.site-footer .brand { color: var(--color-text); }
.site-footer .brand:hover { color: #ffffff; }
.site-footer__tagline { margin-top: var(--sp-4); color: #B9B4A8; max-width: 34ch; }
.site-footer__address {
  font-style: normal;
  margin-top: var(--sp-5);
  color: #B9B4A8;
  font-size: 0.9375rem;
  line-height: 1.8;
}
.site-footer__address a { color: var(--color-text); font-weight: 700; text-decoration-color: var(--color-accent); }
.site-footer__address a:hover { color: #ffffff; }
.site-footer__hours { color: #B9B4A8; }

.site-footer__social { display: flex; flex-direction: row !important; gap: var(--sp-3); margin-top: var(--sp-5); }
.site-footer__social a {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px;
  border: 2px solid #3A3733;
  color: var(--color-text);
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.site-footer__social a:hover { background: var(--color-accent); border-color: var(--color-accent); color: #ffffff; }
.site-footer__social svg { width: 18px; height: 18px; }

/* Footer column titles are <h2> for correct heading order (they follow the
   page's own h2 sections). They are styled down to a small caps label; the
   level is a document-structure decision, the size is a visual one. */
.site-footer h2 {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: #ffffff;
  margin: 0 0 var(--sp-5);
  font-weight: 700;
  padding-bottom: var(--sp-2);
  border-bottom: 2px solid var(--color-accent);
}
.site-footer ul { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--sp-3); }
.site-footer a { color: #E6E2D8; font-size: 0.9375rem; text-decoration: none; }
.site-footer a:hover { color: #ffffff; text-decoration: underline; text-decoration-color: var(--color-accent); }
.site-footer__bottom {
  max-width: var(--content-max);
  margin: var(--sp-16) auto 0;
  padding: var(--sp-6) var(--sp-6) 0;
  border-top: 1px solid #3A3733;
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--sp-4);
  font-size: var(--fs-small);
  color: #B9B4A8;
}
.site-footer__bottom a { color: #E6E2D8; }

/* "Powered by Spark" credit - mandatory, do not remove. The Spark mark keeps
   its fixed brand orange (#f15924) on any footer background. display:inline-block
   is required: the global reset sets `svg { display: block }`, which would drop
   the mark onto its own line below the credit text. */
.spark-mark {
  display: inline-block;
  width: 1.6em;
  height: 1.6em;
  margin-left: 0.15em;
  vertical-align: -0.5em;
}

/* ============================================================================
   Consent banner
   ============================================================================ */
.consent-banner {
  position: fixed;
  left: 50%;
  bottom: var(--sp-4);
  transform: translate(-50%, calc(100% + var(--sp-8)));
  z-index: 90;
  width: min(660px, calc(100vw - var(--sp-8)));
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-4) var(--sp-6);
  padding: var(--sp-5);
  background: var(--color-surface-deep);
  color: #E6E2D8;
  border: none;
  border-top: var(--rule-weight) solid var(--color-accent);
  border-radius: 0;
  opacity: 0;
  transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}
.consent-banner.is-visible { transform: translate(-50%, 0); opacity: 1; }
.consent-banner__text {
  flex: 1 1 16rem;
  margin: 0;
  max-width: none;
  font-size: var(--fs-small);
  line-height: 1.55;
  color: #C9C4B8;
}
.consent-banner__text a { color: #ffffff; font-weight: 700; }
.consent-banner__actions { display: flex; gap: var(--sp-3); flex-shrink: 0; }
.consent-banner__actions .btn { padding: var(--sp-2) var(--sp-5); font-size: 0.875rem; }
.consent-banner__actions .btn-primary { background: var(--color-accent); color: #ffffff; }
.consent-banner__actions .btn-primary:hover { background: #ffffff; color: var(--brand-primary); }
.consent-banner__actions .btn-ghost { color: #E6E2D8; border-color: #55504A; }
.consent-banner__actions .btn-ghost:hover { background: #2A2724; color: #ffffff; }
@media (max-width: 560px) {
  .consent-banner { bottom: 0; width: 100vw; }
  .consent-banner__actions { width: 100%; }
  .consent-banner__actions .btn { flex: 1; }
}

/* ============================================================================
   Buttons - hard-edged. The primary presses INTO the page on click (no lift).
   ============================================================================ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-6);
  font-family: var(--font-sans);
  font-size: 0.875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  border-radius: 0;
  border: 2px solid transparent;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }

.btn-primary {
  background: var(--color-primary);
  color: var(--brand-on-primary);
  border-color: var(--color-primary);
}
.btn-primary:hover {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
  color: #ffffff;
}
.btn-ghost {
  background: transparent;
  color: var(--color-text);
  border-color: var(--color-rule);
}
.btn-ghost:hover { background: var(--color-primary); color: var(--brand-on-primary); }

.btn-lg { padding: var(--sp-4) var(--sp-8); font-size: 0.9375rem; }

/* ============================================================================
   Forms
   ============================================================================ */
.form { display: grid; gap: var(--sp-5); max-width: 40rem; }
.form-row { display: grid; gap: var(--sp-2); }
.form label {
  font-weight: 700;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}
.form input, .form textarea, .form select {
  width: 100%;
  padding: var(--sp-3) var(--sp-4);
  border: 2px solid var(--color-rule);
  border-radius: 0;
  background: var(--color-bg-elev);
  color: var(--color-text);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.form input:focus, .form textarea:focus, .form select:focus {
  outline: none;
  border-color: var(--color-accent);
  box-shadow: inset 0 0 0 2px color-mix(in oklch, var(--brand-accent) 22%, transparent);
}
.form textarea { min-height: 150px; resize: vertical; }
.form .hp { position: absolute; left: -10000px; opacity: 0; pointer-events: none; }
.form-help { font-size: var(--fs-small); color: var(--color-text-muted); }
.form-status { padding: var(--sp-4); border-radius: 0; display: none; font-size: 0.9375rem; }
.form-status[data-state="ok"]    { display: block; background: color-mix(in oklch, var(--color-success) 10%, transparent); color: var(--color-success); border: 2px solid var(--color-success); }
.form-status[data-state="error"] { display: block; background: color-mix(in oklch, var(--color-error) 10%, transparent);   color: var(--color-error);   border: 2px solid var(--color-error); }

/* Two-up form fields on wider screens */
@media (min-width: 640px) {
  .mbp-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-5); }
}

/* ============================================================================
   Hero - Pattern F "Card Grid Hero", carrying the M5 mask-reveal signature.
   The template's radial-glow + dotted-grid hero is replaced wholesale.
   ============================================================================ */
.mbp-hero {
  position: relative;
  isolation: isolate;
  padding-block: var(--sp-16) var(--sp-12);
  border-bottom: var(--rule-weight) solid var(--color-rule);
  overflow: hidden;
}
/* The signature moment. The monogram sits oversized in the top right at low
   opacity, the way a cut decal looks on its backing before it is weeded. It is
   decorative only - the mark is already in the header as a real <img> with alt
   text, so this one is a background and is invisible to screen readers.
   z-index keeps it under the copy; .mbp-hero sets `isolation: isolate` so the
   stack cannot escape the section. */
.mbp-hero::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: -8%;
  right: -6%;
  width: min(46vw, 430px);
  aspect-ratio: 646 / 821;
  background-image: url("../../images/brand/bemoore-monogram-large.png");
  background-size: contain;
  background-repeat: no-repeat;
  opacity: 0.06;
  pointer-events: none;
}
@media (max-width: 1039px) {
  /* Below the two-column breakpoint the copy runs full width and would sit on
     top of the mark, so it moves out of the text's way and shrinks. */
  .mbp-hero::before { width: min(60vw, 300px); top: auto; bottom: -4%; right: -12%; opacity: 0.05; }
}
/* One word of the headline in press red. Uses the LIGHTENED red: the brand
   #D62828 measures 3.58:1 as text on this ground and fails AA. */
.mbp-hero__accent { color: var(--color-accent-text); }
/* Phones: the eyebrow's red rule sat 16px above the headline caps and read as
   butted against them. Give it the same air the rule under the headline gets. */
@media (max-width: 767px) {
  .mbp-hero .eyebrow { padding-bottom: var(--sp-3); margin-bottom: var(--sp-8); }
}
.mbp-hero__inner {
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--sp-6);
}
/* Above 1040px the headline column shares the row with the job ticket, so the
   right half of the hero is not just dead paper. Below that the ticket drops
   under the copy and the headline goes full width. */
.mbp-hero__top { display: grid; grid-template-columns: 1fr; gap: var(--sp-12); }
@media (min-width: 1040px) {
  .mbp-hero__top { grid-template-columns: 1.5fr 1fr; gap: var(--sp-16); align-items: start; }
}

/* --- The job ticket ------------------------------------------------------
   A print shop's work order, pinned to the hero. Ink header bar, ruled rows,
   and a red "APPROVED" stamp rotated off-axis. Pure CSS, no image. This is the
   piece that makes the hero feel like it came out of THIS shop.
   ------------------------------------------------------------------------ */
.mbp-ticket {
  position: relative;
  border: 2px solid var(--color-rule);
  background: var(--color-bg-elev);
  align-self: start;
}
.mbp-ticket__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--sp-4);
  background: var(--color-surface-deep);
  /* Was --brand-bg, which used to be bone paper against an ink bar. Both are
     dark now, so that rendered near-black on near-black and the words vanished. */
  color: var(--color-text);
  padding: var(--sp-3) var(--sp-5);
}
.mbp-ticket__title {
  font-family: var(--font-display);
  font-size: 0.9375rem;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.mbp-ticket__no {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.08em;
  color: #B9B4A8;
}
/* Room at the bottom so the rotated stamp never sits on top of the last row. */
.mbp-ticket__rows { list-style: none; margin: 0; padding: 0 0 var(--sp-12); }
.mbp-ticket__rows li {
  display: flex;
  gap: var(--sp-4);
  align-items: flex-start;
  padding: var(--sp-4) var(--sp-5);
  border-bottom: 1px dashed var(--color-border);
  font-size: 0.9375rem;
  line-height: 1.4;
}
.mbp-ticket__rows li:last-child { border-bottom: none; }
.mbp-ticket__rows svg { width: 22px; height: 22px; color: var(--color-accent-text); flex-shrink: 0; }
.mbp-ticket__rows strong { display: block; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--color-text-muted); font-weight: 700; }
.mbp-ticket__stamp {
  position: absolute;
  right: var(--sp-4);
  bottom: var(--sp-4);
  transform: rotate(-8deg);
  border: 3px solid var(--color-accent);
  color: var(--color-accent-text);
  font-family: var(--font-display);
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: var(--sp-1) var(--sp-3);
  opacity: 0.85;
  pointer-events: none;
}
/* No max-width: the hero column already constrains this, and a ch-based cap
   left the word "and" stranded alone on its own line at 1440px. The size is
   tuned so "SIGNS, SHIRTS, AND" holds together on one line. */
.mbp-hero__title {
  font-size: clamp(2.375rem, 3.4vw + 0.9rem, 3.75rem);
  line-height: 1.0;
  margin: 0 0 var(--sp-6);
  text-transform: uppercase;
}
.mbp-hero__lead {
  font-size: var(--fs-lead);
  color: var(--color-text-muted);
  max-width: 54ch;
  margin-bottom: var(--sp-8);
  line-height: 1.55;
}
.mbp-hero__actions { display: flex; gap: var(--sp-4); flex-wrap: wrap; align-items: center; }
.mbp-hero__phone {
  font-family: var(--font-display);
  font-size: 1.25rem;
  color: var(--color-text);
  text-decoration: none;
  border-bottom: var(--rule-weight) solid var(--color-accent);
  padding-bottom: 2px;
}
.mbp-hero__phone:hover { color: var(--color-accent-text); }

/* --- M5: Mask-Reveal - RETIRED 2026-09-08 -----------------------------------
   The word "everything" in the old headline was filled with a photograph of
   the press, clipped out of the image so the headline became the thing the
   shop makes. It was the signature moment of the Paper & Press brand and it
   depended on that brand: a dark photo reading as inked type against bone
   paper. On the graphite ground the effect inverts and the letters go muddy.

   Removed rather than restyled. The hero is type-led now, and the signature
   moment is the ghosted monogram at .mbp-hero::before.

   The markup that used it is gone from index.php. Nothing references .mbp-mask
   any more, so the rules are deleted rather than left to rot. The press
   photograph itself is still in images/Photos/ and is still used elsewhere.
   ---------------------------------------------------------------------------- */

/* The red rule that draws itself under the headline on load. */
.mbp-hero__rule {
  height: var(--rule-weight);
  background: var(--color-accent);
  width: min(340px, 60%);
  margin-bottom: var(--sp-8);
  transform-origin: left center;
  animation: mbp-rule-draw var(--dur-slow) var(--ease-out) 120ms both;
}
@keyframes mbp-rule-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

/* --- Pattern F: the six service tiles, in the hero ------------------------ */
/* Column counts are EXPLICIT, never auto-fit. There are exactly six tiles, and
   auto-fit resolved to five across at 1440px, leaving one orphan tile beside a
   dead black cell (the parent's ink background showing through the gap). Fixed
   1 / 2 / 3 columns always divides six evenly. */
.mbp-tiles {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  margin-top: var(--sp-16);
  border: 2px solid var(--color-rule);
  background: var(--color-rule);
}
@media (min-width: 560px)  { .mbp-tiles { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .mbp-tiles { grid-template-columns: repeat(4, 1fr); } }
.mbp-tile {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6) var(--sp-5) var(--sp-5);
  background: var(--color-bg);
  color: var(--color-text);
  text-decoration: none;
  /* 1px of the parent's ink background shows through as a hairline rule. */
  outline: 1px solid var(--color-rule);
  transition: background var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}
.mbp-tile:hover, .mbp-tile:focus-visible {
  background: var(--color-primary);
  color: var(--brand-on-primary);
  text-decoration: none;
  outline-color: var(--color-rule);
}
.mbp-tile__icon { width: 30px; height: 30px; color: var(--color-accent); flex-shrink: 0; }
/* HOVER FILL IS PRESS RED NOW. Under Paper & Press the tile's hover fill was
   ink, so a red icon, a red "see more" link and a warm-grey note all read fine
   against it. --color-primary is press red after the 2026-09-08 rebrand, which
   left the icon and the link at red-on-red (1.00:1, literally invisible) and
   the note at 2.42:1. White is the only value that clears AA on this fill at
   5.01:1 - every pink tint tried fails, #FFECEC included. Hierarchy inside the
   hovered tile is carried by size and weight instead of by colour. */
.mbp-tile:hover .mbp-tile__icon,
.mbp-tile:focus-visible .mbp-tile__icon { color: var(--brand-on-primary); }
.mbp-tile__name {
  font-family: var(--font-display);
  font-size: 1.0625rem;
  line-height: 1.15;
  text-transform: uppercase;
}
.mbp-tile__note { font-size: 0.8125rem; color: var(--color-text-muted); margin: 0; }
.mbp-tile:hover .mbp-tile__note,
.mbp-tile:focus-visible .mbp-tile__note { color: var(--brand-on-primary); }
.mbp-tile__go {
  margin-top: auto;
  padding-top: var(--sp-3);
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--color-accent-text);
}
.mbp-tile:hover .mbp-tile__go,
.mbp-tile:focus-visible .mbp-tile__go { color: var(--brand-on-primary); }

/* ============================================================================
   Interior page header (every page except home)
   ============================================================================ */
/* The breadcrumb trail sits in a plain <div>, not a <section>, so it breaks the
   `section + section` adjacency and the first content section inherits NO top
   margin. Worse, render_breadcrumbs() prints nothing on two-level pages, leaving
   an empty div behind - so on /about, /contact, /services, /service-area and
   /privacy-policy the first heading collided with this band's bottom rule.
   Spacing is therefore owned here, by the page head itself. */
.mbp-pagehead {
  padding-block: var(--sp-16) var(--sp-12);
  margin-bottom: var(--sp-12);
  border-bottom: var(--rule-weight) solid var(--color-rule);
  background: var(--color-bg-alt);
}
.mbp-pagehead h1 { margin: 0 0 var(--sp-5); max-width: 20ch; text-transform: uppercase; }
.mbp-pagehead p { font-size: var(--fs-lead); color: var(--color-text-muted); max-width: 58ch; margin: 0; }
/* Action row inside a page head (used by 404). */
.mbp-pagehead__actions {
  display: flex;
  gap: var(--sp-4);
  flex-wrap: wrap;
  align-items: center;
  margin-top: var(--sp-8);
}

/* ============================================================================
   Generic sections
   ============================================================================ */
.section-title { margin-bottom: var(--sp-12); }
.section-title h2 { margin-top: 0; text-transform: uppercase; max-width: 20ch; }
.section-title p { color: var(--color-text-muted); font-size: var(--fs-lead); }
.section-title--center { text-align: center; }
.section-title--center h2 { margin-inline: auto; }
.section-title--center p { margin-inline: auto; }
.section-title--center .eyebrow { display: inline-block; }

/* NOTE: the Spark template's stock components (.hero, .cards/.card, .stats,
   .cta-band, .hero__highlight) are deliberately ABSENT from this stylesheet.
   This site does not use them. Every section below is built for Moore Bros, and
   the only thing inherited from the template is the PHP shell: bootstrap.php,
   the header/footer plumbing, the mail handler, and the schema helpers. If you
   paste stock Spark markup into a page it will render unstyled - that is the
   intended behaviour, not a bug. Build the section instead. */

/* --- "Who we print for" strip --------------------------------------------- */
.mbp-audience {
  border-block: var(--rule-weight) solid var(--color-rule);
  padding-block: var(--sp-10);
  background: var(--color-bg-alt);
}
/* Sit flush under the hero. Otherwise `section + section` opens a bone gap
   between the hero's bottom rule and this band's top rule, and the two rules
   read as a mistake rather than a seam. */
.mbp-hero + .mbp-audience {
  margin-top: 0;
  border-top: none;
}
.mbp-audience__list {
  list-style: none; padding: 0; margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--sp-8) var(--sp-6);
}
.mbp-audience__item { display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); text-align: center; }
.mbp-audience__item svg { width: 32px; height: 32px; color: var(--color-accent-text); }
.mbp-audience__item span {
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

/* --- Big statement / problem block ---------------------------------------- */
/* No ch cap - the .mbp-two column already sets the measure. */
.mbp-statement { max-width: none; }
/* Capped well below --fs-display: this heading lives in the NARROW column of
   .mbp-two. At 3rem Alfa Slab it broke to two or three words per line, and even
   2.375rem left "THERE IS NO PICKUP COUNTER, AND THAT IS THE POINT." on five
   ragged lines. */
.mbp-statement h2 {
  font-size: clamp(1.625rem, 1.25vw + 1.05rem, 2.125rem);
  line-height: 1.1;
  text-transform: uppercase;
  margin-top: 0;
}
.mbp-statement__body { max-width: 60ch; }
.mbp-statement__body p { font-size: var(--fs-lead); color: var(--color-text-muted); }
.mbp-two {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-10);
}
@media (min-width: 900px) {
  .mbp-two { grid-template-columns: 1fr 1.15fr; gap: var(--sp-16); align-items: start; }
}

/* --- The 3-step plan ------------------------------------------------------ */
.mbp-steps {
  list-style: none; padding: 0; margin: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--sp-8);
  counter-reset: mbp-step;
}
.mbp-step { position: relative; padding-top: var(--sp-10); border-top: var(--rule-weight) solid var(--color-rule); }
.mbp-step::before {
  counter-increment: mbp-step;
  content: "0" counter(mbp-step);
  position: absolute;
  top: var(--sp-4);
  left: 0;
  font-family: var(--font-display);
  font-size: 2.75rem;
  line-height: 1;
  color: var(--color-accent);
  opacity: 0.4;
}
.mbp-step h3 { margin-top: var(--sp-8); margin-bottom: var(--sp-3); text-transform: uppercase; font-size: 1.25rem; }
.mbp-step p { color: var(--color-text-muted); margin: 0; }

/* --- Proof: testimonials + credential row --------------------------------- */
.mbp-quotes { display: grid; grid-template-columns: 1fr; gap: var(--sp-6); }
@media (min-width: 820px) { .mbp-quotes { grid-template-columns: 1fr 1fr; } }
.mbp-quote {
  padding: var(--sp-8);
  border: 2px solid var(--color-rule);
  background: var(--color-bg-elev);
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
}
.mbp-quote__mark { font-family: var(--font-display); font-size: 3rem; line-height: 0.6; color: var(--color-accent); }
.mbp-quote blockquote { margin: 0; font-size: 1.1875rem; line-height: 1.5; }
.mbp-quote figcaption { font-size: var(--fs-small); color: var(--color-text-muted); margin-top: auto; }
.mbp-quote figcaption strong { color: var(--color-text); display: block; font-size: 0.9375rem; }

.mbp-creds {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 0;
  margin-top: var(--sp-10);
  border: 2px solid var(--color-rule);
  background: var(--color-rule);
}
.mbp-cred { background: var(--color-bg); padding: var(--sp-6); text-align: center; outline: 1px solid var(--color-rule); }
.mbp-cred__num {
  font-family: var(--font-display);
  font-size: clamp(1.75rem, 2.4vw + 1rem, 2.5rem);
  line-height: 1;
  color: var(--color-text);
}
.mbp-cred__label {
  margin-top: var(--sp-2);
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-text-muted);
}

/* --- Split: image + copy, alternating sides ------------------------------- */
.mbp-split {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-10);
  align-items: center;
}
@media (min-width: 900px) {
  .mbp-split { grid-template-columns: 1.1fr 1fr; gap: var(--sp-16); }
  .mbp-split--reverse .mbp-split__media { order: 2; }
  .mbp-split--wide-media { grid-template-columns: 1.35fr 1fr; }
}
.mbp-split__media img { width: 100%; border: 2px solid var(--color-rule); border-radius: 2px; }
.mbp-split__body h2 { margin-top: 0; text-transform: uppercase; }
.mbp-split__body p { color: var(--color-text-muted); }

/* A flat bullet list with red ticks. */
.mbp-list { list-style: none; padding: 0; margin: 0 0 var(--sp-8); display: grid; gap: var(--sp-3); }
.mbp-list li { display: flex; gap: var(--sp-3); align-items: flex-start; line-height: 1.5; }
.mbp-list li::before {
  content: "";
  flex-shrink: 0;
  width: 10px; height: 10px;
  margin-top: 0.5em;
  background: var(--color-accent);
}

/* --- CTA band: an ink block, not a gradient ------------------------------- */
/* margin-bottom is 0: the CTA is always the last section, and .site-footer's
   own margin-top supplies the gap. Both together left a ~210px void of bare
   paper between the ink band and the ink footer. */
.mbp-cta {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding: var(--sp-20) var(--sp-6);
  background: var(--color-surface-deep);
  color: #ffffff;
  border-radius: 0;
  margin-block: var(--sp-8) 0;
}
.mbp-cta::before {
  /* A press-red bar bleeding off the top-left corner. */
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 42%;
  height: var(--rule-weight);
  background: var(--color-accent);
}
.mbp-cta h2 { color: #ffffff; margin-top: 0; text-transform: uppercase; max-width: 22ch; margin-inline: auto; }
.mbp-cta p { color: #C9C4B8; margin-inline: auto; max-width: 52ch; font-size: var(--fs-lead); }
.mbp-cta__actions { display: flex; gap: var(--sp-4); justify-content: center; flex-wrap: wrap; margin-top: var(--sp-8); align-items: center; }
.mbp-cta .btn-primary { background: var(--color-accent); border-color: var(--color-accent); color: #ffffff; }
.mbp-cta .btn-primary:hover { background: #ffffff; border-color: #ffffff; color: var(--brand-primary); }
.mbp-cta .btn-ghost { color: #ffffff; border-color: #55504A; }
.mbp-cta .btn-ghost:hover { background: #ffffff; color: var(--brand-primary); border-color: #ffffff; }
.mbp-cta__phone { display: block; margin-top: var(--sp-6); color: #C9C4B8; font-size: var(--fs-small); }
.mbp-cta__phone a { color: #ffffff; font-weight: 700; }

/* ============================================================================
   M6 - Card flip (services hub only). Front shows the service; back shows the
   working detail (materials, turnaround) plus the CTA. Disabled under
   reduced-motion, where both faces stack instead.
   ============================================================================ */
.mbp-flips {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-6);
}
@media (min-width: 640px)  { .mbp-flips { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1200px) { .mbp-flips { grid-template-columns: repeat(4, 1fr); } }
.mbp-flip { perspective: 1200px; height: 340px; }
.mbp-flip__inner {
  position: relative;
  width: 100%; height: 100%;
  transform-style: preserve-3d;
  transition: transform var(--dur-slow) var(--ease-out);
}
.mbp-flip:hover .mbp-flip__inner,
.mbp-flip:focus-within .mbp-flip__inner { transform: rotateY(180deg); }
.mbp-flip__face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border: 2px solid var(--color-rule);
  padding: var(--sp-8) var(--sp-6);
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
}
.mbp-flip__front { background: var(--color-bg-elev); }
.mbp-flip__front svg { width: 34px; height: 34px; color: var(--color-accent-text); }
.mbp-flip__front h3 { margin: var(--sp-3) 0 var(--sp-2); text-transform: uppercase; font-size: 1.25rem; }
.mbp-flip__front p { color: var(--color-text-muted); margin: 0; font-size: 0.9375rem; }
.mbp-flip__hint {
  margin-top: auto;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--color-accent-text);
}
.mbp-flip__back {
  background: var(--color-surface-deep);
  color: #E6E2D8;
  transform: rotateY(180deg);
}
.mbp-flip__back h3 { color: #ffffff; margin: 0 0 var(--sp-2); text-transform: uppercase; font-size: 1.125rem; }
.mbp-flip__back ul { list-style: none; padding: 0; margin: 0 0 var(--sp-5); display: grid; gap: var(--sp-2); font-size: 0.9375rem; }
.mbp-flip__back li { display: flex; gap: var(--sp-3); }
.mbp-flip__back li::before { content: ""; flex-shrink: 0; width: 8px; height: 8px; margin-top: 0.55em; background: var(--color-accent); }
.mbp-flip__back .btn { margin-top: auto; align-self: flex-start; }

/* Fallback for anyone who cannot flip a card: reduced-motion users, and touch
   devices with no hover. Both faces stack into one continuous card.

   The back face repeats the service name as an <h3> so it still reads as a
   titled panel when it is the only thing you can see. Once the faces are
   stacked that title is a DUPLICATE sitting directly under the front one, so
   it is removed from the accessibility tree here rather than merely hidden. */
@media (prefers-reduced-motion: reduce), (hover: none) {
  /* Stretch to the tallest card in the row so the ink back-panels line up,
     instead of each card ending wherever its own copy happens to stop. */
  .mbp-flip { height: auto; perspective: none; display: flex; }
  .mbp-flip__inner {
    transform: none !important;
    transform-style: flat;
    display: flex;
    flex-direction: column;
    width: 100%;
  }
  .mbp-flip__face { position: static; backface-visibility: visible; -webkit-backface-visibility: visible; }
  .mbp-flip__front { border-bottom: none; flex: 1 0 auto; }
  .mbp-flip__back { transform: none; border-top: none; flex: 1 0 auto; }
  .mbp-flip__back h3 { display: none; }
  .mbp-flip__back ul { margin-top: 0; }
  .mbp-flip__hint { display: none; }
}

/* ============================================================================
   M2 - Magazine overlap (about page). The copy card sits over the photo.
   ============================================================================ */
/* Mobile: photo, then the copy card pulled up over its bottom edge. */
.mbp-overlap__media img { width: 100%; border: 2px solid var(--color-rule); }
.mbp-overlap__card {
  background: var(--color-bg);
  border: var(--rule-weight) solid var(--color-rule);
  padding: var(--sp-8);
  margin-top: calc(var(--sp-10) * -1);
  margin-inline: var(--sp-4);
  position: relative;
}
.mbp-overlap__card h2 { margin-top: 0; text-transform: uppercase; }
.mbp-overlap__card p:last-child { margin-bottom: 0; }

/* Desktop: a real 12-column overlap rather than absolute positioning.
   The old version pinned the card to the image's bottom edge, so whenever the
   card's text ran taller than the photo it grew UPWARD and towered over it -
   which is exactly what happened on /about. Sharing one grid cell and centring
   both keeps the card locked to the middle of the photo at any copy length. */
@media (min-width: 940px) {
  .mbp-overlap {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    align-items: center;
  }
  .mbp-overlap__media {
    grid-column: 1 / span 8;
    grid-row: 1;
  }
  .mbp-overlap__card {
    grid-column: 6 / span 7;
    grid-row: 1;
    z-index: 1;
    margin: 0;
    align-self: center;
  }
}

/* ============================================================================
   M7 - Scroll-driven text reveal (service area). Rows fade + rise in sequence.
   Purely below the fold; the first viewport always paints complete.
   ============================================================================ */
.mbp-cities {
  list-style: none; padding: 0; margin: 0;
  border-top: var(--rule-weight) solid var(--color-rule);
}
.mbp-city {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-5);
  flex-wrap: wrap;
  padding: var(--sp-5) var(--sp-2);
  border-bottom: 1px solid var(--color-border);
}
.mbp-city__name { font-family: var(--font-display); font-size: clamp(1.25rem, 1.6vw + 1rem, 1.875rem); text-transform: uppercase; }
.mbp-city__note { font-size: 0.8125rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.1em; color: var(--color-accent-text); }
.mbp-city__note--ship { color: var(--color-text-muted); }

/* ============================================================================
   FAQ (details/summary) - no JS
   ============================================================================ */
.mbp-faq { border-top: var(--rule-weight) solid var(--color-rule); max-width: 56rem; }
.mbp-faq details { border-bottom: 1px solid var(--color-border); }
.mbp-faq summary {
  cursor: pointer;
  list-style: none;
  padding: var(--sp-5) var(--sp-10) var(--sp-5) 0;
  position: relative;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  text-transform: uppercase;
  line-height: 1.3;
}
.mbp-faq summary::-webkit-details-marker { display: none; }
.mbp-faq summary::after {
  content: "+";
  position: absolute;
  right: 0; top: 50%;
  transform: translateY(-50%);
  font-size: 1.5rem;
  color: var(--color-accent-text);
  transition: transform var(--dur-base) var(--ease);
}
.mbp-faq details[open] summary::after { transform: translateY(-50%) rotate(45deg); }
.mbp-faq details p { padding-bottom: var(--sp-5); color: var(--color-text-muted); margin: 0; }

/* ============================================================================
   Spec table (service pages) - materials, sizes, turnaround
   ============================================================================ */
.mbp-spec { border-top: var(--rule-weight) solid var(--color-rule); }
.mbp-spec__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-2);
  padding: var(--sp-5) 0;
  border-bottom: 1px solid var(--color-border);
}
@media (min-width: 720px) { .mbp-spec__row { grid-template-columns: 14rem 1fr; gap: var(--sp-8); } }
.mbp-spec__key {
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-accent-text);
  padding-top: 0.2em;
}
.mbp-spec__val { color: var(--color-text-muted); margin: 0; }

/* ============================================================================
   Contact page
   ============================================================================ */
.mbp-contact { display: grid; grid-template-columns: 1fr; gap: var(--sp-16); }
@media (min-width: 940px) { .mbp-contact { grid-template-columns: 1.2fr 1fr; gap: var(--sp-20); } }
.mbp-contact__aside { align-self: start; }
.mbp-reach { border-top: var(--rule-weight) solid var(--color-rule); margin-bottom: var(--sp-10); }
.mbp-reach__row { display: flex; gap: var(--sp-5); padding: var(--sp-5) 0; border-bottom: 1px solid var(--color-border); align-items: flex-start; }
.mbp-reach__row svg { width: 26px; height: 26px; color: var(--color-accent-text); flex-shrink: 0; margin-top: 2px; }
.mbp-reach__label { font-size: 0.6875rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.12em; color: var(--color-text-muted); }
.mbp-reach__value { font-family: var(--font-display); font-size: 1.25rem; line-height: 1.2; }
.mbp-reach__value a { text-decoration: none; }
.mbp-reach__value a:hover { color: var(--color-accent-text); }
.mbp-reach__sub { font-size: 0.875rem; color: var(--color-text-muted); margin: var(--sp-1) 0 0; }

/* Reading content */
.prose { max-width: var(--reading-max); }
.prose h2:first-child, .prose h1:first-child { margin-top: 0; }
.prose h2 { text-transform: uppercase; }
.prose ul, .prose ol { margin: 0 0 var(--sp-5); padding-left: var(--sp-6); }
.prose li { margin-bottom: var(--sp-2); }

:target { scroll-margin-top: calc(var(--nav-height) + var(--sp-6)); }

/* ============================================================================
   Breadcrumbs
   ============================================================================ */
/* Top spacing comes from .mbp-pagehead's margin-bottom (see note there). This
   only has to separate the trail from the content it introduces. */
.breadcrumbs {
  font-size: var(--fs-small);
  color: var(--color-text-muted);
  margin-top: 0;
  margin-bottom: var(--sp-10);
}
.breadcrumbs ol {
  list-style: none; padding: 0; margin: 0;
  display: flex; flex-wrap: wrap; gap: var(--sp-2); align-items: center;
}
.breadcrumbs li { display: inline-flex; align-items: center; gap: var(--sp-2); }
/* ASCII-only: a slash, not a chevron glyph. */
.breadcrumbs li:not(:last-child)::after { content: "/"; color: var(--color-accent); font-weight: 700; }
.breadcrumbs a { color: var(--color-text-muted); text-decoration: none; }
.breadcrumbs a:hover { color: var(--color-accent-text); text-decoration: underline; }
.breadcrumbs [aria-current="page"] { color: var(--color-text); font-weight: 600; }

/* ============================================================================
   Reveal-on-scroll (below the fold ONLY)

   The first viewport must paint complete on a cold load, so no element above
   the fold may carry .mbp-reveal. Elements start visible and are only hidden
   once JS confirms IntersectionObserver support (the .mbp-js class on <html>),
   so a no-JS visitor sees everything.
   ============================================================================ */
.mbp-js .mbp-reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out);
}
.mbp-js .mbp-reveal.is-in { opacity: 1; transform: none; }
.mbp-js .mbp-reveal[data-delay="1"] { transition-delay: 90ms; }
.mbp-js .mbp-reveal[data-delay="2"] { transition-delay: 180ms; }
.mbp-js .mbp-reveal[data-delay="3"] { transition-delay: 270ms; }
.mbp-js .mbp-reveal[data-delay="4"] { transition-delay: 360ms; }
.mbp-js .mbp-reveal[data-delay="5"] { transition-delay: 450ms; }

/* ============================================================================
   Accessibility & motion
   ============================================================================ */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .mbp-js .mbp-reveal { opacity: 1; transform: none; }
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

/* ============================================================================
   Rebrand notice band  -  added 2026-09-08
   Markup: includes/rebrand-notice.php, included once from header.php.

   Press red is the one place the brand colour gets to fill a whole block, so
   the changeover is the loudest thing on the page exactly once.

   CONTRAST: the body line is pure WHITE, not a tinted pink. White on #D62828
   measures 5.01:1 and passes AA. The obvious tint (#FFE3E3) measures 4.14:1
   and fails, as does every softer pink tried. The two lines are separated by
   weight and size instead of by colour. Do not "soften" the second line.
   ============================================================================ */
.mbp-rebrand {
  background: var(--color-accent);
  color: #ffffff;
  padding-block: var(--sp-6);
  border-bottom: var(--rule-weight) solid var(--color-surface-deep);
}
.mbp-rebrand__inner {
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--sp-6);
  display: flex;
  align-items: center;
  gap: var(--sp-5);
}
.mbp-rebrand__mark { flex-shrink: 0; width: 26px; height: auto; }
.mbp-rebrand__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.0625rem, 1.4vw + 0.75rem, 1.375rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0;
  color: #ffffff;
}
.mbp-rebrand__body {
  margin: var(--sp-2) 0 0;
  font-size: var(--fs-small);
  line-height: 1.5;
  max-width: 62ch;
  color: #ffffff;
}
/* KNOWN TRAP, already documented further up this file: the site sets
   `section + section { margin-top: var(--sp-16) }`. This band is the first
   <section> inside <main>, which makes the hero an adjacent sibling for the
   first time and drops a 4rem gap between the band and the hero on every page.
   Reset it here rather than by changing the band's element type. */
.mbp-rebrand + section { margin-top: 0; }

@media (max-width: 640px) {
  .mbp-rebrand__inner { align-items: flex-start; gap: var(--sp-4); }
}

/* ============================================================================
   Consent banner  -  the [hidden] guard.

   Deferred on 2026-08-04 with a note to fold it into the launch deploy, which
   is this one. theme.css styles .consent-banner with a display value, and that
   beats the user-agent `[hidden] { display: none }` the dismiss logic relies
   on. Without this line the bar fades out correctly but never leaves the
   layout, and an invisible, still-focusable "Got it" button stays in the
   keyboard tab order on every page.

   Verify after deploying by dismissing the bar and checking
   getComputedStyle(banner).display === 'none'. Do NOT test with
   getBoundingClientRect().height, which stays truthy at opacity: 0.
   ============================================================================ */
.consent-banner[hidden] { display: none; }
