:root{
  --m-color-primary: #225985;
  --m-color-secondary: #1a2744;
  --m-color-accent: #cf8e25;
  --m-color-text: #45505d;
  --m-color-muted: #7f8ea1;
  --m-color-border: #d8dee8;
  --m-color-bg: #ffffff;
  --m-color-surface: #f5f7fa;
  --m-color-user1: #161e2a;
  --m-color-user2: #5cb8e4;
  --m-color-user3: #16a34a;
  --m-color-user4: #dc2626;
  --m-font-heading: 'BlinkMacSystemFont','SF Pro Display','SF Pro Text','Helvetica Neue','Arial',sans-serif;
  --m-weight-heading: 700;
  --m-size-heading: 2rem;
  --m-lh-heading: 1.08;
  --m-ls-heading: -0.025em;
  --m-font-body: 'BlinkMacSystemFont','SF Pro Text','SF Pro Display','Helvetica Neue','Arial',sans-serif;
  --m-weight-body: 400;
  --m-size-body: 1rem;
  --m-lh-body: 1.65;
  --m-ls-body: 0;
  --m-font-accent: 'IBM Plex Mono',ui-monospace,'SF Mono','Menlo','Consolas',monospace;
  --m-weight-accent: 600;
  --m-size-accent: 0.75rem;
  --m-lh-accent: 1.3;
  --m-ls-accent: 0.14em;
  --m-space-xs: 8px;
  --m-space-sm: 32px;
  --m-space-md: 72px;
  --m-space-lg: 112px;
  --m-space-xl: 144px;
  --m-radius-sm: 6px;
  --m-radius-md: 8px;
  --m-radius-lg: 16px;
  --m-radius-full: 999px;
  --m-shadow-sm: 0px 1px 3px 0px rgba(26,39,68,0.08);
  --m-shadow-md: 0px 4px 14px -2px rgba(26,39,68,0.10);
  --m-shadow-lg: 0px 12px 28px -6px rgba(26,39,68,0.16);
  --m-max-width: 1180px;
  --m-radius: 8px;
  --m-font-heading: 'BlinkMacSystemFont','SF Pro Display','SF Pro Text','Helvetica Neue','Arial',sans-serif;
  --m-font-body: 'BlinkMacSystemFont','SF Pro Text','SF Pro Display','Helvetica Neue','Arial',sans-serif;
  --m-bp-tablet: 1024px;
  --m-bp-mobile: 767px;
}
/* ==========================================================================
   Mason Business -- shared theme stylesheet
   ==========================================================================

   Loaded by Renderer::css() as:

       CssBuilder::rootVars(tokens) + <this file> + CssBuilder::libraryCss()

   That order matters. `libraryCss()` ships STRUCTURE for the v0.6 widgets
   (grid, flow, sizing) and comes AFTER this file, so where this stylesheet
   needs to override a structural default it does so with a deliberately
   higher-specificity selector -- always noted in a comment. Everything else
   here is the layer core does not own: colour, type, spacing, elevation,
   states and print.

   Conventions
   -----------
   - Mobile first. Every @media is min-width except the two that mirror the
     theme breakpoints (--m-bp-tablet 1024px, --m-bp-mobile 767px), which the
     style system also uses, so authored per-breakpoint overrides and the
     theme's own rules break at the same places.
   - Colour only ever comes from a token custom property, so retheming from
     the admin Design panel repaints everything here.
   - Secondary text uses color-mix() against currentColor rather than the
     muted token. That is what lets one stylesheet serve both a white section
     and a navy one: on white it resolves to a grey, on navy to a light blue
     tint, and it can never produce muted-grey-on-navy. A plain fallback
     declaration precedes each one for engines without color-mix.

   Accessibility floors held here
   ------------------------------
   - Every colour pair ships at WCAG 2.2 AA or better (see docs/theme.md for
     the measured table).
   - Interactive targets are at least 24x24 CSS px (2.5.8 Target Size Minimum),
     and the primary navigation and pagination controls are 44x44.
   - Focus is always visible and never relies on colour alone.
   - prefers-reduced-motion removes motion without ever hiding content.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Self-hosted faces
   Latin subsets, woff2 only, font-display:swap so text paints immediately in
   the fallback and never blocks LCP. Served from /assets/fonts/ -- the
   Publisher copies themes/<theme>/fonts/.

   2026-08-21 (typeface-match pass): headings and body copy no longer load a
   webfont at all. Inspected lineaprompt.com directly (computed styles +
   @font-face rules via headless Chrome) -- its h1-h4 and body copy resolve to
   -apple-system/BlinkMacSystemFont/"SF Pro Display"/"SF Pro Text"/"Helvetica
   Neue"/Arial/sans-serif with NO custom @font-face for that role. It is a
   genuine system-font stack, not a distinctive licensed typeface, so matching
   it "exactly" means dropping Poppins/Open Sans in favour of the same system
   stack (see --m-font-heading/--m-font-body in tokens.json). This removes two
   webfonts (Poppins 600/700, Open Sans variable) from the page entirely.
   Note: tokens.json's family strings omit the literal "-apple-system" token
   -- Mason's own admin-input validator (StyleSchema::font()) requires every
   family name start with a letter, so a leading-hyphen keyword is silently
   dropped (found the hard way: it does not reject just that one token, it
   invalidates the whole family and falls back to the theme default). Kept
   BlinkMacSystemFont plus the literal "SF Pro Display"/"SF Pro Text" names,
   which macOS has exposed as real, by-name-selectable system fonts since
   Catalina, so the rendered result on a real Mac is the same typeface either
   way; only very old Safari (pre-10, which read -apple-system specifically)
   would miss it and fall through to Helvetica Neue/Arial instead.
   Swapped JetBrains Mono -> IBM Plex Mono below for the same reason: it is
   the actual mono face lineaprompt.com self-hosts (confirmed via its
   @font-face rules, weights 400/500/600 real, other requested weights fall
   back to the nearest of those) for its monospace-semantic UI (timestamps,
   variables, keyboard shortcuts, a couple of badges) -- this theme's own
   kicker/eyebrow use of the mono face is a deliberate BuildAbility choice
   (see section 17 below), not a Linea pattern, so only the typeface changed,
   not where it is applied. */
/* IBM Plex Mono -- 400/500 only (the two weights this theme actually
   requests via --m-font-mono below: 400 base, 500 for kickers/eyebrows/step
   numbers/stat values/tags). NEVER for body copy or headings -- those stay
   the system-font stack as shipped. */
@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/assets/fonts/ibm-plex-mono-400.woff2) format('woff2');
  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: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/assets/fonts/ibm-plex-mono-500.woff2) format('woff2');
  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;
}

/* --------------------------------------------------------------------------
   2. Theme-local variables
   Derived values that are not tokens in their own right. Kept here rather
   than in tokens.json so the admin Design panel stays a short, meaningful
   list instead of thirty knobs nobody wants to turn.
   -------------------------------------------------------------------------- */
:root {
  --m-gutter: 20px;
  --m-narrow: 760px;

  /* Type scale. clamp() so headings shrink on a phone without a media query.
     Bumped 2026-08-21 (design-audit round 3, item 2) for more visual punch --
     measured against lineaprompt.com's h1 (72px/700/lh0.96) which reads far
     bigger/tighter than this theme's old 52px ceiling. Kept weight 700 (now
     on the system-font stack, see section 1 above) and tightened
     line-height/letter-spacing in tokens.json rather than chasing Linea's
     exact px, since BuildAbility's headings wrap to 2-3 lines on a narrower
     max-width (1180px vs Linea's wide desktop layout). */
  --m-h1: clamp(2.25rem, 1.4rem + 3.7vw, 4rem);
  --m-h2: clamp(1.875rem, 1.3rem + 2.4vw, 2.75rem);
  --m-h3: clamp(1.3rem, 1.15rem + 0.75vw, 1.625rem);
  --m-h4: 1.1875rem;
  --m-lead: 1.125rem;
  --m-small: 0.938rem;

  /* Secondary text: 72% of whatever the local text colour is. */
  --m-dim: 72%;

  /* Hairline for every border this theme draws.
     This is deliberately the FULL border token rather than a softened mix.
     Card, table, form, toggle and social-button boundaries are user interface
     component boundaries under WCAG 1.4.11, which needs 3:1 against the
     adjacent colour; the border token measures 3.47:1 on the page background
     and 3.16:1 on the surface tint, and any mix below about 88% opacity drops
     under the threshold. Depth comes from the shadow scale instead, so the
     borders can stay compliant without the UI looking heavy. */
  --m-hairline: var(--m-color-border);

  /* Mono accent face -- kickers/eyebrows, step numbers, stat values, tags.
     Never body copy. Swapped JetBrains Mono -> IBM Plex Mono 2026-08-21 to
     match lineaprompt.com's actual self-hosted mono face (see section 1). */
  --m-font-mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  --m-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --m-speed: 180ms;
}

/* --------------------------------------------------------------------------
   3. Reset and document
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--m-font-body);
  font-size: var(--m-size-body, 1rem);
  font-weight: var(--m-weight-body, 400);
  line-height: var(--m-lh-body, 1.65);
  letter-spacing: var(--m-ls-body, 0);
  color: var(--m-color-text);
  background: var(--m-color-bg);
  /* Belt and braces against a stray wide child forcing a sideways scroll.
     Every known wide element (tables, logo strips, code) also scrolls inside
     its own container, so this only ever catches authoring mistakes. */
  overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6 {
  font-family: var(--m-font-heading);
  font-weight: var(--m-weight-heading, 700);
  line-height: var(--m-lh-heading, 1.18);
  letter-spacing: var(--m-ls-heading, -0.02em);
  color: inherit;
  margin: 0 0 0.5em;
  /* Long compound words (suburb names, product codes) must not push the
     layout sideways on a 320px screen. */
  overflow-wrap: break-word;
}
h1 { font-size: var(--m-h1); }
h2 { font-size: var(--m-h2); }
h3 { font-size: var(--m-h3); }
h4 { font-size: var(--m-h4); }

p { margin: 0 0 1em; overflow-wrap: break-word; }
p:last-child { margin-bottom: 0; }

ul, ol { margin: 0 0 1em; padding-left: 1.25em; }
li { margin-bottom: 0.4em; }
li:last-child { margin-bottom: 0; }

img, svg, video { max-width: 100%; }
img, video { height: auto; display: block; }

a { color: var(--m-color-primary); text-underline-offset: 0.15em; }
a:hover { color: color-mix(in srgb, var(--m-color-primary) 78%, #000); }

strong, b { font-weight: 600; }

hr { border: 0; border-top: 1px solid var(--m-hairline); margin: 0; }

::selection { background: color-mix(in srgb, var(--m-color-primary) 22%, transparent); }

/* --------------------------------------------------------------------------
   4. Focus, skip link, screen-reader helpers
   -------------------------------------------------------------------------- */

/* One visible ring for everything interactive. The UA default is easy to lose
   against a light surface, so this is explicit and token-coloured. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: 3px solid var(--m-color-primary);
  outline-offset: 2px;
  border-radius: 3px;
}

.m-skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  background: var(--m-color-bg);
  color: var(--m-color-primary);
  font-family: var(--m-font-heading);
  font-weight: 600;
  padding: 12px 20px;
  border: 2px solid var(--m-color-primary);
  border-radius: 0 0 var(--m-radius) 0;
  text-decoration: none;
}
.m-skip:focus { left: 0; }

.m-visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------------------
   5. Layout: sections, columns
   -------------------------------------------------------------------------- */
.m-section {
  padding-top: var(--m-pad-y, 72px);
  padding-bottom: var(--m-pad-y, 72px);
  position: relative;
}
.m-section-inner {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 24px;
}
.m-contained .m-section-inner {
  max-width: var(--m-max-width);
  margin: 0 auto;
  padding-left: var(--m-gutter);
  padding-right: var(--m-gutter);
}
/* A full-bleed section still needs gutters or text runs into the viewport
   edge on a phone (1.4.10 Reflow). Only the max-width is dropped. */
.m-full .m-section-inner {
  padding-left: var(--m-gutter);
  padding-right: var(--m-gutter);
}

/* Below the tablet breakpoint everything is a single column: a 4-up card row
   at 900px is unreadable, and two of anything is the most a phone can hold. */
.m-col { grid-column: span 12; min-width: 0; }
@media (min-width: 768px) {
  .m-col-1 { grid-column: span 6; }
  .m-col-2 { grid-column: span 6; }
  .m-col-3 { grid-column: span 6; }
  .m-col-4 { grid-column: span 6; }
  .m-col-5 { grid-column: span 12; }
  .m-col-6 { grid-column: span 12; }
  .m-col-7 { grid-column: span 12; }
  .m-col-8 { grid-column: span 12; }
  .m-col-9 { grid-column: span 12; }
  .m-col-10 { grid-column: span 12; }
  .m-col-11 { grid-column: span 12; }
  .m-col-12 { grid-column: span 12; }
}
@media (min-width: 1025px) {
  .m-col-1 { grid-column: span 1; }
  .m-col-2 { grid-column: span 2; }
  .m-col-3 { grid-column: span 3; }
  .m-col-4 { grid-column: span 4; }
  .m-col-5 { grid-column: span 5; }
  .m-col-6 { grid-column: span 6; }
  .m-col-7 { grid-column: span 7; }
  .m-col-8 { grid-column: span 8; }
  .m-col-9 { grid-column: span 9; }
  .m-col-10 { grid-column: span 10; }
  .m-col-11 { grid-column: span 11; }
  .m-col-12 { grid-column: span 12; }
}

/* Section background media and overlay (section props bg_image / overlay_*). */
.m-section-overlay {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.m-section-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  pointer-events: none;
}
.m-section > .m-section-inner { position: relative; z-index: 1; }
.m-section-minh > .m-section-inner { min-height: inherit; }

/* --------------------------------------------------------------------------
   6. Alignment utilities
   -------------------------------------------------------------------------- */
.m-align-left { text-align: left; }
.m-align-center { text-align: center; }
.m-align-right { text-align: right; }

/* --------------------------------------------------------------------------
   7. Buttons
   Padding gives every variant a >=44px target, comfortably over the 24x24
   floor. The label is wrapped in a <span> by the renderer, which is what
   makes the icon slot orderable without touching the text.
   -------------------------------------------------------------------------- */
.m-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5em;
  min-height: 44px;
  padding: 12px 28px;
  border: 2px solid transparent;
  border-radius: var(--m-radius);
  font-family: var(--m-font-heading);
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--m-speed) var(--m-ease),
              border-color var(--m-speed) var(--m-ease),
              color var(--m-speed) var(--m-ease),
              transform var(--m-speed) var(--m-ease);
}
.m-btn:hover { transform: translateY(-1px); }
.m-btn:active { transform: translateY(0); }

.m-btn-primary {
  background: var(--m-color-primary);
  border-color: var(--m-color-primary);
  color: #fff;
}
.m-btn-primary:hover {
  background: color-mix(in srgb, var(--m-color-primary) 84%, #000);
  border-color: color-mix(in srgb, var(--m-color-primary) 84%, #000);
  color: #fff;
}

.m-btn-secondary {
  background: var(--m-color-secondary);
  border-color: var(--m-color-secondary);
  color: #fff;
}
.m-btn-secondary:hover {
  background: color-mix(in srgb, var(--m-color-secondary) 82%, #fff);
  border-color: color-mix(in srgb, var(--m-color-secondary) 82%, #fff);
  color: #fff;
}

/* The outline variant is built for LIGHT backgrounds. On a dark section use
   a filled variant instead -- see docs/theme.md. */
.m-btn-outline {
  background: transparent;
  border-color: var(--m-color-primary);
  color: var(--m-color-primary);
}
.m-btn-outline:hover {
  background: var(--m-color-primary);
  border-color: var(--m-color-primary);
  color: #fff;
}

/* --------------------------------------------------------------------------
   8. Text, images, media
   -------------------------------------------------------------------------- */
.m-text > :last-child { margin-bottom: 0; }
.m-text ul, .m-text ol { padding-left: 1.25em; }

.m-image { margin: 0; }
.m-image img, .m-post-hero img { border-radius: 0; }
.m-rounded img { border-radius: var(--m-radius); }
.m-image picture, .m-post-hero picture { display: block; }
.m-align-center .m-image img, .m-image.m-align-center img { margin-left: auto; margin-right: auto; }
.m-align-right .m-image img, .m-image.m-align-right img { margin-left: auto; }

.m-video { position: relative; padding-bottom: 56.25%; height: 0; border-radius: var(--m-radius); overflow: hidden; }
.m-video iframe, .m-video video { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

.m-gallery { display: grid; gap: 16px; }
.m-gallery img { border-radius: var(--m-radius); width: 100%; object-fit: cover; }
.m-gallery-item {
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  border-radius: var(--m-radius);
  overflow: hidden;
  min-width: 24px;
  min-height: 24px;
}

.m-lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(14, 42, 92, 0.88);
}
.m-lightbox img { max-width: 100%; max-height: 90vh; border-radius: var(--m-radius); }
.m-lightbox-close {
  position: absolute;
  top: 16px;
  right: 16px;
  min-width: 44px;
  min-height: 44px;
  font-size: 1.5rem;
  line-height: 1;
  color: #fff;
  background: rgba(0, 0, 0, 0.4);
  border: 2px solid #fff;
  border-radius: var(--m-radius);
  cursor: pointer;
}
.m-lightbox-close:focus-visible { outline-color: #fff; }

.m-divider { border: 0; border-top: 1px solid var(--m-hairline); margin: 0 auto; }
.m-divider-dashed { border-top-style: dashed; }

/* --------------------------------------------------------------------------
   9. Toggle / FAQ
   -------------------------------------------------------------------------- */
.m-toggle {
  border: 1px solid var(--m-hairline);
  border-radius: var(--m-radius);
  background: var(--m-color-bg);
  padding: 4px 20px;
  margin-bottom: 12px;
  transition: border-color var(--m-speed) var(--m-ease), box-shadow var(--m-speed) var(--m-ease);
}
.m-toggle:hover { border-color: var(--m-color-primary); }
.m-toggle[open] { border-color: var(--m-color-primary); box-shadow: var(--m-shadow-sm); }
.m-toggle summary {
  font-family: var(--m-font-heading);
  font-size: 1.0625rem;
  font-weight: 600;
  cursor: pointer;
  padding: 16px 0;
  min-height: 24px;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}
.m-toggle summary::-webkit-details-marker { display: none; }
/* The marker is a CSS-drawn chevron: decoration, never announced. */
.m-toggle summary::after {
  content: "";
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  border-right: 2px solid var(--m-color-primary);
  border-bottom: 2px solid var(--m-color-primary);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform var(--m-speed) var(--m-ease);
}
.m-toggle[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.m-toggle > div { padding-bottom: 16px; }
.m-toggle > div > :last-child { margin-bottom: 0; }
.m-toggle-divider { border-top: 1px solid var(--m-hairline); }

/* --------------------------------------------------------------------------
   10. Table
   The wrapper scrolls so a wide table never forces the page sideways, and it
   is focusable with a visible ring so a keyboard user can reach the scroll.
   -------------------------------------------------------------------------- */
.m-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
  border-radius: var(--m-radius);
}
.m-table { border-collapse: collapse; width: 100%; font-size: var(--m-small); }
.m-table caption {
  text-align: left;
  font-weight: 600;
  padding-bottom: 10px;
  color: currentColor;
  opacity: 0.75;
}
.m-table th, .m-table td {
  border: 1px solid var(--m-hairline);
  padding: 12px 14px;
  text-align: left;
  vertical-align: top;
}
.m-table thead th {
  font-family: var(--m-font-heading);
  font-weight: 600;
  color: var(--m-color-text);
  background: var(--m-color-surface);
  white-space: nowrap;
}
.m-table-striped tbody tr:nth-child(even) { background: var(--m-color-surface); }
.m-table-border th, .m-table-border td { border-color: var(--m-color-border); }

/* --------------------------------------------------------------------------
   11. Form
   -------------------------------------------------------------------------- */
.m-form {
  display: grid;
  gap: 18px;
  max-width: 640px;
  padding: 28px;
  background: var(--m-color-bg);
  border: 1px solid var(--m-hairline);
  border-radius: var(--m-radius);
  box-shadow: var(--m-shadow-sm);
}
.m-form-field { display: grid; gap: 6px; font-weight: 600; font-size: var(--m-small); }
.m-form-field > span { color: var(--m-color-text); }
.m-required { color: var(--m-color-accent); }
.m-form-field input,
.m-form-field textarea,
.m-form-field select {
  width: 100%;
  font: inherit;
  font-weight: 400;
  min-height: 44px;
  color: var(--m-color-text);
  background: var(--m-color-bg);
  padding: 11px 14px;
  border: 1px solid var(--m-color-border);
  border-radius: var(--m-radius);
  transition: border-color var(--m-speed) var(--m-ease), box-shadow var(--m-speed) var(--m-ease);
}
.m-form-field textarea { resize: vertical; min-height: 120px; }
.m-form-field input:focus,
.m-form-field textarea:focus,
.m-form-field select:focus {
  border-color: var(--m-color-primary);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--m-color-primary) 22%, transparent);
}
.m-form-hint { margin: 0; font-size: 0.875rem; color: var(--m-color-muted); font-weight: 400; }
.m-form button[type="submit"] { justify-self: start; }
.m-form button[disabled] { opacity: 0.6; cursor: default; transform: none; }
.m-form-success, .m-form-error {
  margin: 0;
  padding: 14px 16px;
  border-radius: var(--m-radius);
  font-weight: 600;
  font-size: var(--m-small);
}
/* Measured: 7.11:1 and 7.15:1. Each also carries a border, so the state is
   not signalled by colour alone (1.4.1). */
.m-form-success { background: #e7f4ec; color: #145c34; border: 1px solid #145c34; }
.m-form-error { background: #fdeeec; color: #96271b; border: 1px solid #96271b; }

@media (min-width: 768px) {
  .m-form-2col { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
}
/* Single column below tablet regardless of the authored setting: two form
   fields side by side on a phone is unusable. Higher specificity than the
   structural rule in libraryCss, which is unconditional. */
@media (max-width: 767px) {
  .m-form.m-form-2col { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------------------
   12. v0.6 widgets -- the presentation layer over libraryCss structure
   -------------------------------------------------------------------------- */

/* --- icon --------------------------------------------------------------- */
.m-icon { color: inherit; }
.m-icon-svg { display: block; }

/* --- the per-node style wrapper ----------------------------------------- */
/* Emitted by the renderer around any widget that carries a style object. It
   must not introduce a layout of its own, but it does need min-width:0 so a
   long unbroken string inside a flex or grid column cannot push the row wider
   than the viewport. */
.m-w { min-width: 0; }

/* --- icon-box ----------------------------------------------------------- */
.m-icon-box { gap: 18px; }
/* flex:1 with min-width:0 is what stops a long word in the body text from
   widening the box past its column. */
.m-icon-box-body { flex: 1 1 auto; min-width: 0; }
/* Two selectors deep so this beats the structural `.m-icon-box .m-icon` rule
   that libraryCss loads afterwards. */
.m-icon-box > .m-icon {
  flex: 0 0 auto;
  width: 56px;
  height: 56px;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  color: var(--m-color-primary);
  background: color-mix(in srgb, var(--m-color-primary) 12%, transparent);
  border-radius: var(--m-radius);
}
.m-icon-box h2, .m-icon-box h3, .m-icon-box h4 { font-size: 1.1875rem; margin: 0 0 8px; }
.m-icon-box .m-text {
  color: currentColor;
  color: color-mix(in srgb, currentColor var(--m-dim), transparent);
  font-size: var(--m-small);
}

/* --- card --------------------------------------------------------------- */
.m-card {
  height: 100%;
  border: 1px solid var(--m-hairline);
  box-shadow: var(--m-shadow-sm);
  transition: box-shadow var(--m-speed) var(--m-ease), transform var(--m-speed) var(--m-ease);
}
.m-card:hover { box-shadow: var(--m-shadow-lg); transform: translateY(-3px); }
.m-card img { aspect-ratio: 3 / 2; }
.m-card-body { padding: 24px; flex: 1 1 auto; }
.m-card-body h2, .m-card-body h3, .m-card-body h4 { font-size: 1.1875rem; margin: 0; }
.m-card-body .m-text {
  color: var(--m-color-muted);
  font-size: var(--m-small);
  flex: 1 1 auto;
}
.m-card-body a {
  font-family: var(--m-font-heading);
  font-weight: 600;
  font-size: var(--m-small);
  text-decoration: none;
}
.m-card-body a:hover { text-decoration: underline; }
/* The whole card is clickable, but the accessible name still comes from the
   real link, so nothing is added to the tab order. */
.m-card-body a::after { content: ""; position: absolute; inset: 0; }
.m-card { position: relative; }

/* --- boxed icon column (fidelity marker) --------------------------------- */
/* live wraps SOME icon+heading+text groups in a white, shadowed panel (e.g.
   BuildAbility's "3 Challenges" and "Is This For You?" rows) but leaves
   others flat (BuildAbility's "What You Will Achieve" / MOST-pillar rows,
   the homepage "Sound Familiar?" list, the /grow equivalent, and Services'
   "Solving the Three Big Challenges" -- confirmed flat on live via
   getComputedStyle, despite reading as card-like at a glance). Icon, heading
   and text here are three separate widgets composed inside one column
   rather than a single bundled widget, so there is no structural type to
   hook a blanket rule to -- `ic-boxed-card` is applied per-column in the
   page's blocks JSON only where live is actually boxed. Values measured
   from live's boxed instances (getComputedStyle on the equivalent
   Elementor column wrap). */
.ic-boxed-card {
  background: var(--m-color-bg);
  border-radius: var(--m-radius-lg);
  box-shadow: 0 4px 20px rgba(26, 39, 68, 0.08);
  padding: 40px 28px;
}

/* --- testimonial -------------------------------------------------------- */
.m-testimonial {
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 28px;
  background: var(--m-color-bg);
  border: 1px solid var(--m-hairline);
  border-radius: var(--m-radius);
  box-shadow: var(--m-shadow-sm);
}
.m-testimonial blockquote {
  margin: 0;
  flex: 1 1 auto;
  font-size: 1.0625rem;
  line-height: 1.6;
}
/* Fidelity fix 2026-07-22: `open-quote`/`close-quote` resolve through the
   `quotes` property, and in this rendering stack that comes out as a
   straight double-prime rather than a curly mark. Live doesn't use a
   pseudo-element at all (its quote is a literal curly-quote character typed
   into the copy) -- here the equivalent fix is to hardcode the actual
   Unicode curly-quote glyphs so the pseudo-element can't be re-resolved to
   an ASCII quote by `quotes`/UA/font quirks. */
.m-testimonial blockquote::before { content: "\201C"; }
.m-testimonial blockquote::after { content: "\201D"; }
.m-testimonial figcaption {
  font-family: var(--m-font-heading);
  font-weight: 600;
  font-size: var(--m-small);
}
/* Two selectors deep to beat the structural default. */
.m-testimonial .m-testimonial-role {
  display: block;
  font-weight: 400;
  color: var(--m-color-muted);
  color: color-mix(in srgb, currentColor var(--m-dim), transparent);
}
.m-rating { color: var(--m-color-accent); }

/* --- stat --------------------------------------------------------------- */
.m-stat-value { font-size: clamp(2.25rem, 1.6rem + 2.4vw, 3rem); letter-spacing: -0.03em; }
/* Two selectors deep: the structural rule pins this to the muted token,
   which would be unreadable on the navy stats band. */
.m-stat .m-stat-label {
  margin-top: 6px;
  font-size: var(--m-small);
  color: var(--m-color-muted);
  color: color-mix(in srgb, currentColor var(--m-dim), transparent);
}

/* --- pricing-card ------------------------------------------------------- */
.m-pricing {
  height: 100%;
  padding: 32px 28px;
  background: var(--m-color-bg);
  border-color: var(--m-hairline);
  box-shadow: var(--m-shadow-sm);
}
.m-pricing-featured { box-shadow: var(--m-shadow-lg); }
.m-pricing-plan { font-size: 1.1875rem; margin: 0; }
.m-pricing-price { margin: 0; color: var(--m-color-secondary); }
.m-pricing .m-pricing-period {
  display: block;
  font-family: var(--m-font-body);
  font-size: var(--m-small);
  font-weight: 400;
  color: var(--m-color-muted);
}
.m-pricing-features { list-style: none; padding: 0; margin: 0; flex: 1 1 auto; }
.m-pricing-features li {
  position: relative;
  padding-left: 28px;
  margin-bottom: 10px;
  font-size: var(--m-small);
}
/* A drawn tick rather than a bullet glyph: decorative, so it is not read out. */
.m-pricing-features li::before {
  content: "";
  position: absolute;
  left: 4px;
  top: 0.45em;
  width: 11px;
  height: 6px;
  border-left: 2px solid var(--m-color-primary);
  border-bottom: 2px solid var(--m-color-primary);
  transform: rotate(-45deg);
}
.m-pricing .m-btn { width: 100%; margin-top: 8px; }

/* --- team-member -------------------------------------------------------- */
/* Card fidelity pass 2026-07-22: live boxes every team-member card (white
   panel, hairline border, soft shadow, generous inner padding) rather than
   sitting the photo/name/bio directly on the section background. Measured
   from live via getComputedStyle: bg #fff, 1px solid #e5e7eb, 12px radius,
   0 2px 12px rgba(0,0,0,.06), 28px 24px padding -- the padding wraps the
   whole card (photo included), which is safe here because .m-team is only
   ever the team-member widget, never reused for a flat layout. */
.m-team {
  height: 100%;
  background: var(--m-color-bg);
  border: 1px solid var(--m-hairline);
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(26, 39, 68, 0.08);
  padding: 28px 24px;
}
.m-team img { margin: 0 auto 16px; box-shadow: var(--m-shadow-sm); }
.m-team h2, .m-team h3, .m-team h4 { font-size: 1.0625rem; margin: 0; }
.m-team .m-team-role {
  font-size: var(--m-small);
  font-weight: 600;
  color: var(--m-color-primary);
  margin: 4px 0 8px;
}
.m-team .m-text {
  font-size: var(--m-small);
  color: var(--m-color-muted);
  color: color-mix(in srgb, currentColor var(--m-dim), transparent);
}
.m-team-links { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }
.m-team-links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  min-height: 32px;
  border-radius: var(--m-radius);
}

/* --- logo-strip --------------------------------------------------------- */
.m-logo-strip { gap: 32px; }
.m-logo-strip img { max-height: 40px; }
/* Greyscale at 70% opacity would be a 2.9:1 mark on white. Logos are
   decorative and always carry alt text, so this is presentational only --
   but the hover restores full contrast for anyone who looks closely.
   (Base filter added 2026-08-20 -- the transition/hover rules existed but
   the actual grayscale-by-default state was never declared, so the strip
   rendered in full colour even with grayscale:true set.) */
.m-logo-strip-mono img { filter: grayscale(1) opacity(0.7); transition: filter var(--m-speed) var(--m-ease), opacity var(--m-speed) var(--m-ease); }
.m-logo-strip-mono img:hover { filter: none; opacity: 1; }

/* --- cta-banner --------------------------------------------------------- */
/* The banner carries the theme's dark treatment. Doing it here rather than
   via a section background means the band, its text and its button are
   defined together and cannot drift into a contrast failure. */
.m-cta-banner {
  padding: 44px 40px;
  background: var(--m-color-secondary);
  color: #fff;
  box-shadow: var(--m-shadow-md);
}
.m-cta-banner h2, .m-cta-banner h3, .m-cta-banner h4 { color: #fff; }
.m-cta-banner .m-cta-banner-text p {
  margin: 10px 0 0;
  color: #dbe4f2;
  max-width: 62ch;
}
.m-cta-banner-stacked .m-cta-banner-text p { margin-inline: auto; }
/* White button on the navy band: 13.96:1 both ways. */
.m-cta-banner .m-btn-primary {
  background: #fff;
  border-color: #fff;
  color: var(--m-color-secondary);
  flex: 0 0 auto;
}
.m-cta-banner .m-btn-primary:hover {
  background: #e8eefb;
  border-color: #e8eefb;
  color: var(--m-color-secondary);
}
.m-cta-banner a:focus-visible, .m-cta-banner .m-btn:focus-visible { outline-color: #fff; }

/* --- social-links ------------------------------------------------------- */
.m-social a {
  color: var(--m-color-secondary);
  background: var(--m-color-surface);
  border: 1px solid var(--m-hairline);
  transition: background-color var(--m-speed) var(--m-ease), color var(--m-speed) var(--m-ease);
}
.m-social a:hover { background: var(--m-color-primary); border-color: var(--m-color-primary); color: #fff; }

/* --- contact-details ---------------------------------------------------- */
.m-contact { font-style: normal; }
.m-contact dl { margin: 0; }
.m-contact div { margin-bottom: 16px; align-items: center; }
.m-contact div:last-child { margin-bottom: 0; }
/* Two selectors deep: the structural rule pins the icon to the primary token,
   which is a 1.6:1 mark against the navy footer.
   Card fidelity pass 2026-07-22: live renders these as solid blue squares
   (#225985) with a white glyph, 44px square, 12px radius. Matched exactly via
   getComputedStyle on live's /contact page. Design-audit colour-hierarchy fix
   2026-08-20 swapped the primary/accent token VALUES (primary is now the
   navy #225985, accent is now the gold #cf8e25) -- this rule is repointed
   from --m-color-accent to --m-color-primary so the square stays the same
   navy it was fidelity-matched to. The dark-footer variant below overrides
   this back to a translucent white treatment, so this change is
   contact-page-only. */
.m-contact dt .m-icon {
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  color: #fff;
  background: var(--m-color-primary);
  border-radius: 12px;
}
.m-contact dd a { color: inherit; text-decoration: none; }
.m-contact dd a:hover { text-decoration: underline; }

/* --- map ---------------------------------------------------------------- */
.m-map { border: 1px solid var(--m-hairline); }
.m-map-load { color: var(--m-color-text); font-family: var(--m-font-heading); font-weight: 600; }
.m-map-hint {
  display: inline-block;
  padding: 12px 20px;
  min-height: 44px;
  background: var(--m-color-bg);
  border: 2px solid var(--m-color-primary);
  border-radius: var(--m-radius);
  color: var(--m-color-primary);
}
.m-map-load:hover .m-map-hint { background: var(--m-color-primary); color: #fff; }
.m-map-static { margin: 0; padding: 16px; text-align: center; }

/* --- posts-grid --------------------------------------------------------- */
.m-posts article {
  height: 100%;
  padding-bottom: 20px;
  border-bottom: 1px solid var(--m-hairline);
}
.m-posts h3 { font-size: 1.1875rem; }
.m-posts h3 a { color: inherit; text-decoration: none; }
.m-posts h3 a:hover { color: var(--m-color-primary); text-decoration: underline; }
.m-posts article > p:last-child {
  margin: 0;
  font-size: var(--m-small);
  color: var(--m-color-muted);
  color: color-mix(in srgb, currentColor var(--m-dim), transparent);
}
.m-posts-empty { color: var(--m-color-muted); font-style: italic; }

/* --------------------------------------------------------------------------
   13. Blog archive, post header, pagination, breadcrumbs
   -------------------------------------------------------------------------- */

/* Dark hero band above the card grid -- mirrors the page-header treatment
   used across the rest of the site instead of a bare <h1> on white.
   Fidelity pass 2026-07-22: live runs a much taller photographic hero
   (140px/120px top/bottom padding, diagonal navy-to-steel-blue scrim over a
   real photo) rather than a short solid-colour band. The exact source photo
   (grow-hero.jpg) already exists in this instance's media library from the
   WP import, so it is referenced here as a theme background image -- this is
   presentational only, not a content change. */
.m-blog-hero {
  position: relative;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 140px var(--m-gutter) 120px;
  background: var(--m-color-secondary) url('/media/2026/07/grow-hero-d007a7.jpg') center / cover no-repeat;
  overflow: hidden;
}
.m-blog-hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, color-mix(in srgb, var(--m-color-secondary) 75%, transparent) 0%, color-mix(in srgb, var(--m-color-accent) 65%, transparent) 100%);
}
.m-blog-hero-inner { position: relative; z-index: 1; max-width: 800px; }
.m-blog-hero-inner h1 { color: #fff; font-size: clamp(2.25rem, 1.5rem + 2.6vw, 3.5rem); margin: 0 0 20px; }
.m-blog-hero-inner p { color: #fff; opacity: 0.95; margin: 0; font-size: 1.25rem; line-height: 1.7; }

.m-blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 30px;
  margin: 8px 0 16px;
}
@media (max-width: 900px) {
  .m-blog-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .m-blog-grid { grid-template-columns: 1fr; }
}

/* Card fidelity pass 2026-07-22: live wraps the whole card in a shadowed,
   rounded surface (image edge-to-edge at the top, 24px padded text block
   below) and shows only the title + date -- no excerpt. This widget has no
   body wrapper div in the DOM (image link, then a bare h2 and two <p>s as
   article children), so the 24px "card body" inset is applied directly to
   the text elements instead of a wrapper, and the excerpt paragraph is
   hidden rather than removed (keeps the markup theme-agnostic). */
.m-blog-card {
  display: block;
  padding: 0;
  margin: 0;
  background: var(--m-color-bg);
  border-radius: var(--m-radius);
  box-shadow: var(--m-shadow-sm);
  overflow: hidden;
  transition: transform var(--m-speed) var(--m-ease), box-shadow var(--m-speed) var(--m-ease);
}
.m-blog-card:hover { transform: translateY(-4px); box-shadow: var(--m-shadow-lg); }
.m-blog-card > a { display: block; margin-bottom: 0; }
.m-blog-card img { width: 100%; aspect-ratio: 2 / 1; object-fit: cover; border-radius: 0; transition: transform 0.5s var(--m-ease); }
.m-blog-card:hover img { transform: scale(1.04); }
.m-blog-card h2 { font-size: 1.35rem; font-weight: 600; line-height: 1.3; margin: 16px 24px 8px; }
.m-blog-card h2 a { color: var(--m-color-secondary); text-decoration: none; }
.m-blog-card h2 a:hover { color: var(--m-color-accent); text-decoration: underline; }
.m-blog-card > p.m-post-date { margin: 0 24px 24px; }
/* The excerpt is the only OTHER <p> the archive renders per card. */
.m-blog-card > p:not(.m-post-date) { display: none; }

.m-post-date {
  color: var(--m-color-muted);
  font-size: 0.8125rem;
  margin: 0 0 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.m-post-header { padding-top: 48px; }
.m-post-header .m-contained {
  max-width: var(--m-max-width);
  margin: 0 auto;
  padding-left: var(--m-gutter);
  padding-right: var(--m-gutter);
}

/* --- post: back link + footer CTA --------------------------------------- */
/* Both sit in the same contained column as the post header/content. */
.m-post-back .m-contained,
.m-post-cta .m-contained {
  max-width: var(--m-max-width);
  margin: 0 auto;
  padding-left: var(--m-gutter);
  padding-right: var(--m-gutter);
}
.m-post-back { padding-top: 28px; }
.m-post-back a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--m-color-secondary);
  text-decoration: none;
}
.m-post-back a:hover { color: var(--m-color-primary); }
/* Breathing room between the article body and the CTA band, and below it
   before the footer. */
.m-post-cta { padding: 16px 0 64px; }
.m-post-header h1 { margin: 0 0 8px; }
.m-post-hero { margin: 0 0 28px; }
.m-post-hero img { width: 100%; max-height: 460px; object-fit: cover; border-radius: var(--m-radius); }

.m-post-author { font-weight: 600; color: var(--m-color-text); }
.m-post-terms { margin: 0 0 16px; display: flex; flex-wrap: wrap; gap: 8px; }
.m-term-link {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--m-color-border);
  color: var(--m-color-text);
  font-size: 0.8rem;
  font-weight: 600;
  text-decoration: none;
}
.m-term-link:hover { border-color: var(--m-color-primary); color: var(--m-color-primary); }

/* Magazine-style post header: title overlaid on a full-bleed hero image
   with a dark scrim, used whenever the post has a hero image. */
.m-post-header-media {
  position: relative;
  padding-top: 0;
  overflow: hidden;
}
.m-post-header-media .m-post-hero { margin: 0; }
.m-post-header-media .m-post-hero img {
  width: 100%;
  height: 380px;
  max-height: none;
  object-fit: cover;
  border-radius: 0;
  display: block;
}
.m-post-hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, color-mix(in srgb, var(--m-color-secondary) 55%, transparent) 0%, color-mix(in srgb, var(--m-color-secondary) 80%, transparent) 100%);
}
.m-post-hero-content {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.m-post-hero-content .m-contained { padding-left: var(--m-gutter); padding-right: var(--m-gutter); }
.m-post-header-media h1 { color: #fff; margin: 0 0 8px; }
.m-post-header-media .m-post-date {
  color: #fff;
  opacity: 0.85;
  text-transform: none;
  letter-spacing: normal;
  margin: 0;
}
.m-post-header-media .m-post-author { color: #fff; }
/* Live's byline shows only the date, no "By <author>" -- the theme still
   renders the separator dot and author name markup (useful once real bylines
   exist), so hide both rather than removing them from the renderer. */
.m-post-header-media .m-post-date span { display: none; }
.m-post-header-media .m-post-terms { justify-content: center; margin-top: 12px; }
.m-post-header-media .m-term-link { border-color: rgba(255, 255, 255, 0.5); color: #fff; }
.m-post-header-media .m-term-link:hover { border-color: #fff; color: #fff; }
@media (max-width: 640px) {
  .m-post-header-media .m-post-hero img { height: 260px; }
}

/* Pagination fidelity pass 2026-07-22: live uses filled pill buttons (light
   grey inactive, steel-blue active) rather than bordered boxes with a gold
   active state. Steel blue is #225985, live's --ic-blue. Design-audit
   colour-hierarchy fix 2026-08-20 swapped the primary/accent token VALUES
   (primary is now #225985 navy, accent is now #cf8e25 gold), so this rule is
   repointed to --m-color-primary to keep the same like-for-like steel-blue
   active state, not a new colour. The 44px minimum target size is a WCAG
   2.5.8 floor this theme holds everywhere else (see section 30/33 docs) and
   is kept even though live's own pill runs slightly under it. */
.m-blog-pagination { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 32px; }
.m-blog-pagination a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0 16px;
  border: 0;
  border-radius: 4px;
  background: var(--m-color-surface);
  color: var(--m-color-text);
  text-decoration: none;
  font-weight: 500;
}
.m-blog-pagination a:hover { background: var(--m-color-primary); color: #fff; }
.m-blog-pagination a.m-current {
  background: var(--m-color-primary);
  border-color: var(--m-color-primary);
  color: #fff;
}

/* Article body typography fidelity pass 2026-07-22. Live's post body runs an
   18px/1.8 measure (vs this theme's 16px/1.65 default body copy) with
   generous top margin ahead of each H3 and a visible breathing gap around
   the <hr> dividers the renderer already emits between sections -- Mason's
   own defaults (h3 margin-top:0, hr margin:0) are what made the article read
   as one dense, undifferentiated block next to live's clearly separated
   sections. Scoped with `.m-post-header ~ .m-section` (a sibling combinator:
   the post header and the body section are both direct children of
   <article>) rather than a bare `article` selector, because the homepage
   also uses bare <article> elements for unrelated cards -- this only ever
   matches the section(s) that follow a post header, i.e. single-post pages. */
.m-post-header ~ .m-section { font-size: 1.125rem; line-height: 1.8; }
.m-post-header ~ .m-section .m-text p { margin-bottom: 1.25em; }
.m-post-header ~ .m-section h2 { margin-top: 2.2em; margin-bottom: 0.5em; }
.m-post-header ~ .m-section h3 { margin-top: 2em; margin-bottom: 0.5em; font-size: 1.75rem; font-weight: 600; }
.m-post-header ~ .m-section hr.m-divider { margin: 40px 0; opacity: 0.7; }
.m-post-header ~ .m-section .m-text ul,
.m-post-header ~ .m-section .m-text ol { margin-bottom: 1.25em; }
.m-post-header ~ .m-section .m-text li { line-height: 1.7; margin-bottom: 6px; }
.m-post-header ~ .m-section .m-text blockquote {
  margin: 24px 0;
  padding: 16px 24px;
  border-left: 4px solid var(--m-color-accent);
  background: var(--m-color-surface);
  border-radius: 0 var(--m-radius) var(--m-radius) 0;
  font-style: italic;
}
.m-post-header ~ .m-section .m-image img { border-radius: var(--m-radius); margin: 24px 0; }

/* A real <ol> so the trail has an order in the accessibility tree; the
   separator is a ::before so it is decoration and is never read out. */
.m-breadcrumbs { font-size: 0.875rem; color: var(--m-color-muted); margin-bottom: 16px; }
.m-breadcrumbs ol { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px; }
.m-breadcrumbs li { display: flex; align-items: center; gap: 4px; margin: 0; }
.m-breadcrumbs li + li::before { content: "/"; color: var(--m-color-border); padding-right: 4px; }
.m-breadcrumbs a { color: var(--m-color-muted); text-decoration: none; }
.m-breadcrumbs a:hover, .m-breadcrumbs a:focus-visible { color: var(--m-color-primary); text-decoration: underline; }
.m-breadcrumbs [aria-current="page"] { color: var(--m-color-text); }

/* --------------------------------------------------------------------------
   14. Site header and navigation
   -------------------------------------------------------------------------- */
.m-header { background: var(--m-color-bg); border-bottom: 1px solid var(--m-hairline); }
.m-header-inner {
  max-width: var(--m-max-width);
  margin: 0 auto;
  padding: 16px var(--m-gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}
.m-header .m-logo {
  font-family: var(--m-font-heading);
  font-weight: 700;
  font-size: 1.25rem;
  color: var(--m-color-secondary);
  text-decoration: none;
}
.m-nav { display: flex; gap: 28px; flex-wrap: wrap; }
.m-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 24px;
  color: var(--m-color-text);
  text-decoration: none;
  font-family: var(--m-font-heading);
  font-weight: 600;
  font-size: var(--m-small);
}
.m-nav a:hover { color: var(--m-color-primary); }
.m-nav a[aria-current="page"] {
  color: var(--m-color-primary);
  box-shadow: inset 0 -2px 0 var(--m-color-primary);
}

/* Mobile nav disclosure. The button ships hidden with aria-expanded="false"
   and ~230 bytes of inline JS only unhides it, so a no-JS visitor gets the
   full nav list rather than a dead toggle. Styling keys off the ARIA
   attribute itself, so the accessible state and the visual state cannot
   drift apart. */
.m-nav-toggle {
  display: none;
  align-items: center;
  gap: 8px;
  min-width: 44px;
  min-height: 44px;
  padding: 8px 14px;
  font: inherit;
  font-family: var(--m-font-heading);
  font-weight: 600;
  color: var(--m-color-text);
  background: var(--m-color-bg);
  border: 1px solid var(--m-color-border);
  border-radius: var(--m-radius);
  cursor: pointer;
}
.m-nav-toggle[hidden] { display: none; }
.m-nav-bars {
  display: block;
  width: 18px;
  height: 2px;
  background: currentColor;
  box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor;
}
@media (max-width: 767px) {
  .m-nav-toggle:not([hidden]) { display: inline-flex; }
  .m-header-inner { flex-wrap: wrap; }
  /* Every one of these is scoped to :not([hidden]), so without JS none apply
     and the nav stays a plain visible list. */
  .m-nav-toggle:not([hidden])[aria-expanded] ~ .m-nav {
    flex-basis: 100%;
    flex-direction: column;
    gap: 0;
  }
  .m-nav-toggle:not([hidden])[aria-expanded="false"] ~ .m-nav { display: none; }
  .m-nav-toggle:not([hidden])[aria-expanded="true"] ~ .m-nav { display: flex; }
  .m-nav-toggle:not([hidden])[aria-expanded] ~ .m-nav a {
    display: block;
    padding: 14px 0;
    min-height: 44px;
    border-top: 1px solid var(--m-hairline);
  }
}

/* --------------------------------------------------------------------------
   15. Site footer
   -------------------------------------------------------------------------- */
.m-footer { background: var(--m-color-secondary); color: #fff; margin-top: 0; }
.m-footer-inner {
  max-width: var(--m-max-width);
  margin: 0 auto;
  padding: 56px var(--m-gutter);
  font-size: var(--m-small);
}
/* #c7d2e4 on #0e2a5c measures 9.15:1. */
.m-footer p { color: #c7d2e4; }
.m-footer h2, .m-footer h3, .m-footer h4 { color: #fff; font-size: 1rem; margin: 0 0 14px; }
.m-footer a { color: #fff; }
.m-footer a:hover { color: #c7d2e4; }
/* The primary blue ring is invisible on the dark footer; use white there. */
.m-footer a:focus-visible, .m-footer button:focus-visible { outline-color: #fff; }
.m-footer .m-social a {
  color: #fff;
  background: rgba(255, 255, 255, 0.10);
  border-color: rgba(255, 255, 255, 0.28);
}
.m-footer .m-social a:hover { background: #fff; color: var(--m-color-secondary); border-color: #fff; }
.m-footer .m-contact dt .m-icon {
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
}
.m-footer .m-contact dd { color: #c7d2e4; }

/* --------------------------------------------------------------------------
   16. Embed placeholder (preview only)
   -------------------------------------------------------------------------- */
.m-embed-preview {
  padding: 16px;
  border: 1px dashed var(--m-color-border);
  border-radius: var(--m-radius);
  background: var(--m-color-surface);
}
.m-embed-preview-label {
  margin: 0 0 8px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--m-color-muted);
}
.m-embed-preview-code {
  margin: 0;
  overflow-x: auto;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-word;
}

/* --------------------------------------------------------------------------
   17. Reduced motion
   Motion is removed; nothing is hidden. The animation gate in libraryCss
   already guarantees .m-anim content stays visible, and this covers the
   transitions this stylesheet adds on top.
   -------------------------------------------------------------------------- */
@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;
  }
  .m-btn:hover, .m-card:hover, .bb-frame:hover { transform: none; }
  .m-image-zoom:hover img { transform: none; }
}

/* --------------------------------------------------------------------------
   18. Print
   Ink-cheap and readable: chrome removed, backgrounds dropped, link targets
   spelled out, and nothing allowed to break across a page mid-thought.
   -------------------------------------------------------------------------- */
@media print {
  .m-skip,
  .m-nav,
  .m-nav-toggle,
  .m-footer .m-social,
  .m-map-load,
  .m-lightbox,
  .m-blog-pagination,
  .m-form button,
  .m-section-video,
  .m-section-overlay,
  .m-shape { display: none !important; }

  body { background: #fff; color: #000; font-size: 11pt; }
  .m-section { padding-top: 12pt; padding-bottom: 12pt; }
  .m-section-inner { display: block; }
  .m-col { margin-bottom: 12pt; }

  .m-header, .m-footer, .m-cta-banner, .m-testimonial, .m-card, .m-pricing, .m-form, .m-toggle {
    background: #fff !important;
    color: #000 !important;
    box-shadow: none !important;
    border: 1px solid #999;
  }
  .m-cta-banner h2, .m-cta-banner h3, .m-cta-banner .m-cta-banner-text p,
  .m-footer p, .m-footer a, .m-footer h2, .m-footer h3, .m-footer h4 { color: #000 !important; }

  a { color: #000; text-decoration: underline; }
  /* Spell out real destinations only: a fragment or a javascript-free anchor
     adds nothing to a printed page. */
  .m-text a[href^="http"]::after,
  .m-posts a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 9pt; }

  /* Every toggle prints open, or an FAQ page prints as a list of questions. */
  .m-toggle > div { display: block !important; }

  h1, h2, h3, h4 { page-break-after: avoid; break-after: avoid; }
  img, figure, .m-card, .m-testimonial, .m-pricing { page-break-inside: avoid; break-inside: avoid; }
  .m-table-wrap { overflow: visible; }
  thead { display: table-header-group; }
}

/* ==========================================================================
   Increase Construction overrides (appended; keep parent rules above intact)
   ========================================================================== */

/* Headings on light backgrounds read near-navy on the live IC site. Dark
   sections opt out with cssClass "ic-dark", which restores inheritance so a
   widget wrapper's colour (white, gold) flows into the heading again. */
h1, h2, h3, h4 { color: #232c3d; }
.ic-dark :is(h1, h2, h3, h4) { color: inherit; }

/* Outline buttons on dark sections: white ghost button like the live hero. */
.ic-dark .m-btn-outline { border-color: #fff; color: #fff; }
.ic-dark .m-btn-outline:hover { background: #fff; border-color: #fff; color: #1a2744; }

/* Primary CTA button inside a dark (.ic-dark) section: .m-btn-primary's
   default background is var(--m-color-primary), the SAME navy several dark
   sections (e.g. the closing CTA band, node .m-n-dbb90ebe) use for their own
   background -- button disappears into the section. Confirmed live
   2026-08-20 ("Book a Walkthrough" in the closing band was unreadable).
   Swap to the gold accent so it actually stands out against navy. */
.ic-dark .m-btn-primary { background: var(--m-color-accent); border-color: var(--m-color-accent); color: #1a2744; }
.ic-dark .m-btn-primary:hover { background: color-mix(in srgb, var(--m-color-accent) 84%, #000); border-color: color-mix(in srgb, var(--m-color-accent) 84%, #000); color: #1a2744; }

/* Footer / dark-band nav links. */
.ic-dark .m-nav-menu a { color: #c9d2de; }
.ic-dark .m-nav-menu a:hover { color: var(--m-color-primary); }

/* Featured pricing card = steel blue panel with white copy and a gold badge,
   matching the "Retainer Partnership" card on increaseconstruction.com.
   Design-audit colour-hierarchy fix 2026-08-20 swapped the primary/accent
   token VALUES (primary is now #225985 navy, accent is now #cf8e25 gold),
   so this rule is repointed to --m-color-primary to keep the same steel
   blue panel. */
.m-pricing-featured {
  position: relative;
  background: var(--m-color-primary);
  border-color: var(--m-color-primary);
  color: #fff;
  overflow: visible;
}
.m-pricing-featured::before {
  content: "MOST POPULAR";
  position: absolute;
  top: -14px;
  left: 50%;
  transform: translateX(-50%);
  background: var(--m-color-primary);
  color: #fff;
  font-family: var(--m-font-heading);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  padding: 5px 16px;
  border-radius: 999px;
  white-space: nowrap;
}
.m-pricing-featured .m-pricing-plan,
.m-pricing-featured .m-pricing-price { color: #fff; }
.m-pricing-featured .m-pricing-period { color: rgba(255, 255, 255, 0.78); }
.m-pricing-featured .m-pricing-features li { border-bottom: 1px solid rgba(255,255,255,0.16); padding-bottom: 10px; }
.m-pricing-featured .m-pricing-features li::before { border-color: #fff; }
.m-pricing-featured .m-btn-primary { background: var(--m-color-primary); border-color: var(--m-color-primary); }

/* Gold primary buttons keep white text on hover (parent hover mixes toward
   white, which washes gold out). */
.m-btn-primary:hover {
  background: color-mix(in srgb, var(--m-color-primary) 88%, #000);
  border-color: color-mix(in srgb, var(--m-color-primary) 88%, #000);
  color: #fff;
}

/* Header nav: darker steel-grey links, no underline, like the live site. */
.m-nav-menu a { color: #45505d; font-size: 1.125rem; font-weight: 400; text-decoration: none; }
.m-nav-menu a:hover { color: var(--m-color-primary); }
.m-nav { gap: 32px; }
/* Doubled class for specificity: the core's structural .m-nav-menu nav ul
   rule is appended AFTER this file in the published stylesheet. */
.m-nav-menu.m-nav-horizontal nav ul { gap: 32px; }

/* In-page anchor jumps (See How It Works, Take The First Step) scroll rather
   than teleport. The reduced-motion block at the top of this file already
   resets this to auto. This is the fallback path only -- when the Lenis
   smooth-scroll layer (Renderer::smoothScrollJs()) is active it marks <html>
   with a "lenis"/"lenis-smooth" class and takes over anchor scrolling itself
   (anchors:true), so the rule right below hands control back to native/auto
   on that class to stop the two mechanisms double-easing the same jump. */
html { scroll-behavior: smooth; }
html.lenis { scroll-behavior: auto; }
[id] { scroll-margin-top: 96px; }

/* Form widget used as a dark card (home "Take The First Step"): the node style
   paints the wrapper as the card, so the form itself goes chromeless. */
.ic-form-card .m-form, .m-form.ic-form-card { border: none; box-shadow: none; max-width: 100%; background: transparent; padding: 4px; }

/* Header nav sits right-aligned beside the Contact Us button, like the live
   site: the nav column is wider than the link list, so without this the links
   hug the logo and leave a dead gap before the button.
   Selector fixed 2026-07-21: the core nav-menu widget's flex container is
   `.m-nav-menu nav ul` (see CssBuilder.php), never a bare `.m-nav` -- that
   class belongs to the older settings-driven header only, so the original
   `.ic-nav-right .m-nav` rule here never matched anything. */
.ic-nav-right .m-nav-menu nav ul { justify-content: flex-end; }

/* Header row: the logo, nav and CTA-button columns are unequal heights (the
   logo image is the tallest), so the grid's default item alignment (stretch,
   which then top-aligns each column's block content) left the nav links and
   the Contact Us button sitting near the top of the row instead of centred
   on it, like the live site's `.ic-nav-inner { display:flex; align-items:
   center }`. Centring the grid items reproduces that regardless of which
   column is tallest. Desktop only -- the mobile compact bar below already
   sets its own flex + align-items:center. */
@media (min-width: 768px) {
  header.m-header-template .m-section-inner { align-items: center; }
}

/* Hero background positioning: the renderer inlines background-position:center,
   so the nudge below needs !important to win. */
.ic-hero { background-size: auto 135% !important; background-position: center 42% !important; }

/* Mobile header: single compact row (logo + hamburger), like the live site.
   Added 2026-07-21. Without this the header's 3 columns (logo / nav / Contact
   Us button) fall back to the generic 12-col grid every other section on the
   page uses, which stacks them full-width on top of each other below 768px --
   logo, then a "Menu" row, then a floating Contact Us button, instead of one
   bar. The Contact Us column is hidden on mobile (matches the live site,
   which surfaces no CTA in the compact bar) and the toggle's "Menu" text
   label is hidden so only the bars icon shows. */
@media (max-width: 767px) {
  header.m-header-template .m-section-inner {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
  }
  header.m-header-template .m-col { grid-column: unset; width: auto; }
  header.m-header-template .m-col:last-child { display: none; }
  header.m-header-template .m-nav-toggle span:not(.m-nav-bars) { display: none; }
  /* Opening the drawer needs the row to wrap so the full-width link list
     drops onto its own line below the logo/toggle, instead of trying to
     squeeze into the flex row next to them. */
  header.m-header-template:has(.m-nav-open) .m-section-inner { flex-wrap: wrap; }
  header.m-header-template:has(.m-nav-open) .m-col:nth-child(2) { flex-basis: 100%; order: 3; }
}

/* --------------------------------------------------------------------------
   Fixed floating pill header -- added 2026-08-21 (design-audit round 3,
   item 3). Reference measured live on lineaprompt.com via Playwright
   getComputedStyle at scroll=0 and scroll=1500:
     position: fixed; top: 16px; left: 50% + translateX(-50%);
     outer slot width: calc(100vw - 32px); z-index: 40;
     visible pill: border-radius 12px, background rgba(255,255,255,.82),
     backdrop-filter: blur(40px), border 1px solid rgba(255,255,255,.88),
     box-shadow 0 24px 60px -42px rgba(37,50,72,.72) + inset 0 1px 0
     rgba(255,255,255,.9). Identical at both scroll positions -- it never
     shrinks/gains a shadow/changes opacity on scroll, so no scroll-listener
     JS is added here, just a stylesheet that is always in that state.
   Ported onto BuildAbility's own tokens rather than Linea's violet/off-white:
   background uses --m-color-bg (white) via color-mix for the alpha, border
   uses --m-radius-lg (16px, the closest EXISTING radius token to Linea's
   12px -- no bespoke radius value invented), and the shadow tints toward
   --m-color-secondary (navy) instead of Linea's neutral grey so it reads as
   this site's own elevation, not a copy.
   This replaces the old `.m-header { position: sticky; top: 0 }` bar (set in
   templates/header.json, still present there as the pre-JS/no-animation
   fallback) with a selector of higher specificity than the section's
   generated single-class rule, matching this file's own documented
   override convention (see file header, and the desktop header row-centring
   rule earlier in this section). */
header.m-header-template {
  position: fixed;
  top: 16px;
  left: 50%;
  transform: translateX(-50%);
  width: calc(100% - 32px);
  max-width: var(--m-max-width);
  z-index: 200;
  background: transparent;
  border-bottom: none;
}
header.m-header-template .m-section {
  border-radius: var(--m-radius-lg, 16px);
  background: color-mix(in srgb, var(--m-color-bg) 82%, transparent);
  -webkit-backdrop-filter: blur(40px);
  backdrop-filter: blur(40px);
  border: 1px solid color-mix(in srgb, #fff 85%, transparent);
  box-shadow:
    0 24px 60px -42px color-mix(in srgb, var(--m-color-secondary) 55%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, 0.85);
}
/* Content offset so the page doesn't render underneath the now-fixed bar.
   Generous fixed values (not an exact measured header height) since the
   header's rendered height differs slightly by breakpoint and the moment the
   mobile drawer is open. */
body { padding-top: 92px; }
@media (max-width: 767px) {
  header.m-header-template { top: 10px; width: calc(100% - 20px); }
  body { padding-top: 78px; }
}
/* Reduced motion: keep the fixed position (it's not an animation), nothing
   to opt out of here -- listed for completeness alongside this file's other
   reduced-motion handling. */

/* Checklist rows inside the How We Work Together plan cards: no bullets,
   steel tick, hairline divider per row -- white on the featured card. */
.ic-checklist ul { list-style: none; margin: 0; padding: 0; }
.ic-checklist li {
  position: relative;
  padding: 11px 0 11px 28px;
  border-bottom: 1px solid #e7ebf1;
}
.ic-checklist li::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 18px;
  width: 10px;
  height: 5px;
  border-left: 2px solid var(--m-color-secondary);
  border-bottom: 2px solid var(--m-color-secondary);
  transform: rotate(-45deg);
}
.ic-plan-featured .ic-checklist li { border-bottom-color: rgba(255, 255, 255, 0.16); }
.ic-plan-featured .ic-checklist li::before { border-color: #fff; }

/* MOST POPULAR pill straddling the featured card's top edge. The column that
   carries it must keep position:relative in its node style. */
.ic-plan-badge {
  position: absolute;
  top: -15px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1;
}
.ic-plan-badge p {
  margin: 0;
  background: var(--m-color-primary);
  color: #fff;
  font-family: var(--m-font-heading);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  padding: 7px 20px;
  border-radius: 999px;
  white-space: nowrap;
}

/* ROI band headline: a text widget so the "3 x Full Time Employees" phrase can
   carry the gold <strong>, which the heading widget's plain string cannot. */
.ic-roi-heading p {
  margin: 0;
  font-family: var(--m-font-heading);
  font-weight: 700;
  font-size: 2.3rem;
  line-height: 1.28;
  color: #fff;
}
.ic-roi-heading strong { color: var(--m-color-primary); font-weight: 700; }
@media (max-width: 782px) {
  .ic-roi-heading p { font-size: 1.7rem; }
}

/* --------------------------------------------------------------------------
   19. Fidelity pass 2026-07-22 -- section rhythm, footer, outline-icon fill
   -------------------------------------------------------------------------- */

/* Section vertical rhythm. Every content section carries its own --m-pad-y,
   authored per block from this theme's own tokens.json spacing scale
   (xs/sm/md/lg/xl = 8/32/72/112/144px) -- there is no single theme default
   to edit.

   Fix 2026-08-20: this rule used to multiply --m-pad-y by 1.4286 ("Fidelity
   pass 2026-07-22" comment, still in git history). That ratio was reverse
   engineered to match increase-construction's own live WordPress site and
   was copied here verbatim when this theme was cloned from
   increase-construction's base (see theme.json's own description) -- there
   is no external "live" reference for buildability.online to fidelity-match
   against, so the multiplier just silently inflated every section's padding
   ~43% past what tokens.json documents (e.g. md=72px rendered as ~103px),
   which is exactly the kind of undocumented drift that made the spacing
   read as inconsistent. Removed; --m-pad-y now renders at its authored
   value.

   The two :not() exclusions are wrapped in :where() so they contribute ZERO
   specificity (a bare :not(...) counts the specificity of its argument,
   which for "header.m-header-template .m-section" is a full type+class+class
   chain -- that pushed this rule to (0,5,2), far above a node's own
   `.m-n-xxxxxxxx{padding-top:...}` override at (0,1,0)). Renderer.php
   deliberately emits per-page node CSS in a <style> block AFTER this
   stylesheet specifically so a node-level override "beats the theme at equal
   specificity" (see the comment at Renderer.php's page head assembly) -- that
   invariant only holds if this rule stays at equal specificity too. Without
   :where() here, no section-level padding override (blocks JSON
   style.base.padding) could ever take effect: this rule always won regardless
   of source order. Keep :where() even though the multiplier is gone -- it is
   what makes per-section padding overrides possible at all. */
.m-section:where(:not(header.m-header-template .m-section)):where(:not(footer.m-footer-template .m-section)) {
  padding-top: var(--m-pad-y, 72px);
  padding-bottom: var(--m-pad-y, 72px);
}

/* Footer. The section's own background token (user1, #161e2a -- see
   footer.json) isn't reaching the rendered element, so the transparent
   section lets the stale `.m-footer { background: var(--m-color-secondary) }`
   rule above show through instead: the same steel blue as every CTA band on
   the page, which is why the footer never read as a distinct dark bar the
   way it does live. Pinning the background here (double class beats the
   single-class rule above regardless of source order) restores the darker,
   near-black tone the token already specifies. */
footer.m-footer-template.m-footer { background: var(--m-color-user1); }

@media (min-width: 768px) {
  /* Same unequal-column-height issue as the header: centre the row instead
     of top-aligning the shorter columns against the logo's height. */
  footer.m-footer-template .m-section-inner { align-items: center; }
}

/* Footer padding: live runs a tight 40px bar, not full content-section
   spacing -- set explicitly rather than picking it up from the section-
   rhythm rule above, which this footer opts out of. */
footer.m-footer-template .m-section { padding-top: 40px; padding-bottom: 40px; }

/* Footer nav: the header's larger 1.125rem / 32px-gap treatment (further up
   this file) reads oversized in a slim utility bar. Live's footer links run
   14.4px with a tighter gap; both selectors need the footer-scoped prefix to
   win over the header-wide `.m-nav-menu a` / `.m-nav-menu.m-nav-horizontal
   nav ul` rules. */
footer.m-footer-template .m-nav-menu a { font-size: 0.9rem; }
footer.m-footer-template .m-nav-menu.m-nav-horizontal nav ul { gap: 24px; }

/* Footer nav stacked vertical list (2026-08-20 design feedback round):
   Sean wants "Governance & Compliance" on its own line and "Contact"
   beneath it rather than one inline row. Same selector/specificity as the
   horizontal rule above; wins on source order (later rule, same weight). */
footer.m-footer-template .m-nav-menu.m-nav-horizontal nav ul {
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

/* Footer social icons: live uses plain flat glyphs with no badge. The
   default `.m-social a` treatment (40px circle, tinted fill, hairline ring --
   right for a normal in-page social-links widget) reads heavy and "bubbly"
   at footer scale, so flatten it here only. */
footer.m-footer-template .m-social a {
  width: 20px;
  height: 20px;
  background: transparent;
  border: 0;
}
footer.m-footer-template .m-social a:hover { background: transparent; color: #fff; opacity: 0.75; }

/* Footer's last column stacks the copyright text and the social icon list as
   two separate block children, so on desktop they rendered as two stacked
   lines instead of live's single "© 2026 ... [icons]" row. Row-flex the
   column and right-align it like the source column's own m-align-right
   copy already implies. */
@media (min-width: 768px) {
  footer.m-footer-template .m-col:last-child {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 20px;
  }
}
/* At the default 16px body size "© 2026 Increase Construction" plus the two
   icons doesn't fit the 3-of-12 column (267px at 1440) on one line and
   wraps. Live runs the copyright line at 13.6px; matching that here both
   fits the row and reads as the fine-print size it should be. */
footer.m-footer-template .m-text.m-align-right p { font-size: 0.85rem; white-space: nowrap; }

/* Homepage "Latest From The Blog" cards: live's equivalent card (image, bold
   title, small grey uppercase date) has no divider under the text -- this
   widget's structural `.m-posts article` rule (section 12 above) draws a
   hairline border-bottom on every card, which reads as a stray line under
   text that has nothing below it to separate from. Drop it site-wide for
   this widget; nothing currently uses it to separate stacked content. */
.m-posts article { border-bottom: 0; padding-bottom: 0; }

/* Footer on mobile: live centres every row (logo, nav, copyright, social).
   Turning each column into a centred flex stack does this without fighting
   the copyright paragraph's `m-align-right` utility class -- once the box
   shrinks to its own content width under align-items:center, text-align has
   nothing left to align against. */
@media (max-width: 767px) {
  footer.m-footer-template .m-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 20px;
  }
  footer.m-footer-template .m-nav-menu nav ul { justify-content: center; }
}

/* Outline icons render solid. Icons.php emits two paint styles: filled
   (`fill="currentColor"`, used for social glyphs) and outline (`fill="none"
   stroke="currentColor"`, used for every m-icon-box / checklist icon,
   including the check-circle tick on /grow). The structural stylesheet's
   `.m-icon svg{fill:currentColor}` rule (higher specificity than this file's
   `.m-icon-svg{display:block}`, and loaded after it regardless) applies to
   both, so every outline icon gets filled in solid -- an open circle-plus-
   check glyph becomes a filled blob with a stray diagonal cut where the
   check stroke shows through. The paint style is still in the DOM as the
   `fill="none"` attribute Icons.php wrote, so it can be targeted directly;
   two classes plus the attribute beats the single class + element rule it's
   overriding, so this wins regardless of source order. */
.m-icon svg[fill="none"] { fill: none; }

/* Nav link vertical centring, header and footer alike. Two compounding
   causes left the link text sitting a few px above true centre even after
   the header/footer row-centring rules above: (1) `li` inherits this file's
   generic `margin-bottom:0.4em` (section 3, for prose lists), which is
   trailing space a horizontal nav never wants, and (2) the structural
   `.m-nav-menu nav ul{display:flex}` rule never sets align-items, so it
   defaults to stretch and each `li` fills the ul's full cross-axis height
   with its content pinned to the top of that taller box. Fixing both here
   (rather than in the header/footer alignment rules above) means any current
   or future `.m-nav-menu` -- not just these two -- centres correctly. */
.m-nav-menu nav ul { align-items: center; }
.m-nav-menu nav ul li { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   20. Header/footer logo scale + header height (2026-08-20)
   -------------------------------------------------------------------------- */
/* site-logo's per-instance width rule (`.m-n-xxxxxxxx img{width:Npx}`,
   Renderer::siteLogo()) is queued into self::$responsiveCss but never
   flushed into the published bundle for chrome (header/footer) templates --
   confirmed on the live site.98c16632.css, which contains no
   `.m-n-f86c4356`/`.m-n-d1cc1ac3` rule at all. Without it the logo <img>
   (native 6420x4167, only the base reset's `img{max-width:100%;height:auto}`
   applying) simply fills its column: 267px tall in the header, 236px tall in
   the footer on desktop. Capped directly here instead, independent of that
   broken pipeline. First pass (2026-08-20) capped these at 44px/40px, which
   read as too small once live -- bumped to 54px header / 60px footer, still
   nowhere near the original ~267px runaway. */
footer.m-footer-template .m-logo img { height: 72px; width: auto; }
header.m-header-template .m-logo img { height: 64px; width: auto; }

/* Header vertical padding: was --m-pad-y:24px (paddingY "sm", already the
   smallest step the paddingY enum offers) top and bottom via the structural
   `.m-section{padding-top/bottom:var(--m-pad-y,72px)}` rule. Overridden
   directly here since "sm" has no smaller enum step. Trimmed further to
   10px top/bottom when the logo grew to 54px, keeping header row height
   at ~10+10+54 = 74px -- comfortably above the 44px min tap-target and
   far more compact than the previous ~222px (mostly logo height, not
   padding -- confirmed via live getBoundingClientRect, not source). */
header.m-header-template .m-section { padding-top: 10px; padding-bottom: 10px; }

/* --------------------------------------------------------------------------
   21. Contact-details icon/text vertical centring (2026-08-20)
   -------------------------------------------------------------------------- */
/* `.m-contact div{align-items:center}` (section 10 above) is beaten by the
   structural stylesheet's own `.m-contact div{display:flex;...;align-items:
   flex-start}` (loaded after theme CSS regardless of source order, same
   pattern documented at `.m-icon svg[fill="none"]` above) -- same (0,1,1)
   specificity, later rule wins. Confirmed live: the 44px icon square and the
   shorter one-line email link both start at the row's top edge instead of
   sharing a centre line. Three selectors here (element+class+child+element)
   beats the structural rule's one class + one element regardless of load
   order. */
address.m-contact dl > div { align-items: center; }

/* --------------------------------------------------------------------------
   17. BuildAbility mono-accent system (added 2026-08-20)
   New component classes for the tokens/typography refresh. The mono face
   (IBM Plex Mono as of 2026-08-21, --m-font-mono) is reserved for
   kickers/eyebrows, step numbers, stat values on the dark band, and tags --
   never body copy or headings, which stay the system-font stack.
   -------------------------------------------------------------------------- */

/* --- kicker / eyebrow --------------------------------------------------- */
/* Real pills, added 2026-08-21 (design-audit round 3, item 1). Measured
   against lineaprompt.com's eyebrow tags (e.g. "Product surfaces", "Command
   flow"): border-radius 8px, bg at ~9% accent-tint, border at ~22% accent-tint,
   padding 4px 10px, 11px/600/uppercase/0.12em letter-spacing. Reworked here
   onto BuildAbility's own navy/gold tokens (border-radius uses --m-radius,
   which resolves to tokens.json radius.md = 8px, an exact match) rather than
   copying Linea's violet. Kept the mono face -- that's this theme's own
   established accent treatment (see block comment above), not something
   Linea's kickers use.
   display:flex (not inline-flex) + width:fit-content instead of the old bare
   inline-block: gives a reliable shrink-wrapped pill AND lets the
   :has(.m-align-center) rule below center it with margin:auto regardless of
   whether the containing column itself sets text-align (the trusted-by strip's
   column doesn't, which is why that instance rendered left-aligned before this
   fix -- confirmed via computed getComputedStyle rects on the live page). */
.bb-kicker {
  display: flex;
  align-items: center;
  width: fit-content;
  font-family: var(--m-font-heading);
  font-weight: 600;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--m-color-secondary);
  background: color-mix(in srgb, var(--m-color-accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--m-color-accent) 32%, transparent);
  border-radius: var(--m-radius);
  padding: 4px 10px;
}
.bb-kicker-muted {
  display: flex;
  align-items: center;
  width: fit-content;
  font-family: var(--m-font-heading);
  font-weight: 600;
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--m-color-muted);
  background: var(--m-color-surface);
  border: 1px solid var(--m-color-border);
  border-radius: var(--m-radius);
  padding: 4px 10px;
}
/* The inner .m-text carries the widget's own alignment intent
   (m-align-left/center/right) -- honour it on the pill itself via margin
   rather than relying on the containing column to also set text-align, since
   not every column does (trusted-by strip did not). */
.bb-kicker:has(.m-align-center),
.bb-kicker-muted:has(.m-align-center) {
  margin-left: auto;
  margin-right: auto;
}
.bb-kicker:has(.m-align-right),
.bb-kicker-muted:has(.m-align-right) {
  margin-left: auto;
  margin-right: 0;
}
/* Dark-section contrast (.ic-dark, e.g. a future dark hero/CTA band reusing a
   kicker) -- the default navy text and light tints above disappear on navy,
   so flip to white-on-translucent like the existing .ic-dark button/nav
   overrides elsewhere in this file. */
.ic-dark .bb-kicker {
  color: #fff;
  background: rgba(255, 255, 255, 0.12);
  border-color: rgba(255, 255, 255, 0.32);
}
.ic-dark .bb-kicker-muted {
  color: rgba(255, 255, 255, 0.7);
  background: rgba(255, 255, 255, 0.06);
  border-color: rgba(255, 255, 255, 0.18);
}

/* --- browser-chrome image frame ------------------------------------------
   No nested wrapper markup is available from the widget renderer (a widget
   with a custom cssClass gets exactly one wrapping <div>, no inner bar
   element), so the top bar and its three dots are drawn with ::before /
   ::after pseudo-elements rather than a literal `.bb-frame-bar` node. The
   `.bb-frame-bar` selector is kept below as a hook in case a future widget
   type does render one -- it currently matches nothing and is harmless. */
.bb-frame {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--m-color-border);
  border-radius: var(--m-radius-lg, 16px);
  box-shadow: var(--m-shadow-md);
  padding-top: 30px;
  background: var(--m-color-surface);
  transition: transform var(--m-speed) var(--m-ease), box-shadow var(--m-speed) var(--m-ease);
}
.bb-frame:hover { transform: translateY(-3px); box-shadow: var(--m-shadow-lg); }
.bb-frame::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 30px;
  background: var(--m-color-surface);
  border-bottom: 1px solid var(--m-color-border);
}
.bb-frame::after {
  content: "";
  position: absolute;
  top: 14px;
  left: 16px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--m-color-border);
  box-shadow: 16px 0 0 var(--m-color-border), 32px 0 0 var(--m-color-border);
}
.bb-frame-bar { /* see comment above -- reserved, not currently rendered */
  height: 30px;
  border-bottom: 1px solid var(--m-color-border);
  background: var(--m-color-surface);
}
.bb-frame img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 0 0 var(--m-radius-lg, 16px) var(--m-radius-lg, 16px);
}

/* --- hero product screenshot: more visual presence (added 2026-08-21) ----
   The hero's pulse-dashboard.png is a genuinely wide/short screenshot
   (1600x760, ~2.1:1), so at width:100%/height:auto it reads small and
   letterboxed next to the taller hero copy column. Scoped to this one
   widget instance (.m-n-5fa8b561 is the unique node id Mason renders for
   the hero image widget -- other .bb-frame instances further down the page,
   KPI row/stage panel/scorecards, are untouched and keep their natural
   ratio) rather than changing .bb-frame img globally. Desktop-only
   (min-width matches --m-bp-tablet 1024px): below that the frame stacks
   full-width under the copy and its natural ratio already reads fine, so a
   forced crop there would just lose more of the screenshot for no gain.
   Crops to a taller 4:3 and anchors to the top, keeping the KPI cards and
   overall-satisfaction score (the strongest part of the screenshot) fully
   visible and only trimming the lower "customers by stage" list. */
@media (min-width: 1025px) {
  .m-n-5fa8b561.bb-frame img {
    width: 100%;
    height: 420px;
    object-fit: cover;
    object-position: top;
  }
}

/* --- numbered step pattern ------------------------------------------------ */
.bb-step {
  padding-top: 24px;
  border-top: 1px solid var(--m-hairline);
}
.bb-step-num {
  display: block;
  font-family: var(--m-font-mono);
  font-weight: 500;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--m-color-accent);
  margin-bottom: 12px;
}
.bb-step h3 {
  margin: 0 0 8px;
}

/* --- dark-band stat values ------------------------------------------------
   `.ic-dark` is the existing convention this theme's blocks already use
   (style.base.cssClass) to mark a navy section -- see the stats band and
   closing CTA band on the home page. */
.ic-dark .m-stat-value {
  font-family: var(--m-font-mono);
  font-weight: 500;
  color: var(--m-color-accent);
}

/* --- tag / "coming soon" pill --------------------------------------------- */
.bb-tag {
  display: inline-flex;
  align-items: center;
  padding: 6px 16px;
  font-family: var(--m-font-mono);
  font-weight: 500;
  font-size: var(--m-size-accent, 0.75rem);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--m-color-primary);
  background: color-mix(in srgb, var(--m-color-primary) 10%, transparent);
  border-radius: var(--m-radius-full, 999px);
}

/* --- CTA button: slightly tighter than the base .m-btn ------------------- */
.m-btn-primary {
  padding: 11px 24px;
  border-radius: var(--m-radius-sm, 6px);
}

/* --------------------------------------------------------------------------
   18. Footer flattening (added 2026-08-20)
   The site footer is a dark (.ic-dark) template section, so the hairline
   uses a translucent white rather than the light-mode border token, and the
   copyright column gets a smaller, muted treatment.
   -------------------------------------------------------------------------- */
.m-footer-template { border-top: 1px solid rgba(255, 255, 255, 0.14); }
.m-footer-template .m-col-3 .m-text p {
  font-size: 0.8125rem;
  opacity: 0.65;
}

/* --- hero image: soft lift + slight left tilt (added 2026-08-21) ---------
   Reference: lineaprompt.com's hero panel (.summon-panel.magnetic-panel) sits
   at a small static rotate(-2.6deg) with a large soft drop shadow beneath it
   (rgba(58,74,100,.55) 0 34px 96px -48px) plus a 1px inset highlight on top.
   Applied to the same .m-n-5fa8b561 frame as the crop rule above -- desktop
   only, same breakpoint, so mobile keeps the frame flat/full-width. Kept the
   existing --m-shadow-md border/shadow on .bb-frame itself and layered this
   shadow on top via the wrapping node so hover-lift (.bb-frame:hover) still
   works unmodified. */
@media (min-width: 1025px) {
  .m-n-5fa8b561.bb-frame {
    transform: rotate(-1.6deg);
    box-shadow: 0 34px 72px -32px rgba(22, 50, 74, 0.35), var(--m-shadow-md);
  }
  .m-n-5fa8b561.bb-frame:hover {
    transform: rotate(-1.6deg) translateY(-3px);
  }
}

/* --- hero heading underline stroke (added 2026-08-21) ---------------------
   Reference: lineaprompt.com draws a hand-drawn squiggle SVG under the last
   word of its h1 (.hero-underline, indigo stroke, animates in via
   stroke-dasharray). Mason's heading widget renders a single text node with
   no per-word span to hook a precise "last line only" underline the way a
   hand-built React page can, so this approximates it as a fixed-width
   decorative stroke under the whole hero heading block instead of one word --
   same idea (a hand-drawn accent, not a rule line), simpler execution.
   Scoped to the hero heading only (.m-n-a1ecd941, the unique node id) so it does not touch any other heading on the page. Gold accent, not lineaprompt's
   indigo, to stay on-brand. */
.m-n-a1ecd941 {
  position: relative;
}
.m-n-a1ecd941::after {
  content: "";
  display: block;
  width: 180px;
  max-width: 60%;
  height: 12px;
  margin-top: 4px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 220 12'%3E%3Cpath d='M2 7.5C40 3.5 92 2.5 138 5.5C168 7.5 196 8.5 218 6' stroke='%23CF8E25' stroke-width='3' stroke-linecap='round' fill='none'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: 100% 100%;
  opacity: 0.9;
}


/* --- v0.6 animation library --- */
@keyframes m-anim-fade-in{from{opacity:0}to{opacity:1;transform:none}}@keyframes m-anim-fade-up{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:none}}@keyframes m-anim-fade-down{from{opacity:0;transform:translateY(-24px)}to{opacity:1;transform:none}}@keyframes m-anim-slide-left{from{opacity:0;transform:translateX(32px)}to{opacity:1;transform:none}}@keyframes m-anim-slide-right{from{opacity:0;transform:translateX(-32px)}to{opacity:1;transform:none}}@keyframes m-anim-zoom-in{from{opacity:0;transform:scale(.92)}to{opacity:1;transform:none}}.m-anim-ready .m-anim{opacity:0}.m-anim-ready .m-anim.m-in{opacity:1}@media (prefers-reduced-motion: reduce){.m-anim,.m-anim-ready .m-anim{opacity:1!important;animation:none!important}}

/* --- v0.6 widgets (structure only) --- */
.m-icon{display:inline-flex;line-height:0}
.m-icon svg{width:1em;height:1em;fill:currentColor}
.m-icon-box{display:flex;gap:16px}
.m-icon-box-top{flex-direction:column;align-items:flex-start}
.m-icon-box .m-icon{font-size:32px;color:var(--m-color-primary)}
.m-icon-box h2,.m-icon-box h3,.m-icon-box h4{margin:0 0 8px}
.m-testimonial{margin:0}
.m-testimonial blockquote{margin:0 0 12px;font-size:1.125rem}
.m-testimonial figcaption{display:flex;align-items:center;gap:12px}
.m-testimonial img{width:48px;height:48px;border-radius:999px;object-fit:cover}
.m-rating{display:inline-flex;gap:2px;color:var(--m-color-accent)}
.m-card{display:flex;flex-direction:column;overflow:hidden;border-radius:var(--m-radius);background:var(--m-color-bg)}
.m-card img{width:100%;object-fit:cover}
.m-card-body{padding:20px;display:flex;flex-direction:column;gap:8px}
.m-stat{text-align:center}
.m-stat-value{display:block;font-family:var(--m-font-heading);font-size:2.5rem;font-weight:700;line-height:1.1}
.m-stat-label{display:block;color:var(--m-color-muted)}
.m-pricing{display:flex;flex-direction:column;gap:12px;padding:24px;border:1px solid var(--m-color-border);border-radius:var(--m-radius)}
.m-pricing-featured{border-color:var(--m-color-primary);border-width:2px}
.m-pricing-price{font-family:var(--m-font-heading);font-size:2.25rem;font-weight:700;line-height:1}
.m-pricing ul{margin:0;padding-left:1.1em}
.m-team{text-align:center}
.m-team img{width:100%;max-width:220px;aspect-ratio:1;object-fit:cover;border-radius:var(--m-radius)}
.m-team-role{color:var(--m-color-muted);margin:4px 0}
.m-logo-strip{display:grid;gap:24px;align-items:center}
.m-logo-strip img{width:100%;height:auto;object-fit:contain}
.m-logo-strip-mono img{filter:grayscale(1);opacity:.7}
.m-cta-banner{display:flex;flex-wrap:wrap;gap:16px;align-items:center;justify-content:space-between;padding:32px;border-radius:var(--m-radius);background:var(--m-color-surface)}
.m-cta-banner-stacked{flex-direction:column;text-align:center}
.m-cta-banner h2,.m-cta-banner h3{margin:0}
.m-social{display:flex;gap:12px;flex-wrap:wrap;list-style:none;margin:0;padding:0}
.m-social a{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:var(--m-radius)}
.m-social-round a{border-radius:999px}
.m-contact{margin:0}
.m-contact div{display:flex;gap:12px;align-items:flex-start;margin-bottom:12px}
.m-contact dt{flex:0 0 auto;color:var(--m-color-primary)}
.m-contact dd{margin:0}
.m-map{position:relative;border-radius:var(--m-radius);overflow:hidden;background:var(--m-color-surface)}
.m-map iframe{display:block;width:100%;height:100%;border:0}
.m-map-load{display:flex;flex-direction:column;gap:8px;align-items:center;justify-content:center;width:100%;height:100%;border:0;cursor:pointer;background:transparent;font:inherit;color:inherit;padding:16px;text-align:center}
.m-map-load img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.5}
.m-map-load span{position:relative}
.m-posts{display:grid;gap:24px}
.m-posts article{display:flex;flex-direction:column;gap:8px}
.m-posts img{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:var(--m-radius)}
.m-posts h3{margin:0}
.m-shape{position:absolute;left:0;width:100%;line-height:0;pointer-events:none;overflow:hidden}
.m-shape svg{display:block;width:100%;height:100%}
.m-shape-top{top:0}
.m-shape-bottom{bottom:0;transform:rotate(180deg)}
.m-section-shaped{position:relative;overflow:hidden}
.m-valign-middle>.m-section-inner{align-items:center}
.m-valign-bottom>.m-section-inner{align-items:flex-end}
.m-col-sticky{position:sticky;top:24px}
.m-col-top{align-self:flex-start}
.m-col-middle{align-self:center}
.m-col-bottom{align-self:flex-end}
.m-btn-sm{padding:8px 16px;font-size:.875rem}
.m-btn-lg{padding:16px 32px;font-size:1.125rem}
.m-btn-block{display:block;width:100%;text-align:center}
.m-btn .m-icon{margin-inline:0 .5em}
.m-btn-icon-right .m-icon{order:2;margin-inline:.5em 0}
.m-image-zoom{overflow:hidden}
.m-image-zoom img{transition:transform .4s ease}
.m-image-zoom:hover img{transform:scale(1.06)}
.m-ratio-square img{aspect-ratio:1}
.m-ratio-standard img{aspect-ratio:4/3}
.m-ratio-wide img{aspect-ratio:16/9}
.m-ratio-portrait img{aspect-ratio:3/4}
.m-fit-cover img{object-fit:cover;width:100%}
.m-fit-contain img{object-fit:contain;width:100%}
.m-form-2col{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.m-form-2col>button,.m-form-2col>p{grid-column:1/-1}
/* full_width field spans both columns. NOTE: like the >button/>p rule above,
   the direct-child combinator does not cross a two-step form's .m-form-step
   display:contents wrapper, so a full-width field inside a stepped 2-col form
   stays half-width (consistent with the submit button's existing behaviour). */
.m-form-2col>.m-form-field-full{grid-column:1/-1}
.m-form-fill .m-form-field input,.m-form-fill .m-form-field textarea,.m-form-fill .m-form-field select{background:var(--m-field-bg,var(--m-color-surface))}
.m-form-field input,.m-form-field textarea,.m-form-field select{border-color:var(--m-field-border,var(--m-color-border));border-radius:var(--m-field-radius,var(--m-radius))}
.m-form-field>span{color:var(--m-label-color,inherit)}
.m-table thead th{background:var(--m-th-bg,var(--m-color-surface));color:var(--m-th-color,inherit)}
.m-table-striped tbody tr:nth-child(odd){background:var(--m-stripe-bg,var(--m-color-surface))}
.m-table td,.m-table th{border-color:var(--m-table-border,var(--m-color-border))}
.m-toggle-divider{border-bottom:1px solid var(--m-color-border)}
.m-lightbox{position:fixed;inset:0;background:rgba(0,0,0,.9);display:flex;align-items:center;justify-content:center;z-index:9999;border:0;padding:24px}
.m-lightbox img{max-width:100%;max-height:90vh;object-fit:contain}
.m-logo img{display:block;height:auto;max-width:100%}
.m-logo-text{font-family:var(--m-font-heading);font-weight:700;font-size:1.25rem}
.m-nav-menu nav ul{display:flex;flex-wrap:wrap;gap:20px;list-style:none;margin:0;padding:0}
.m-nav-vertical nav ul{flex-direction:column;gap:10px}
.m-nav-toggle{display:none;align-items:center;gap:8px;background:transparent;border:0;font:inherit;color:inherit;cursor:pointer;padding:8px}
.m-nav-toggle .m-nav-bars{display:block;width:20px;height:2px;background:currentColor;box-shadow:0 6px 0 currentColor,0 -6px 0 currentColor}
.m-nav-menu a:focus-visible,.m-nav-toggle:focus-visible{outline:2px solid var(--m-color-primary);outline-offset:2px}
.m-nav-item{position:relative;display:flex;align-items:center}
.m-nav-toggle-sub{display:inline-flex;align-items:center;justify-content:center;background:transparent;border:0;color:inherit;font:inherit;cursor:pointer;padding:4px 6px;margin-inline-start:2px}
.m-nav-toggle-sub:focus-visible{outline:2px solid var(--m-color-primary);outline-offset:2px}
.m-nav-caret{display:inline-block;width:0;height:0;border-left:4px solid transparent;border-right:4px solid transparent;border-top:5px solid currentColor;transition:transform .15s ease}
.m-nav-item.m-nav-sub-open .m-nav-caret,.m-nav-toggle-sub[aria-expanded="true"] .m-nav-caret{transform:rotate(180deg)}
/*
 * `.m-nav-menu .m-nav-item .m-nav-submenu` (three classes) rather than the
 * more obvious `.m-nav-submenu` on its own: the submenu <ul> is a descendant
 * of the widget's own <nav>, exactly like the top-level <ul>, so the plain
 * one-class selector would tie on specificity with `.m-nav-menu nav ul`
 * above (and lose outright to increase-construction/theme.css's
 * `.m-nav-menu.m-nav-horizontal nav ul{gap:32px}`) and inherit a horizontal
 * flex gap meant for the top-level menu, not a dropdown list.
 */
.m-nav-menu .m-nav-item .m-nav-submenu{position:absolute;top:100%;left:0;z-index:60;display:none;flex-direction:column;flex-wrap:nowrap;gap:2px;min-width:200px;margin:4px 0 0;padding:8px 0;list-style:none;background:var(--m-color-bg);border:1px solid var(--m-color-border);border-radius:var(--m-radius);box-shadow:0 8px 24px rgba(0,0,0,.15)}
.m-nav-item.m-nav-align-right .m-nav-submenu{left:auto;right:0}
.m-nav-item.m-nav-sub-open>.m-nav-submenu,.m-nav-item:hover>.m-nav-submenu,.m-nav-item:focus-within>.m-nav-submenu{display:flex}
.m-nav-submenu li{width:100%}
.m-nav-menu .m-nav-submenu a{display:block;padding:8px 16px;white-space:nowrap}
.m-nav-submenu .m-nav-item{width:100%}
.m-nav-vertical .m-nav-menu .m-nav-item .m-nav-submenu{position:static;flex-direction:column;margin:4px 0 0 0;padding-left:16px;border:0;box-shadow:none;background:transparent;min-width:0}
.m-visually-hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
.m-lightbox-close{position:absolute;top:12px;right:16px;background:transparent;border:0;color:#fff;font-size:2rem;line-height:1;cursor:pointer}
/* --- neutral blog fallback (themes may override) --- */
:where(.m-blog-hero){position:relative;display:flex;align-items:center;justify-content:center;text-align:center;min-height:180px;padding:48px var(--m-gutter);max-width:var(--m-max-width);margin:0 auto;box-sizing:border-box}
:where(.m-blog-hero-inner){position:relative;max-width:720px}
:where(.m-blog-hero-inner) :where(h1){margin:0 0 12px}
:where(.m-blog-hero-inner) :where(p){margin:0;opacity:.8}
:where(.m-blog-grid){display:grid;grid-template-columns:repeat(3,1fr);gap:32px}
@media (max-width:900px){:where(.m-blog-grid){grid-template-columns:repeat(2,1fr)}}
@media (max-width:640px){:where(.m-blog-grid){grid-template-columns:1fr}}@media (max-width:767px){.m-nav-mobile-drawer .m-nav-toggle:not([hidden]){display:inline-flex}.m-nav-mobile-drawer .m-nav-toggle:not([hidden])+nav{display:none}.m-nav-mobile-drawer.m-nav-open .m-nav-toggle+nav{display:block;width:100%}.m-nav-mobile-drawer nav ul{flex-direction:column;gap:0}.m-nav-mobile-drawer nav ul>li{border-top:1px solid var(--m-hairline, var(--m-color-border))}.m-nav-mobile-drawer nav ul>li:first-child{border-top:0}.m-nav-mobile-drawer nav ul>li>a{display:block;padding:14px 4px;min-height:44px;box-sizing:border-box}.m-nav-mobile-inline nav ul>li>a{display:block;padding:10px 4px;min-height:44px;box-sizing:border-box}.m-nav-mobile-hidden nav{display:none}.m-nav-mobile-drawer .m-nav-submenu{position:static;flex-direction:column;margin:4px 0 0;padding-left:16px;border:0;box-shadow:none;background:transparent;min-width:0}.m-nav-mobile-drawer .m-nav-item:hover>.m-nav-submenu{display:none}.m-nav-mobile-drawer .m-nav-item.m-nav-sub-open>.m-nav-submenu,.m-nav-mobile-drawer .m-nav-item:focus-within>.m-nav-submenu{display:flex}.m-nav-mobile-drawer .m-nav-item{flex-wrap:wrap}}
