/*
Theme Name: Cititel
Template: aw-base
Description: Cititel Telephone Systems. Client-specific design system on top of aw-base.
Version: 0.1.0
*/

/* ------------------------------------------------------------------
   Loaded after aw-base/tokens.css and aw-base/style.css.
   aw-base's own components read --aw-* variables, so this file defines
   the Cititel design tokens AND remaps the --aw-* layer onto them.
   Never override aw-base/tokens.css wholesale: doing so deletes every
   --aw-* value the parent stylesheet depends on and the type scale
   collapses to browser defaults.
   ------------------------------------------------------------------ */

:root {
  /* ---- Brand fixed values ---- */
  /* Aligned to the chosen logo art, 3 September. The logo's own blue is #028BE9,
     which is only 3.58:1 on white and cannot carry a label or a fill. --c-navy is
     that blue darkened until it clears 4.5:1, so the site reads as the same colour
     family as the mark without failing contrast. */
  --c-navy: #075BA6;
  --c-ink: #2B2A2A;
  --c-white: #FFFFFF;
  --c-tagline-red: #FF3B30;   /* registered wording only, display sizes only */

  /* ---- Navy ramp ---- */
  --navy-50:  #EAF2FA;   /* section tint. #F2F8FD read as white against white. */
  --navy-100: #D6E9F8;
  --navy-200: #A9D2F1;
  --navy-300: #6FB4E6;
  --navy-400: #2E96DC;
  --navy-500: #0C82CE;
  --navy-600: #0271B7;
  --navy-700: #025C96;  /* brand, the logo blue darkened to pass */
  --navy-800: #014A79;  /* hover */
  --navy-900: #0B3556;  /* pressed and the dark ground */
  --navy-950: #072940;

  /* ---- Red ---- */
  --cyan: #99E5F5;      /* the logo's bright blue. Decoration on dark only. */
  --amber: #9A5B00;     /* review stars, 5.43:1 on white */
  --cyan-ink: #026099;  /* the same blue darkened, 6.15:1 on white, safe for icons and text */
  --red-500: #FF3B30;   /* tagline */
  --red-700: #C7291F;   /* any red UI element: passes AA with white text */
  --red-50:  #FEF4F3;   /* error field fill */
  --red-200: #F5C9C4;
  --red-300: #FF8A82;   /* offer tag on navy, 6.9:1 */

  /* ---- Semantic ---- */
  --bg: var(--c-white);
  --bg-tint: var(--navy-50);
  --bg-inverse: var(--navy-900);
  --surface: var(--c-white);
  --surface-inverse: var(--navy-800);
  --border: var(--navy-100);
  --border-strong: var(--navy-200);   /* decorative only, never a control edge */
  --border-control: var(--navy-400);  /* form controls, 4.84:1 on white, WCAG 1.4.11 */
  --border-inverse: var(--navy-600);
  --text: var(--c-ink);
  /* A slate, NOT a step on the navy ramp. It was --navy-600 (#0B65AB), which
     sits 1.06:1 against --action (#075BA6): every muted paragraph on the site
     read as a link. Contrast audits pass either way, so this is invisible to
     them. 6.46:1 on white, 6.03:1 on the tint. */
  --text-muted: #5A6570;
  --text-inverse: var(--c-white);
  --text-inverse-muted: var(--navy-200);
  --action: var(--navy-700);
  --action-hover: var(--navy-800);
  --action-active: var(--navy-900);
  --action-text: var(--c-white);
  --focus-ring: var(--navy-700);
  --error: var(--red-700);
  --placeholder: var(--navy-500);     /* 7.46:1 on white */

  /* ---- Type ---- */
  --font-display: Archivo, system-ui, sans-serif;
  --font-body: "Source Sans 3", system-ui, sans-serif;

  --fs-display-xl: 76px;  --lh-display-xl: 0.97;  --tr-display-xl: -0.035em;
  --fs-h1: 56px;          --lh-h1: 1.04;          --tr-h1: -0.03em;
  --fs-h2: 40px;          --lh-h2: 1.1;           --tr-h2: -0.025em;
  --fs-h3: 28px;          --lh-h3: 1.2;           --tr-h3: -0.015em;
  --fs-h4: 21px;          --lh-h4: 1.35;
  --fs-body-lg: 19px;     --lh-body-lg: 1.68;
  --fs-body: 17px;        --lh-body: 1.65;
  --fs-small: 15px;       --lh-small: 1.6;
  --fs-eyebrow: 13px;     --tr-eyebrow: 0.14em;

  /* ---- Spacing (4px base) ---- */
  --sp-1: 4px;   --sp-2: 8px;   --sp-3: 12px;  --sp-4: 16px;
  --sp-6: 24px;  --sp-8: 32px;  --sp-12: 48px; --sp-16: 64px;
  --sp-24: 96px; --sp-32: 128px; --sp-40: 160px;

  --gutter: 64px;
  --section-y: 72px;
  /* 45.5rem is 728px, which is what 68ch measured as on the body font. It is stated in rem
     rather than ch on purpose: ch is font-relative, so a measure in ch is a DIFFERENT width on a
     40px heading than on 17px body text. That is fine while it only caps line length, and wrong
     the moment anything has to line two elements up against it. */
  --measure: 45.5rem;

  /* ---- Radius ---- */
  --r-input: 4px;
  --r-button: 6px;
  --r-card: 12px;
  --r-panel: 20px;

  /* ---- Elevation ---- */
  --shadow-sm: 0 1px 2px rgba(14, 21, 32, 0.06);
  --shadow-md: 0 6px 16px rgba(14, 21, 32, 0.10);
  --shadow-lg: 0 18px 40px rgba(14, 21, 32, 0.16);

  /* ---- Logo slot ---- */
  --logo-slot-h: 40px;   /* mobile */
  --logo-slot-h-condensed: 30px;
  --logo-clear: 16px;

  /* ---- Motion ---- */
  --dur-fast: 140ms;
  --dur: 180ms;
  --dur-reveal: 260ms;   /* header condense and logo height: must feel immediate */
  --dur-menu:   210ms;   /* nav dropdown. 50% longer than --dur-fast, which read as a snap. */
  /* Anything ARRIVING on the page runs to one number. Responses to the user
     keep their own faster tokens above. */
  --dur-enter: 1300ms;
  --dur-card:  var(--dur-enter);   /* card and stat reveals */
  --dur-slide: var(--dur-enter);   /* the handset images */
  --dur-count: var(--dur-enter);   /* the number counters, read by motion.js */
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
  --stagger: 120ms;
}

@media (max-width: 720px) {
  :root {
    --fs-display-xl: 44px; --lh-display-xl: 1.02;
    --fs-h1: 36px;
    --fs-h2: 30px;
    --fs-h3: 24px;
    --gutter: 20px;
    --section-y: 56px;
    --logo-slot-h: 32px;
  }
}

/* Navy ground: set on any section to flip the semantic layer. */
.on-navy {
  --cyan-ink: var(--cyan);
  --bg: var(--navy-900);
  --surface: var(--navy-800);
  --border: var(--navy-600);
  --border-strong: var(--navy-400);
  --text: var(--c-white);
  --text-muted: var(--navy-200);
  --action: var(--c-white);
  --action-hover: var(--navy-100);
  --action-active: var(--navy-100);
  --action-text: var(--navy-800);
  --focus-ring: var(--c-white);
  --bg-tint: var(--navy-800);          /* was inheriting the light tint */
  --border-control: var(--navy-300);   /* 5.77:1 on the navy ground */
  --placeholder: var(--navy-300);
  --error: #FF8A80;                    /* 7.17:1 on navy; red-700 was 2.94 */
  --shadow-sm: none; --shadow-md: none; --shadow-lg: none;

  /* The block above only remaps tokens. Paint the ground too, or the section
     stays transparent and light-on-navy text lands on white. */
  background: var(--bg);
  color: var(--text);
}

@media (prefers-reduced-motion: reduce) {
  :root { --dur-fast: 0ms; --dur: 0ms; --dur-reveal: 0ms; --dur-card: 0ms; --dur-count: 0ms; --dur-slide: 0ms; --stagger: 0ms; }
}


/* ---- Drive aw-base from the Cititel tokens ---- */
:root {
  --aw-color-bg: var(--c-white);
  --aw-color-text: var(--c-ink);
  --aw-color-muted: var(--text-muted);
  --aw-color-border: var(--border);
  --aw-color-accent: var(--c-navy);
  --aw-color-accent-text: var(--c-white);
  --aw-color-secondary: var(--red-700);
  --aw-color-secondary-text: var(--c-white);
  --aw-color-inverted-bg: var(--navy-900);
  --aw-color-inverted-text: var(--c-white);
  --aw-color-link: var(--action);
  --aw-color-surface: var(--bg-tint);
  --aw-surface-bg: var(--bg-tint);
  --aw-brand-danger: var(--error);
  --aw-focus-ring: var(--focus-ring);

  --aw-font-body: var(--font-body);
  --aw-font-heading: var(--font-display);
  --aw-font-size-base: var(--fs-body);
  --aw-font-size-lead: var(--fs-body-lg);
  --aw-font-size-h1: var(--fs-h1);
  --aw-font-size-h2: var(--fs-h2);
  --aw-font-size-h3: var(--fs-h3);
  --aw-font-size-small: var(--fs-small);
  --aw-font-size-eyebrow: var(--fs-eyebrow);
  --aw-line-height: var(--lh-body);
  --aw-line-height-heading: var(--lh-h2);
  --aw-font-weight-heading: 800;
  --aw-letter-spacing-heading: var(--tr-h2);
  --aw-eyebrow-letter-spacing: var(--tr-eyebrow);

  --aw-radius: var(--r-card);
  --aw-button-radius: var(--r-button);
  --aw-button-font-weight: 700;
  --aw-card-shadow: var(--shadow-sm);
  --aw-header-bg: var(--c-white);
  --aw-footer-bg: var(--navy-900);
  --aw-footer-text: var(--c-white);
  --aw-footer-muted: var(--navy-200);
}

/* aw-base titles use a class, which outranks the bare h1 rule below. */
.aw-entry__title { font-family: var(--font-display); font-size: var(--fs-h1);
  line-height: var(--lh-h1); letter-spacing: var(--tr-h1); font-weight: 800; }


/* ---- Components ---- */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
}

/* Every link rule below excludes .btn. A button is not a link visually, and an
   `a:hover` rule outranks `.btn--primary` on specificity, which silently painted
   the CTA label the same navy as its own hover background.
   The exclusion is written :not(:where(.btn)) rather than :not(.btn) so it keeps
   the specificity of a bare `a`. Plain :not(.btn) raises it to 0,1,1, which then
   overrides aw-base's own .aw-skip-link colour and hides the skip link. */
a:not(:where(.btn)) { color: var(--action); text-decoration: none; }
a:not(:where(.btn)):hover { color: var(--action-hover); }
/* Links inside prose are underlined, so colour is never the only signal (WCAG 1.4.1). */
/* Component links inside prose are excluded by name. This rule is 0,1,1 and beat
   .aw-project-grid__link at 0,1,0, so the card titles were underlined even
   though the component asked for none. The exclusions sit inside :where() so
   the specificity does not move. */
.prose a:not(:where(.btn, .aw-project-grid__link, .aw-cta-banner__button)),
p a:not(:where(.btn, .aw-project-grid__link, .aw-cta-banner__button)),
li a:not(:where(.btn, .aw-project-grid__link, .aw-cta-banner__button)) { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.prose a:not(:where(.btn)):hover, p a:not(:where(.btn)):hover, li a:not(:where(.btn)):hover { text-decoration-thickness: 2px; }
.on-navy a:not(:where(.btn)) { color: var(--c-white); }
.on-navy a:not(:where(.btn)):hover { color: var(--navy-200); }

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--focus-ring);
  border-radius: var(--r-button);
}

/* ---------- Layout ---------- */
.section { padding: var(--section-y) var(--gutter); }
.section--tint { background: var(--bg-tint); border-block: 1px solid var(--border); }
.section--navy { background: var(--navy-900); color: var(--c-white); }
.wrap { max-width: 1180px; margin-inline: auto; }
.stack > * + * { margin-top: var(--sp-4); }
.grid { display: grid; gap: var(--sp-6); }
.grid--2 { grid-template-columns: repeat(2, 1fr); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--4 { grid-template-columns: repeat(4, 1fr); }
.row { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; }
@media (max-width: 900px) {
  .grid--2, .grid--3, .grid--4 { grid-template-columns: 1fr; }
}

/* ---------- Type ---------- */
.display { font-family: var(--font-display); font-weight: 900; font-size: var(--fs-display-xl); line-height: var(--lh-display-xl); letter-spacing: var(--tr-display-xl); margin: 0; text-wrap: balance; }
h1, .h1 { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h1); line-height: var(--lh-h1); letter-spacing: var(--tr-h1); margin: 0; }
h2, .h2 { font-family: var(--font-display); font-weight: 800; font-size: var(--fs-h2); line-height: var(--lh-h2); letter-spacing: var(--tr-h2); margin: 0; }
h3, .h3 { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h3); line-height: var(--lh-h3); letter-spacing: var(--tr-h3); margin: 0; }
h4, .h4 { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h4); line-height: var(--lh-h4); margin: 0; }
.lead { font-size: var(--fs-body-lg); line-height: var(--lh-body-lg); max-width: 46ch; }
.small { font-size: var(--fs-small); line-height: var(--lh-small); color: var(--text-muted); }
/* --navy-700, not --navy-500. Deepening the section tint to #EAF2FA so a
   section change actually reads pushed navy-500 to 4.45:1 against it, just
   under the line. This clears both grounds: 6.08 on the tint, 6.87 on white. */
.eyebrow { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: var(--tr-eyebrow); text-transform: uppercase; color: var(--action); }
.on-navy .eyebrow { color: var(--navy-300); }
/* .tagline, .tagline--sm and .on-navy .tagline--sm were removed on 13 September 2026.
   The footer was their only user, and the tagline now lives inside the reversed logo
   artwork rather than as a line of red text beneath it. Nothing else on the site sets
   the class. If the wording is ever needed as live text again, it is registered and
   takes red-700 at body size (red-500 clears 3:1 only, so it is display sizes only). */

/* ---------- Buttons ---------- */
.btn { text-decoration: none; }   /* WP core underlines a:where(:not(.wp-element-button)) */
.btn:hover, .btn:focus { text-decoration: none; }
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font-family: var(--font-body); font-weight: 700; font-size: 17px; line-height: 1;
  padding: 16px 24px; min-height: 48px; border-radius: var(--r-button);
  border: 1.5px solid transparent; cursor: pointer;
  transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.btn--primary { background: var(--action); color: var(--action-text); }
.btn--primary:hover { background: var(--action-hover); transform: translateY(-2px); box-shadow: var(--shadow-lg); }
.btn--primary:active { background: var(--action-active); transform: none; box-shadow: none; }
.btn--primary[disabled] { background: var(--navy-100); color: var(--navy-300); pointer-events: none; }
.btn--secondary { background: transparent; color: var(--action); border-color: var(--action); }
.btn--secondary:hover { background: var(--navy-100); }
.btn--secondary:active { background: var(--navy-200); }
.on-navy .btn--secondary { color: var(--c-white); border-color: var(--navy-400); }
.on-navy .btn--secondary:hover { background: var(--navy-800); border-color: var(--navy-300); }
.btn--quiet { background: transparent; color: var(--action); padding-inline: var(--sp-3); }
.btn--quiet:hover { background: var(--bg-tint); }
.btn--sm { font-size: 15px; padding: 12px 18px; min-height: 44px; }
.btn--block { width: 100%; }
@media (max-width: 720px) { .btn { width: 100%; } }

/* ---------- Header and the logo slot ---------- */
.header { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-8); padding: 18px var(--gutter); background: var(--bg); border-bottom: 1px solid var(--border); position: sticky; top: 0; z-index: 50; transition: padding var(--dur) var(--ease); }
.header__left { display: flex; align-items: center; gap: var(--sp-8); min-width: 0; }
/* Fixed height, floating width: holds from 1:1 to 3:1. */
.logo-slot { flex: none; height: var(--logo-slot-h); display: block; margin-right: calc(var(--logo-clear) - var(--sp-8) + var(--sp-8)); }
.logo-slot > svg, .logo-slot > img { height: 100%; width: auto; display: block; }
.nav { display: flex; align-items: center; gap: 26px; font-weight: 600; }
.nav a { color: var(--text); }
.nav a[aria-current="page"] { color: var(--action); box-shadow: inset 0 -2px 0 var(--action); }
.header__phone { font-family: var(--font-display); font-weight: 700; font-size: 17px; color: var(--navy-800); }
.on-navy .header__phone { color: var(--c-white); }
.header.is-condensed { padding-block: 10px; background: var(--navy-950); }
.header.is-condensed .logo-slot { height: var(--logo-slot-h-condensed); }
.header.is-condensed .header__phone { display: none; }
.header__burger, .header__call { width: 44px; height: 44px; display: none; align-items: center; justify-content: center; border-radius: var(--r-button); }
@media (max-width: 900px) {
  .nav, .header__phone { display: none; }
  .header__burger, .header__call { display: inline-flex; }
}

/* Mobile navigation: full-height navy sheet, 44px targets. */
.mobile-nav { position: fixed; inset: 0; background: var(--navy-900); color: var(--c-white); display: grid; align-content: start; padding: var(--sp-2) 0 var(--sp-6); overflow-y: auto; opacity: 0; transform: translateY(-8px); pointer-events: none; transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease); }
.mobile-nav[data-open="true"] { opacity: 1; transform: none; pointer-events: auto; }
.mobile-nav a, .mobile-nav button { display: flex; justify-content: space-between; align-items: center; min-height: 56px; padding: 0 var(--gutter); font-size: 18px; font-weight: 600; color: var(--c-white); border-bottom: 1px solid var(--navy-700); background: none; border-inline: 0; border-top: 0; width: 100%; text-align: left; }
.mobile-nav__sub { background: var(--navy-950); }
.mobile-nav__sub a { font-size: 16px; font-weight: 400; min-height: 52px; color: var(--navy-100); }
.mobile-nav__actions { display: grid; gap: var(--sp-3); padding: var(--sp-6) var(--gutter) 0; }

/* ---------- Cards ---------- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-card); padding: var(--sp-8); box-shadow: var(--shadow-sm); }
.card--tint { background: var(--bg-tint); box-shadow: none; }
.card--outline { background: transparent; border: 1.5px solid var(--action); box-shadow: none; }
/* Only cards that are entirely one link get the lift. */
a.card, .card--link { display: block; transition: transform 160ms var(--ease), box-shadow 160ms var(--ease); }
.card { transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--border-strong); }
/* Whole card is the click target, not just the link text. Every .card on the site carries
   exactly one link (checked across all pages: 7 cards, 1 link each), which is what makes a
   blanket overlay safe here. A second link in a card would sit under this one and become
   unreachable, so if one is ever added, give it position:relative and a z-index above 1. */
.card:has(a) { position: relative; cursor: pointer; }
.card a::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.card:focus-within { outline: 2px solid var(--action); outline-offset: 3px; }
.card a:focus-visible { outline: none; }
a.card:hover, .card--link:hover { transform: translateY(-3px); box-shadow: var(--shadow-md); }
.card__meta { font-size: 12px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--navy-500); }
.on-navy .card { background: var(--surface-inverse); border-color: var(--border-inverse); color: var(--c-white); }
@media (max-width: 720px) { .card { padding: var(--sp-6); } }

/* Annotation card on the product shot: offset outlined rectangle behind. */
.annotation { position: relative; }
.annotation::before { content: ""; position: absolute; inset: 10px -10px -10px 10px; border: 1.5px solid var(--border-strong); border-radius: 10px; }
.annotation > * { position: relative; }

/* ---------- Credibility band ---------- */
/* This band is a dark ground but it is not .on-navy, so it never inherited the
   token remap that block does. A link dropped into it kept --action, which is
   2.12:1 on navy-950. Remapping here rather than adding .on-navy to the markup,
   because the two grounds are different colours on purpose. */
.credibility { background: var(--navy-950); color: var(--c-white); padding: var(--section-y) var(--gutter);
  --text: var(--c-white);
  --text-muted: var(--navy-200);
  --action: var(--c-white);
  --action-hover: var(--navy-100);
  --border: var(--navy-600);
  --border-strong: var(--navy-400);
  --cyan-ink: var(--cyan); }
.credibility__figure { font-family: var(--font-display); font-weight: 900; font-size: var(--fs-display-xl); line-height: 1; letter-spacing: -0.04em; }
.sector-list { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.sector-list > * { border: 1px solid var(--navy-600); color: var(--navy-100); font-weight: 600; padding: 9px 16px; border-radius: var(--r-button); }

/* ---------- Offer band (never a popup) ---------- */
.offer-band { background: var(--c-ink); color: var(--c-white); padding: 22px var(--gutter); display: flex; align-items: center; justify-content: space-between; gap: var(--sp-6); flex-wrap: wrap; }
.offer-band__tag { border: 1.5px solid var(--red-500); color: var(--red-300); font-family: var(--font-display); font-weight: 800; font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase; padding: 7px 12px; border-radius: 5px; }

/* ---------- Forms ---------- */
.field { display: grid; gap: var(--sp-2); }
.field > label { font-weight: 600; font-size: 16px; }
.field .hint { font-size: var(--fs-small); line-height: 1.55; color: var(--text-muted); }
.input, .select, .textarea {
  width: 100%; font-family: var(--font-body); font-size: 17px; color: var(--text);
  background: var(--surface); padding: 15px 14px; min-height: 54px;
  border: 1.5px solid var(--border-control); border-radius: var(--r-input);
}
.input::placeholder, .textarea::placeholder { color: var(--placeholder); }
.input:focus, .select:focus, .textarea:focus { outline: none; border-color: var(--action); box-shadow: 0 0 0 3px rgba(27, 53, 87, 0.18); }
.textarea { resize: vertical; min-height: 96px; }
.field[data-invalid="true"] .input { border-color: var(--error); background: var(--red-50); }
.field-error { display: flex; gap: var(--sp-2); font-size: var(--fs-small); font-weight: 600; color: var(--error); }

/* Segmented control: beats a dropdown for 5–6 thumb-sized options. */
.segmented { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.segmented input { position: absolute; opacity: 0; width: 0; height: 0; }
.segmented label { border: 1.5px solid var(--border-control); border-radius: var(--r-input); padding: 13px 20px; min-height: 48px; display: inline-flex; align-items: center; font-weight: 600; cursor: pointer; }
.segmented input:checked + label { background: var(--action); border-color: var(--action); color: var(--action-text); font-weight: 700; }
.segmented input:focus-visible + label { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--focus-ring); }

.filedrop { border: 1.5px dashed var(--border-control); background: var(--bg-tint); border-radius: var(--r-input); padding: 24px; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.filedrop[data-filled="true"] { border-style: solid; border-color: var(--action); background: var(--surface); }

/* ---------- Footer ---------- */
.footer { background: var(--c-ink); color: var(--c-white); }
.footer__cols { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: var(--sp-12); padding: var(--sp-16) var(--gutter) var(--sp-12); }
.footer__heading { font-size: 12px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; color: var(--navy-300); }
.footer__links { display: grid; gap: var(--sp-3); margin-top: var(--sp-4); }
.footer__links a { color: var(--navy-100); }
.footer__bar { border-top: 1px solid var(--navy-700); padding: var(--sp-5, 20px) var(--gutter); display: flex; justify-content: space-between; gap: var(--sp-6); flex-wrap: wrap; font-size: var(--fs-small); color: var(--navy-300); }
@media (max-width: 900px) { .footer__cols { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px) { .footer__cols { grid-template-columns: 1fr; } }

/* ---------- Motion ---------- */
/* transform and opacity only. Nothing fires on load; the LCP headline never animates. */
[data-reveal] { opacity: 0.92; transform: translateY(8px); transition: opacity var(--dur-card) var(--ease), transform var(--dur-card) var(--ease); }
[data-reveal].is-in { opacity: 1; transform: none; }
[data-reveal]:nth-child(2) { transition-delay: var(--stagger); }
[data-reveal]:nth-child(3) { transition-delay: calc(var(--stagger) * 2); }
[data-reveal]:nth-child(4) { transition-delay: calc(var(--stagger) * 3); }
[data-reveal]:nth-child(5) { transition-delay: calc(var(--stagger) * 4); }
[data-reveal]:nth-child(6) { transition-delay: calc(var(--stagger) * 5); }

@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
  .btn:hover, a.card:hover, .card--link:hover { transform: none; }
  * { scroll-behavior: auto; }
}

/* ---------- One-colour print ---------- */
@media print {
  .header { position: static; }
  .section--navy, .credibility, .footer, .offer-band, .on-navy { background: #FFFFFF !important; color: #000000 !important; }
  .on-navy *, .credibility *, .footer * { color: #000000 !important; border-color: #000000 !important; }
  .btn--primary { background: #FFFFFF !important; color: #000000 !important; border: 1.5px solid #000000 !important; }
  [data-reveal] { opacity: 1 !important; transform: none !important; }
}

/* ---- Home page composition ---- */
.hero { padding: var(--sp-16) var(--gutter) var(--sp-16); max-width: 1180px; margin: 0 auto; }
.hero__tagline { font-size: var(--fs-eyebrow); letter-spacing: var(--tr-eyebrow); text-transform: uppercase; margin: 0 0 var(--sp-4); }
.hero .display { max-width: 15ch; }
.hero .lead { margin: var(--sp-6) 0 0; max-width: 58ch; }
.hero__actions { display: flex; gap: var(--sp-4); flex-wrap: wrap; margin: var(--sp-8) 0 0; }
/* The content has a <br> between the two buttons. In a flex row that is not a line break, it is a
   flex ITEM: 20px tall, 0 wide, sitting between them. On a phone, where the buttons stack, it turned
   a 16px gap into 52px and read as two unrelated buttons rather than a pair. */
.hero__actions br, .page-hero__actions br, .hero__photo br { display: none; }
.trust-row { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--sp-8); margin-top: var(--sp-16);
  padding-top: var(--sp-8); border-top: 1px solid var(--border); }
.trust { font-size: var(--fs-small); line-height: 1.6; color: var(--text-muted); }
.trust strong { color: var(--text); }

.stat-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-12); max-width: 1180px; margin: 0 auto; }
.stat__label { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h4); margin-top: var(--sp-2); }
.stat__blurb { color: var(--navy-200); font-size: var(--fs-small); margin: var(--sp-3) 0 0; }
.credibility .sectors { max-width: 1180px; margin: var(--sp-16) auto 0; padding-top: var(--sp-8); border-top: 1px solid var(--navy-600); }
.credibility .eyebrow { color: var(--navy-200); }
.sector-list { list-style: none; padding: 0; margin: var(--sp-4) 0 0; display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-8);
  font-family: var(--font-display); font-weight: 600; }

.section { padding: var(--section-y) var(--gutter); }
/* .eyebrow is a span, and an inline box ignores max-width and auto margins, so the
   label stayed on the gutter while the heading centred in the 1180px column. Above
   1180px + gutters that read as the label falling off the left of the layout. */
.section > .eyebrow { display: block; }
.section > .eyebrow, .section > h2, .section > .lead, .section > p { max-width: 1180px; margin-left: auto; margin-right: auto; }
.section > h2 { margin-top: var(--sp-3); }
.section > .lead { margin-top: var(--sp-4); }
.section .grid { max-width: 1180px; margin: var(--sp-12) auto 0; }
.section .grid + p { margin-top: var(--sp-12); }
.measure { max-width: var(--measure); }
.card__link { font-weight: 700; }

.split { display: grid; grid-template-columns: 1fr 1.15fr; gap: var(--sp-16); align-items: center; max-width: 1180px; margin: 0 auto; }
.split__media img { width: 100%; height: auto;
  filter: drop-shadow(0 18px 28px rgba(7, 47, 82, .18)); }
.ticks { list-style: none; padding: 0; margin: var(--sp-6) 0 0; display: grid; gap: var(--sp-4); }
.ticks li { padding-left: 26px; position: relative; }
.ticks li::before { content: ""; position: absolute; left: 0; top: 9px; width: 12px; height: 12px;
  border-left: 2.5px solid var(--action); border-bottom: 2.5px solid var(--action); transform: rotate(-45deg); }
.closing-cta { text-align: center; }
.closing-cta .lead, .closing-cta h2 { margin-left: auto; margin-right: auto; }
.closing-cta .hero__actions { justify-content: center; }

@media (max-width: 900px) {
  .trust-row, .stat-grid { grid-template-columns: 1fr; gap: var(--sp-8); }
  .split { grid-template-columns: 1fr; gap: var(--sp-8); }
  /* 64px above the heading and 64px below the photo is desktop breathing room on a screen
     that has none to spare: on a 390px phone it pushed the first line of the headline 64px
     below the header and left 96px of nothing between the handset and the reviews. Halved
     above. Below, 24px of hero padding plus a 32px trust-row margin overshot and left the
     handset 4px off the rule, so both come back up a step: measured, the handset now sits
     about 30px clear of the divider, with the trust row's own 32px of padding under it. */
  .hero { padding-top: var(--sp-8); padding-bottom: var(--sp-8); }
  .hero .display { max-width: none; }
  .trust-row { margin-top: var(--sp-12); }
}

/* ---- Motion. transform and opacity only, never layout. ---- */
.js-motion .reveal-group > * { opacity: 0; transform: translateY(22px);
  /* box-shadow and border-color are named here on purpose. Without them this
     rule replaces .card's own transition list and the hover shadow snaps. */
  transition: opacity var(--dur-card) var(--ease), transform var(--dur-card) var(--ease),
              box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease); }
.js-motion .reveal-group.is-in > * { opacity: 1; transform: none; }

/* The reveal rule above is 0,3,0 and lands `transform: none`, which outranked
   `.card:hover` at 0,2,0: cards inside a revealed group changed shadow on hover
   and never lifted, while a card outside one did. Restated here at 0,4,0 so the
   lift survives the reveal. */
.js-motion .reveal-group.is-in > .card:hover,
.js-motion .reveal-group.is-in > a.card:hover,
.js-motion .reveal-group.is-in > .card--link:hover { transform: translateY(-4px); }
.reveal-group.is-in > *:nth-child(2) { transition-delay: var(--stagger); }
.reveal-group.is-in > *:nth-child(3) { transition-delay: calc(var(--stagger) * 2); }
.reveal-group.is-in > *:nth-child(4) { transition-delay: calc(var(--stagger) * 3); }

@media (prefers-reduced-motion: reduce) {
  .js-motion .reveal-group > * { opacity: 1; transform: none; transition: none; }
}

/* ---- Front page runs full width; aw-base caps .aw-entry at the reading measure ---- */
.home .aw-entry--front { max-width: none; padding: 0; }
.home .aw-entry--front > .hero,
.home .aw-entry--front > .section { width: 100%; }
.credibility { margin-inline: 0; }

/* ---- Site header ---- */
.site-header__inner { flex-wrap: nowrap; }
.site-header { position: sticky; top: 0; z-index: 60; background: var(--c-white);
  border-bottom: 1px solid var(--border); transition: padding var(--dur) var(--ease); }
.site-header__inner { display: flex; align-items: center; gap: 16px;
  max-width: 1180px; margin: 0 auto; padding: 5px var(--gutter); }
/* 10px, not 4px. Two requests pull against each other here: make the bar shorter on scroll, and
   do not let it look cramped. At 4px the nav had 19px of air above it against 42px at rest, which
   reads as the header losing its padding even though the padding barely changed. The height is
   still well down from 119px at rest, which was the point. One number if it wants tuning again. */
.site-header.is-condensed .site-header__inner { padding-block: 10px; }
.site-header.is-condensed { box-shadow: 0 2px 14px rgba(14,21,32,.10); }

/* A slot, not a logo. Fixed height, width floats, so a 3:1 wide mark and a
   1:1 square mark both sit correctly without touching this file. */
.logo-slot { display: inline-flex; align-items: center; flex: 0 0 auto;
  height: var(--logo-slot-h); margin-right: 8px; }
.site-header.is-condensed .logo-slot { height: var(--logo-slot-h-condensed); }
.logo-slot__img, .logo-slot img { height: 100%; width: auto; max-width: 260px; object-fit: contain; display: block; }
.logo-slot--footer { height: 44px; margin: 0 0 var(--sp-4); }
.logo-slot--footer .logo-slot__img { max-width: 220px; }

.site-nav { margin-left: auto; }
/* Gap is 24px, the same air it had before, and it survives with the phone number showing because
   Home came out of the menu. Measured on the deployed header at 1440px by reading .site-nav's own
   auto margin, which is the actual free space: 24px leaves +21px, 26px leaves +13px and 28px only
   +5px. Do not read free space off scrollWidth. .site-nav's scrollWidth includes the absolutely
   positioned dropdowns at min-width 232px and over-reads the row by 86px, which on 13 September
   led to the logo and the phone number both being shrunk for no reason.

   flex-wrap:nowrap is load-bearing, not tidiness. white-space:nowrap below only stops text
   breaking *inside* an item; without flex-wrap the list silently drops items onto a second row
   and the header grows a floor. That shipped: from 1321px up, where the phone number reappears,
   Contact sat under Home on every desktop monitor. It reads as fine when you resize a window
   down, because narrowing hides the phone, so the bug is invisible to the person testing it. */
.site-nav .aw-primary-nav__list { display: flex; flex-wrap: nowrap; gap: 24px; list-style: none; margin: 0; padding: 0;
  font-family: var(--font-display); font-weight: 600; font-size: 15.5px; white-space: nowrap; }
.site-nav a { color: var(--text); }
.site-nav a:hover { color: var(--action); }
.site-header__actions { display: flex; align-items: center; gap: var(--sp-4); flex: 0 0 auto; }

/* The phone number is out of the header row at every width, not just narrow ones.
   Measured at 1440px: the row needs 1200px and the 1180px container gives 1052px of content
   box, so it is 148px short and the number itself is 147px of that. The old rule hid it below
   1320px, which meant it only ever appeared at the widths where it could not fit. It has no
   home yet; the announcement bar is dismissible so it is the wrong place. Until it gets one,
   the number lives in the footer and on the contact page. */
.site-header__actions .header__phone { display: none; }

/* Above 1280px the header runs wider than the 1180px body column so the phone number can come
   back. It cannot fit otherwise: even with Home removed from the menu, a 1180px container is
   short at every nav gap. The trade is that the logo sits about 50px left of the body text
   below it. That is a deliberate choice, made 13 September 2026, taken because a phone systems
   company having its number visible beats the logo lining up with the first paragraph.

   The 1280px floor is not arbitrary. Content box is container minus 128px of gutter, the row
   needs 1127px at a 30px nav gap, so the container has to reach 1275px before the number fits.
   Below that the number hides again and the nav has room to spare. */
/* The number comes back once the container reaches its full 1180px. Below that it hides again
   and the nav has room to spare. */
@media (min-width: 1180px) {
  .site-header__actions .header__phone { display: inline-block; }
}
@media (max-width: 900px) {
  .site-nav { margin-left: 0; }
  .site-header__inner { flex-wrap: wrap; gap: var(--sp-4); }
}

/* ---- Site footer ---- */
.site-footer { padding: var(--sp-12) var(--gutter) 0; }
.site-footer__inner { display: grid; grid-template-columns: 1.2fr 2fr; gap: var(--sp-16);
  max-width: 1180px; margin: 0 auto; padding-bottom: var(--sp-16); }
.site-footer__meta, .site-footer__contact { font-size: var(--fs-small); line-height: 1.8; color: var(--text-muted); margin: 0 0 var(--sp-4); }
.site-footer__contact a { color: var(--c-white); }
.site-footer__links { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--sp-3) var(--sp-8); font-size: var(--fs-small); }
.site-footer__bar { max-width: 1180px; margin: 0 auto; padding: var(--sp-6) 0 var(--sp-8);
  border-top: 1px solid var(--border); display: flex; justify-content: space-between; gap: var(--sp-4);
  flex-wrap: wrap; font-size: var(--fs-small); color: var(--text-muted); }
.site-footer__bar p { margin: 0; }
.site-footer__legal { display: block; margin-top: var(--sp-2); font-size: 0.8125rem; opacity: 0.62; max-width: 64ch; }
.site-footer__aw { opacity: 0.62; }
.site-footer__aw a { color: inherit; }
.site-footer__aw a:hover { color: var(--c-white); }

@media (max-width: 820px) {
  .site-footer__inner { grid-template-columns: 1fr; gap: var(--sp-8); }
}

/* ---- Primary nav dropdowns ---- */
.site-nav .aw-primary-nav__list > li { position: relative; }
/* display and gap are reset deliberately. aw-base sets `.aw-primary-nav ul` to
   a wrapping flex ROW with a 32px gap, which is right for the top-level list and
   catches every .sub-menu underneath it too, so the dropdown opened as a
   two-column grid with 32px between rows: Avaya and Samsung side by side, then
   Panasonic, Service request and Other services stranded below. */
.site-nav .aw-primary-nav__list .sub-menu {
  display: block; flex-wrap: nowrap; gap: 0;
  position: absolute; top: 100%; left: -14px; min-width: 232px; margin: 0; padding: var(--sp-2) 0;
  list-style: none; background: var(--c-white); border: 1px solid var(--border);
  border-radius: var(--r-card); box-shadow: var(--shadow-md);
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity var(--dur-menu) var(--ease), transform var(--dur-menu) var(--ease), visibility var(--dur-menu);
  z-index: 70;
}
.site-nav li:hover > .sub-menu,
.site-nav li:focus-within > .sub-menu { opacity: 1; visibility: visible; transform: none; }
.site-nav .sub-menu a { display: block; padding: 9px 18px; font-weight: 500; white-space: nowrap; }
.site-nav .sub-menu a:hover { background: var(--bg-tint); }
.site-nav .menu-item-has-children > a::after {
  content: ""; display: inline-block; width: 6px; height: 6px; margin-left: 7px; vertical-align: 2px;
  border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg);
}
/* ---- Mobile navigation ----
   aw-base's nav.js toggles `is-open` on the menu UL and flips aria-expanded on
   the button. The child has to honour that or the menu renders permanently open,
   with every submenu expanded, which is what happened. ---- */
@media (max-width: 1120px) {
  .aw-nav-toggle { display: inline-flex !important; align-items: center; justify-content: center;
    order: 3; margin-left: auto; width: 44px; height: 44px; background: none; border: 0;
    cursor: pointer; color: var(--text); }

  .site-header__inner { flex-wrap: wrap; row-gap: 0; }
  .site-nav { order: 4; flex: 1 0 100%; margin: 0; }

  /* The open menu is a panel in its own right, not an inline list. Inline, it ran
     109px past the viewport on a phone and the wheel scrolled the page behind it
     instead of the menu, so the last items were unreachable. */
  .site-nav .aw-primary-nav__list {
    /* nowrap matters: with a capped height, a wrapping column flex container
       spills the remaining items into a second column off the right edge. */
    display: none; flex-direction: column; flex-wrap: nowrap; gap: 0; margin: 0;
    padding: 0 var(--gutter) var(--sp-8);
    position: fixed; left: 0; right: 0; top: var(--header-h, 104px);
    /* height, not max-height: the panel fills the rest of the screen so the white
       ground covers the page behind it instead of leaving a strip of content
       showing under a short menu. */
    height: calc(100dvh - var(--header-h, 104px));
    overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch;
    background: var(--c-white); border-top: 1px solid var(--border);
    box-shadow: 0 16px 30px rgba(14,21,32,.10); z-index: 55; }
  .site-nav .aw-primary-nav__list.is-open { display: flex; }

  .site-nav .aw-primary-nav__list > li { width: 100%; }
  .site-nav .aw-primary-nav__list > li > a { display: flex; width: 100%; padding: 14px 0;
    min-height: 50px; font-size: 17px; border-bottom: 1px solid var(--border); }

  /* A parent with children shares its row with the toggle button: the link stays
     tappable across most of the row, the button is a separate 44px target at the
     end. The border that used to sit on the link moves to the row so it still
     spans full width once the link is no longer 100% wide. */
  .site-nav .aw-primary-nav__list > li.menu-item-has-children {
    display: flex; align-items: center; flex-wrap: wrap; border-bottom: 1px solid var(--border); }
  .site-nav .aw-primary-nav__list > li.menu-item-has-children > a {
    width: auto; flex: 1 1 auto; border-bottom: 0; }
  /* The li is a flex row so the link and the toggle sit side by side. Without this
     the sub-menu becomes a third column beside them: the children floated to the
     right of the parent with a column of dead space next to it. */
  .site-nav .aw-primary-nav__list > li.menu-item-has-children > .sub-menu {
    flex: 0 0 100%; width: 100%; }

  /* Children are indented under their parent with a rule, not a filled block.
     A tinted panel behind them read as a stray background. */
  .site-nav .aw-primary-nav__list .sub-menu {
    position: static; opacity: 1; visibility: visible; transform: none; box-shadow: none;
    border: 0; border-left: 2px solid var(--border-strong); border-radius: 0;
    background: transparent; padding: var(--sp-2) 0 var(--sp-3); margin: 0 0 0 var(--sp-2);
    min-width: 0; width: auto; display: block; }
  /* Collapsed by default only once the toggle script has actually run (the
     `.has-toggles` class it adds). Without it there is no button to reopen a
     hidden submenu, so every link must stay visible as a fallback. */
  .site-nav .aw-primary-nav__list.has-toggles .sub-menu { display: none; }
  .site-nav .aw-primary-nav__list.has-toggles > li.is-open > .sub-menu { display: block; }
  .site-nav .sub-menu li { width: 100%; }
  .site-nav .sub-menu a { display: flex; align-items: center; min-height: 46px;
    padding: 8px 0 8px var(--sp-4); font-size: 16px; white-space: normal;
    color: var(--text-muted); }
  .site-nav .sub-menu a:hover { color: var(--action); }
  /* The decorative chevron painted on the link is replaced by the real button's
     own chevron, so it would otherwise double up. */
  .site-nav .aw-primary-nav__list.has-toggles .menu-item-has-children > a::after { display: none; }

  /* The toggle button itself: full 44px tap target, transparent, chevron drawn
     with the same rotated-square technique as the decorative one it replaces,
     flipping to point up when the script sets aria-expanded="true". */
  .site-nav .aw-primary-nav__list .submenu-toggle {
    display: flex; align-items: center; justify-content: center; flex: 0 0 auto;
    width: 44px; height: 44px; margin-left: auto; padding: 0;
    background: none; border: 0; cursor: pointer; color: inherit; }
  .site-nav .aw-primary-nav__list .submenu-toggle::after {
    content: ""; display: inline-block; width: 8px; height: 8px;
    border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(45deg); transition: transform var(--dur-fast) var(--ease); }
  .site-nav .aw-primary-nav__list .submenu-toggle[aria-expanded="true"]::after {
    transform: rotate(-135deg); }
  .site-nav .aw-primary-nav__list .submenu-toggle:focus-visible {
    outline: none; box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--focus-ring);
    border-radius: var(--r-button); }

  /* One right-hand cluster. The logo's margin-right plus the toggle's
     margin-left:auto left the CTA floating between two gaps, reading as a
     third, unrelated element rather than part of the controls. */
  .logo-slot { margin-right: 0; }
  .site-header__actions { order: 2; margin-left: auto; }
  .aw-nav-toggle { margin-left: 0; }
  .site-header__inner { gap: var(--sp-3); }
  .site-header__actions .btn { padding: 10px 16px; min-height: 44px; }
}
@media (min-width: 1121px) { .aw-nav-toggle { display: none !important; } }

/* The sticky Call/Directions bar (.aw-contact-bar) only appears at <=782px, and
   is fixed to the viewport bottom there. Below that width the open mobile menu
   panel needs to stop clear of it, or its last item(s) sit underneath and can
   never be reached. 57px = the bar's own 56px min-height plus its 1px top
   border (measured in the browser); the safe-area term covers the iOS home-
   indicator inset on top of that. */
@media (max-width: 782px) {
  .site-nav .aw-primary-nav__list {
    height: calc(100dvh - var(--header-h, 104px));
    padding-bottom: calc(var(--sp-8) + 57px + env(safe-area-inset-bottom, 0px));
  }
}

/* ---- Inner page chrome ---- */
.page-entry { max-width: none; padding: 0; }
.page-hero { max-width: 1180px; margin: 0 auto; padding: var(--sp-16) var(--gutter) var(--sp-12); }
.crumbs { font-size: var(--fs-small); color: var(--text-muted); display: flex; gap: var(--sp-2);
  flex-wrap: wrap; align-items: center; margin-bottom: var(--sp-6); }
.crumbs a { color: var(--text-muted); }
.crumbs a:hover { color: var(--action); }
.crumbs [aria-current] { color: var(--text); font-weight: 600; }
.page-hero__title { max-width: 20ch; }
.page-hero__lead { margin-top: var(--sp-4); max-width: 62ch; }
.page-hero__actions { display: flex; gap: var(--sp-4); flex-wrap: wrap; margin-top: var(--sp-8); }
/* No container and no left stripe. A tinted panel with a 3px accent border down
   its left edge is the single most recognisable AI-build component and it was on
   the hero of every inner page. Space and weight carry it instead. */
.page-hero__badge { margin-top: var(--sp-8); font-size: var(--fs-small); color: var(--text-muted); }
.page-hero__badge strong { color: var(--action); font-family: var(--font-display);
  font-weight: 800; letter-spacing: .01em; }

/* Prose children are centred INSIDE a wide wrapper, rather than the wrapper
   being narrowed. Narrowing the wrapper fixed the dead space down the right but
   took the card grid with it, leaving two 300px cards with the titles wrapping
   mid-name. Wide blocks opt out below. */
.page-body { max-width: 1180px; margin: 0 auto; padding: 0 var(--gutter) var(--section-y); }
.page-body > * { max-width: var(--measure); margin-inline: auto; }
/* The 24ch cap keeps a headline to a couple of short lines and stays. What had to change is where
   the narrower box sits. Every child here is centred independently, so a heading at 24ch and a
   paragraph at 68ch end up with different left edges and the heading floats 41px inside the text
   it introduces. Measured on /about/ at 1440px: paragraphs at x=356, every h2 at x=397.
   So the heading keeps its own width and takes the reading column's left margin rather than its
   own. max() keeps it at 0 once the viewport is narrower than the measure.
   Do not "fix" this by moving the measure onto .page-body and letting children fill it. That was
   tried on 14 September and it works for the text, but the blocks that deliberately break out of
   the column then need 100vw to get their width back, and 100vw includes the scrollbar, which put
   a horizontal scrollbar on nine pages. */
.page-body > h2 {
  max-width: 24ch; margin-top: var(--sp-16);
  margin-left: max(0px, calc((100% - var(--measure)) / 2)); margin-right: auto;
  /* --measure is in rem so this resolves the same here as it does on the paragraphs. */
}
.page-body > h3 { margin-top: var(--sp-12); }
.page-body > p, .page-body > ul, .page-body > ol { margin-top: var(--sp-4); }
.page-body > .wp-block-columns, .page-body > figure, .page-body > .wp-block-image,
.page-body > .wp-block-aw-project-grid, .page-body > .wp-block-aw-cta-banner { max-width: none; }
.page-body img { max-width: 100%; height: auto; border-radius: var(--r-card); }
/* Photographs dropped into a page body. These are real site photos rather than product shots,
   so they get the page's card radius and room to breathe, and they break out of the reading
   column the same way figures already do. */
/* Aligned to the reading column. This was 1052px, the full content width, which
   read as an escape rather than a figure; then 880, which was a number picked to
   sit between two others and was still too much for a product shot. The measure
   is not arbitrary: the photo lines up with the paragraph above it, and a wide
   16:9 frame stops being a band across the page. */
/* Every image block in a page body, not just the ones we placed. A core image
   block carries width and height from the file and figure.wp-block-image has no
   max-width of its own, so a 899px render sat 171px wider than the column it was
   in and started further left than every paragraph on the page. */
.page-body .wp-block-image { max-width: var(--measure); margin-inline: auto; }
.page-body .wp-block-image img { width: 100%; height: auto; }
/* A cut-out product render is not a photograph. It has no background doing work,
   so filling the reading column just makes the handset large; narrower reads as a
   figure sitting beside the text about it. */
.page-body .wp-block-image.product-shot { max-width: 440px; }
/* A near-square or upright photo at full column width becomes a tall block that
   pushes the rest of the page down. Half the measure on desktop, full width on a
   phone where there is no column to be half of. */
.page-body .aw-photo--tall { max-width: calc(var(--measure) / 2); }
@media (max-width: 700px) {
  .page-body .aw-photo--tall { max-width: 100%; }
}
.page-body > .aw-photo { margin-block: var(--sp-12); }
.page-body > .aw-photo img { width: 100%; height: auto; display: block; }
.page-body > .aw-photo figcaption { margin-top: var(--sp-3); }
.page-body figcaption { font-size: var(--fs-small); color: var(--text-muted); margin-top: var(--sp-2); }
.page-body ul, .page-body ol { padding-left: 1.25em; }
.page-body li + li { margin-top: var(--sp-2); }
.page-body table { width: 100%; border-collapse: collapse; margin-top: var(--sp-6); }
.page-body th, .page-body td { text-align: left; padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border); }
.page-body th { font-family: var(--font-display); font-weight: 700; }

/* ---- On this page ---- */
/* Matched to the prose column, not the 1180 wrapper. Spanning the full width
   while the text under it sat at --measure made the page look like a mistake
   rather than a decision: a narrow column with a wide box parked above it. */
.toc { max-width: calc(var(--measure) + var(--gutter) * 2); margin: 0 auto var(--sp-8);
  padding: 0 var(--gutter); }
.toc__inner { border: 1px solid var(--border); border-radius: var(--r-card); padding: var(--sp-4) var(--sp-6);
  background: var(--bg-tint); }
.toc__label { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: var(--tr-eyebrow);
  text-transform: uppercase; color: var(--text-muted); }
.toc__list { list-style: none; margin: var(--sp-3) 0 0; padding: 0; display: flex; flex-wrap: wrap;
  gap: var(--sp-2) var(--sp-6); font-size: var(--fs-small); font-weight: 600; }

/* ---- aw-forms, wired to the design system ----
   The plugin ships its own class names, so map them rather than asking the
   client to hand-write markup. Control edges use --border-control, which is
   the 3:1 token, because a field border identifies the control (WCAG 1.4.11). */
.aw-form-wrap { max-width: 640px; }
.aw-form__field { display: grid; gap: var(--sp-2); margin-top: var(--sp-6); }
.aw-form__field > label { font-family: var(--font-display); font-weight: 700; font-size: 16px; }
.aw-form__required { color: var(--error); margin-left: 2px; }
.aw-form__hint { font-size: var(--fs-small); line-height: 1.55; color: var(--text-muted); margin: 0; }

.aw-form input[type="text"], .aw-form input[type="email"], .aw-form input[type="tel"],
.aw-form input[type="number"], .aw-form input[type="url"], .aw-form select, .aw-form textarea {
  width: 100%; font: inherit; font-size: 16px; color: var(--text); background: var(--surface);
  padding: 13px 14px; min-height: 48px;
  border: 1.5px solid var(--border-control); border-radius: var(--r-input);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
/* Specificity, not decoration. The inputs above are matched by
   `.aw-form input[type="text"]` at 0,2,0, which beats aw-forms' own
   `.aw-form__field input` in form.css. A bare `textarea` is only 0,1,1, ties
   with `.aw-form__field textarea`, and loses on source order, so the box came
   out with a 1px pale border and a 12px radius while every input beside it had
   1.5px navy and 4px. Matching the field class puts it back on equal footing. */
.aw-form .aw-form__field textarea,
.aw-form textarea {
  min-height: 128px; resize: vertical;
  border: 1.5px solid var(--border-control); border-radius: var(--r-input);
  padding: 13px 14px; background: var(--surface); color: var(--text);
  font: inherit; font-size: 16px; width: 100%;
}
.aw-form ::placeholder { color: var(--placeholder); opacity: 1; }
.aw-form :is(input, select, textarea):hover { border-color: var(--navy-500); }
.aw-form :is(input, select, textarea):focus-visible {
  outline: none; border-color: var(--action); box-shadow: 0 0 0 3px rgba(27, 53, 87, 0.18); }
.aw-form input[type="file"] { width: 100%; font: inherit; font-size: 15px; padding: 12px;
  border: 1.5px dashed var(--border-control); border-radius: var(--r-input); background: var(--bg-tint); }
.aw-form input[type="file"]::file-selector-button {
  font: inherit; font-weight: 700; margin-right: var(--sp-3); padding: 8px 14px; cursor: pointer;
  color: var(--action-text); background: var(--action); border: 0; border-radius: var(--r-button); }

.aw-form__actions { margin-top: var(--sp-8); }
.aw-form__submit { font-family: var(--font-display); font-weight: 700; font-size: 17px;
  padding: 15px 26px; min-height: 52px; cursor: pointer;
  color: var(--action-text); background: var(--action); border: 1.5px solid transparent;
  border-radius: var(--r-button); transition: background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease); }
.aw-form__submit:hover { background: var(--action-hover); transform: translateY(-1px); }
.aw-form__submit:active { background: var(--action-active); transform: none; }
.aw-form__hp { position: absolute; left: -9999px; }

/* WCAG 2.5.8 wants a 24px minimum target. Nav links are 17px of text, so the
   padding is what makes them tappable, not decoration. */
.site-nav .aw-primary-nav__list > li > a { display: inline-flex; align-items: center; min-height: 32px; padding-block: 4px; }
.site-footer__links a { display: inline-flex; align-items: center; min-height: 26px; }
.crumbs a, .crumbs span { display: inline-flex; align-items: center; min-height: 24px; }
.site-footer__contact a, .site-footer__aw a { display: inline-flex; align-items: center; min-height: 24px; }

/* The logo slot used to be set here as well, at 64px with a 200px width cap and a 50px
   condensed height. Every line of it was already overridden further down by the block that
   sets 72/88px and max-width:none, so it had no effect and only made the real value hard to
   find. Five rules were setting one property. Removed 13 September 2026; the live values are
   in the ".site-header { padding-block: 10px; }" block below. */

/* Stagger up to eight, so a four-up grid and a six-item list both read. */
.js-motion .reveal-group.is-in > *:nth-child(5) { transition-delay: calc(var(--stagger) * 4); }
.js-motion .reveal-group.is-in > *:nth-child(6) { transition-delay: calc(var(--stagger) * 5); }
.js-motion .reveal-group.is-in > *:nth-child(7) { transition-delay: calc(var(--stagger) * 6); }
.js-motion .reveal-group.is-in > *:nth-child(8) { transition-delay: calc(var(--stagger) * 7); }

/* ---- Cyan, decoration only. Never a label or a fill on white (3.58:1). ---- */
.credibility .rule { height:3px; width:64px; background: var(--cyan); border-radius:2px; margin-bottom: var(--sp-4); }
.credibility__figure .u { display:block; height:3px; width:52px; background: var(--cyan); margin-top:10px; border-radius:2px; }
.credibility .eyebrow { color: var(--cyan); }
/* The sector items are bordered pills, so a leading dot sits on the border and
   reads as a rendering fault. The pill is already the delineation. */
.sector-list li { position: relative; }
@media (max-width: 620px) { .sector-list { gap: var(--sp-3); } }
/* The pills now go to their section on /industries/. The whole pill is the
   target, not the words inside it, so the 24px minimum is met by the padding. */
.sector-list li { padding: 0; border: 0; }
.sector-list a { display: block; padding: 9px 16px; border: 1px solid var(--navy-600);
  border-radius: var(--r-button); color: var(--navy-100); font-weight: 600;
  text-decoration: none; transition: border-color var(--dur-fast) var(--ease),
  background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.sector-list a:hover { border-color: var(--cyan); background: rgba(40,189,239,.10); color: var(--c-white); }
.sector-list a:focus-visible { outline: 3px solid var(--cyan); outline-offset: 2px; }
.on-navy .card { border-color: var(--navy-600); }
.on-navy .card:hover { border-color: var(--cyan); }

/* Icon wash, from the inspiration board. Cyan at 14% behind a cyan stroke. */
.ic { width:38px; height:38px; border-radius:10px; background: rgba(40,189,239,.14);
  display:grid; place-items:center; margin-bottom: var(--sp-3); flex: 0 0 auto; }
.ic svg { width:19px; height:19px; stroke: var(--cyan-ink); fill:none; stroke-width:2;
  stroke-linecap:round; stroke-linejoin:round; }
.on-navy .ic svg { stroke: var(--cyan); }
.feature { display:flex; gap: var(--sp-4); align-items:flex-start; }
.feature h3 { font-size: var(--fs-h4); margin:0 0 4px; }
.feature p { margin:0; color: var(--text-muted); font-size: var(--fs-small); line-height:1.6; }

/* Trust row, with the Google rating */
.trust--rating { display:flex; gap: var(--sp-3); align-items:center; }
.g-badge { width:34px; height:34px; border-radius:50%; border:1.5px solid var(--border-strong);
  display:grid; place-items:center; font-family: var(--font-display); font-weight:800; font-size:15px;
  color: var(--action); flex:0 0 auto; }
.stars { color: var(--amber); letter-spacing:1px; font-size:13px; }

/* Hero photo slot */
.hero__grid { display:grid; grid-template-columns: 1.05fr .95fr; gap: var(--sp-16); align-items:center; }
.hero__grid > .hero__photo { align-self: center; }
.photo-slot { border:1.5px dashed var(--border-strong); border-radius: var(--r-panel);
  background: var(--bg-tint); min-height: 330px; display:grid; place-items:center; padding: var(--sp-8);
  text-align:center; color: var(--text-muted); font-size: var(--fs-small); line-height:1.6; }
.photo-slot strong { display:block; color: var(--text); font-family: var(--font-display); margin-bottom:4px; }
@media (max-width: 900px){ .hero__grid { grid-template-columns:1fr; gap: var(--sp-8);} .photo-slot{min-height:220px} }

/* Header condense, eased rather than snapped */
.site-header { transition: box-shadow var(--dur-reveal) var(--ease), background var(--dur-reveal) var(--ease); }
.site-header__inner { transition: padding-block var(--dur-reveal) var(--ease); }
.logo-slot { transition: height var(--dur-reveal) var(--ease); }
.logo-slot__img, .logo-slot img { transition: height var(--dur-reveal) var(--ease); }

/* ---- Promotion bar. Client-editable via AW Site > Announcement bar (edit_pages). ---- */
.aw-announce { background: var(--navy-900); color: var(--c-white); border: 0;
  font-family: var(--font-body); font-size: var(--fs-small); }
.aw-announce__inner { max-width: 1180px; margin: 0 auto; padding: 11px var(--gutter);
  display: flex; align-items: center; justify-content: center; gap: var(--sp-4); flex-wrap: wrap; }
/* aw-base renders the link as a pill with its own background, so the colour and
   the ground have to be set together. Setting only the colour makes it white on white. */
.aw-announce__link { background: var(--c-white); color: var(--navy-800);
  text-decoration: none; font-weight: 700; padding: 6px 13px; border-radius: 999px; }
.aw-announce__link:hover { background: var(--navy-100); color: var(--navy-900); }
/* A cyan marker rather than cyan text: it fails 4.5:1 as a label on navy at this size.
   It hangs off the message, not off __inner. As a flex item of a wrapping row it was a
   sibling of the text, so on a phone, where the message is long enough to wrap, the dot
   got pushed onto a line of its own and floated above the sentence. Inside the message's
   own line box it travels with the first word and cannot be orphaned. */
.aw-announce__message::before { content: ""; display: inline-block; width: 8px; height: 8px;
  border-radius: 50%; background: var(--cyan); margin-right: 10px; vertical-align: 1px; }
.aw-announce button, .aw-announce [class*="dismiss"] { color: var(--navy-200); }
.aw-announce button:hover, .aw-announce [class*="dismiss"]:hover { color: var(--c-white); }
@media (max-width: 640px) { .aw-announce__inner { text-align: center; } }

/* ---- Hero photograph ---- */
.hero__photo { margin: 0; padding: 0; background: none; box-shadow: none; }
.hero__photo img { display: block; width: 100%; height: auto;
  filter: drop-shadow(0 24px 34px rgba(7, 47, 82, .22)); }

/* Slide in from the side. transform and opacity only, so no layout moves and
   nothing is hidden until motion.js confirms it can animate. */
/* overflow-x: clip contains the travel WITHOUT creating a scroll container, and
   without clipping the vertical drop-shadow the way overflow:hidden would. */
.hero, .section { overflow-x: clip; }

/* Direction follows the column the image sits in, so each one leaves by its
   nearest edge. A fixed positive translate sent the left-column image the wrong
   way and it never actually cleared the viewport. `100% + 60px` is measured
   against the element's own width, so it is fully off screen at any breakpoint
   without hard-coding a distance. */
.js-motion .slide-in { opacity: 0; transform: translateX(calc(100% + 60px)) scale(.985);
  transition: opacity var(--dur-slide) var(--ease),
              transform var(--dur-slide) cubic-bezier(.16,.84,.32,1); }
.js-motion .split__media.slide-in { transform: translateX(calc(-100% - 60px)) scale(.985); }
.js-motion .slide-in.is-in { opacity: 1; transform: none; }
/* Small screens still rise rather than slide. A near-full-width image travelling
   in from the side reads as a glitch on a phone, and there is no room for the
   movement to be legible. */
@media (max-width: 720px) {
  .js-motion .slide-in { transform: translateY(30px) scale(.99); }
}
@media (prefers-reduced-motion: reduce) {
  .js-motion .slide-in { opacity: 1; transform: none; transition: none; }
}

/* ---- The core promise, type led ----
   No container, no stripe, no tinted panel. Scale carries it, and the cyan is a
   highlight painted behind the words rather than the text colour, so contrast is
   the text's own. See the visual tells note in the global build discipline. ---- */
.promise-led { margin-top: var(--sp-12); max-width: 640px; }
.promise-led__line { font-family: var(--font-display); font-weight: 900; font-size: 31px;
  line-height: 1.15; letter-spacing: -0.02em; margin: 0 0 var(--sp-2); text-wrap: balance; }
.promise-led__line em { font-style: normal;
  background: linear-gradient(transparent 62%, rgba(40,189,239,.42) 62%); padding: 0 2px; }
.promise-led__sub { margin: 0; font-size: var(--fs-body); line-height: 1.6; color: var(--text-muted); }
@media (max-width: 620px) { .promise-led__line { font-size: 25px; } }

/* Trust row, now three items with the rating linking out to the profile.
   Scoped to a min-width: written bare, this sat AFTER the max-width:900px
   stacking rule and beat it, so a phone got three 100px columns wrapping
   "A person / answers" two words to a line. */
@media (min-width: 901px) { .trust-row { grid-template-columns: repeat(2, 1fr); } }
a.trust--rating { text-decoration: none; color: inherit; border-radius: var(--r-card);
  padding: var(--sp-3); margin: calc(var(--sp-3) * -1);
  transition: background var(--dur-fast) var(--ease); }
a.trust--rating:hover { background: var(--bg-tint); }
a.trust--rating strong { color: var(--action); }
@media (max-width: 900px) {
  .trust-row { gap: var(--sp-6); }
  /* No horizontal padding on the hit area at this width. Padded, it was wider
     than its own grid column and hung 12px past the row whichever way the
     negative margin went. Vertical padding still gives it a comfortable target. */
  a.trust--rating { padding: var(--sp-3) 0; margin: calc(var(--sp-3) * -1) 0 0; }
}

/* ---- Page ground: a wash that fades out by the fold. No extra request. ---- */
body { background: #FFFFFF; }
body::before { content: ""; position: fixed; inset: 0 0 auto 0; height: 1100px; z-index: -1;
  background: linear-gradient(180deg, var(--navy-50) 0%, #F7FAFD 55%, #FFFFFF 100%);
  pointer-events: none; }
/* The header is NOT in this list. It is sticky, so a transparent ground lets page
   content scroll through it. It gets the wash's own top colour instead, which
   matches the ground at rest and stays opaque once scrolled. */
.aw-site-main, .hero, .page-hero { background: transparent; }
.site-header { background: #F7FAFD; }
.site-header.is-condensed { background: rgba(255, 255, 255, 0.92);
  -webkit-backdrop-filter: saturate(1.6) blur(10px); backdrop-filter: saturate(1.6) blur(10px); }
@supports not (backdrop-filter: blur(1px)) {
  .site-header.is-condensed { background: #FFFFFF; }
}

/* ---- Segmented control. Radios styled as a bar, so it stays keyboard and
   screen-reader native. Better than a select on a phone. ---- */
.segmented { position: relative; display: flex; flex-wrap: wrap; gap: 0;
  border: 1.5px solid var(--border-control); border-radius: var(--r-input); overflow: hidden;
  width: 100%; max-width: 100%; }
/* Properly visually hidden. `position:absolute; opacity:0` alone leaves the input
   at full width and it escapes the container, overflowing the page. */
.segmented input { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.segmented label { flex: 1 1 0; justify-content: center; text-align: center;
  font-family: var(--font-display); font-weight: 700; font-size: 15px;
  padding: 12px 18px; min-height: 48px; display: inline-flex; flex-direction: column;
  justify-content: center; cursor: pointer; background: var(--surface); color: var(--text);
  /* The bar owns the border and the radius. Segments carry a divider only, or the
     two sets of rounded corners nest and it reads as boxes inside a box. */
  border: 0; border-right: 1.5px solid var(--border-control); border-radius: 0;
  transition: background var(--dur-fast) var(--ease); }

/* Five bands do not fit on a phone. The joined control clips its overflow to keep
   the rounded corners, so a fifth option was being hidden rather than wrapped and
   the customer could not reach it. Below 560px the segments become separate pills
   that wrap, which is the same control without the seam. */
@media (max-width: 560px) {
  .segmented { flex-wrap: wrap; gap: var(--sp-3); border: none; overflow: visible;
    border-radius: 0; width: 100%; }
  .segmented label { border: 1.5px solid var(--border-control); border-radius: var(--r-input);
    flex: 1 1 auto; justify-content: center; }
  .segmented input:checked + label { border-color: var(--action); }
}
/* Only when the segments are joined into one control. Below 560px they wrap as
   separate pills and the last one needs all four borders like the rest. */
@media (min-width: 561px) { .segmented label:last-of-type { border-right: 0; } }
.segmented label small { display: block; font-family: var(--font-body); font-weight: 400;
  font-size: 12px; color: var(--text-muted); margin-top: 1px; }
.segmented label:hover { background: var(--bg-tint); }
.segmented input:checked + label { background: var(--action); color: var(--action-text); }
.segmented input:checked + label small { color: var(--navy-200); }
.segmented input:focus-visible + label { outline: 2px solid var(--focus-ring); outline-offset: -2px; }

/* ---- Feature rows. Icon, heading, one line. Two columns, not a three-up grid. ---- */
.features { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-8) var(--sp-12);
  max-width: 1180px; margin: var(--sp-12) auto 0; }
@media (max-width: 820px) { .features { grid-template-columns: 1fr; gap: var(--sp-6); } }

/* ---- Upload field, drag and drop ---- */
.dropzone { position: relative; border: 1.5px dashed var(--border-control); border-radius: var(--r-input);
  background: var(--bg-tint); padding: var(--sp-8); text-align: center;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease); }
.dropzone.is-over { background: var(--navy-100); border-color: var(--action); border-style: solid; }
.dropzone input[type="file"] { position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0; cursor: pointer; }
.dropzone__icon { width: 40px; height: 40px; margin: 0 auto var(--sp-3); border-radius: 10px;
  background: rgba(40,189,239,.14); display: grid; place-items: center; }
.dropzone__icon svg { width: 20px; height: 20px; stroke: var(--cyan-ink); fill: none; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round; }
.dropzone__main { font-family: var(--font-display); font-weight: 700; font-size: 16px; }
.dropzone__main u { text-underline-offset: 3px; }
.dropzone__hint { font-size: var(--fs-small); color: var(--text-muted); margin-top: 4px; }
.dropzone__file { display: none; margin-top: var(--sp-3); font-size: var(--fs-small); font-weight: 600;
  color: var(--action); }
.dropzone.has-file .dropzone__file { display: block; }

/* ---- Mobile contact bar. aw-base gives it a navy ground and 48px targets but
   no visible pressed or focus state, so a tap gives no feedback at all. ---- */
.aw-contact-bar { background: var(--navy-900); border-top: 1px solid var(--navy-600); }
.aw-contact-bar__link { position: relative; color: var(--c-white); font-family: var(--font-display);
  font-weight: 700; min-height: 56px; display: flex; align-items: center; justify-content: center;
  gap: var(--sp-2); text-decoration: none;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.aw-contact-bar__link + .aw-contact-bar__link { border-left: 1px solid var(--navy-600); }
.aw-contact-bar__link:hover { background: var(--navy-800); }
/* A press has to be visible on a touch screen, where there is no hover at all. */
.aw-contact-bar__link:active { background: var(--cyan-ink); color: var(--c-white); }
.aw-contact-bar__link:focus-visible { outline: 3px solid var(--cyan); outline-offset: -3px; }
/* The cyan marker doubles as the pressed affordance. */
.aw-contact-bar__link::after { content: ""; position: absolute; left: 18%; right: 18%; bottom: 0;
  height: 3px; background: var(--cyan); transform: scaleX(0); transform-origin: 50% 50%;
  transition: transform var(--dur-fast) var(--ease); }
.aw-contact-bar__link:hover::after, .aw-contact-bar__link:active::after,
.aw-contact-bar__link:focus-visible::after { transform: scaleX(1); }
/* On a touch screen there is no hover, but the browser still applies :hover on tap.
   Scoped with :not(:active) so it cannot cancel the pressed state, which it did. */
@media (hover: none) { .aw-contact-bar__link:hover:not(:active) { background: transparent; } }

/* The native number input still carries the value; it is hidden from sight only. */
.aw-form input.is-enhanced { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* aw-forms prints its own hint under the field, so the zone carries the only copy. */
.dropzone + .aw-form__hint, .aw-form__field:has(.dropzone) > .aw-form__hint { display: none; }
.dropzone.is-invalid { border-color: var(--error); background: var(--red-50); }
.dropzone.is-invalid .dropzone__file { color: var(--error); font-weight: 700; }

/* ---- Quote page: form on the left, supporting detail on the right ---- */
.quote-layout { display: grid; grid-template-columns: 1.5fr 1fr; gap: var(--sp-16);
  align-items: start; max-width: 1180px; margin: 0 auto; }
.quote-layout > * { max-width: none; }
.quote-layout__form h2 { margin: 0 0 var(--sp-3); }
.quote-layout__form > p { margin: 0 0 var(--sp-8); max-width: 58ch; }
.quote-layout__form .aw-form-wrap { max-width: none; }
.quote-layout__side { display: flex; flex-direction: column; gap: var(--sp-4); position: sticky; top: 130px; }
.side-card { background: var(--bg-tint); border: 1px solid var(--border);
  border-radius: var(--r-card); padding: var(--sp-6); }
.side-card h3 { font-size: var(--fs-h4); margin: 0 0 var(--sp-2); }
.side-card p { margin: 0 0 var(--sp-3); font-size: var(--fs-small); line-height: 1.6; }
.side-card p:last-child { margin-bottom: 0; }
.side-card__note { color: var(--text-muted); }
@media (max-width: 940px) {
  .quote-layout { grid-template-columns: 1fr; gap: var(--sp-12); }
  .quote-layout__side { position: static; }
}

/* Real tables, since the pricing pages carry one */
.page-body .wp-block-table { max-width: var(--measure); overflow-x: auto; }
.page-body .wp-block-table table { width: 100%; border-collapse: collapse; }
.page-body .wp-block-table th { text-align: left; font-family: var(--font-display); font-weight: 700;
  padding: var(--sp-3) var(--sp-4); border-bottom: 2px solid var(--text); }
.page-body .wp-block-table td { padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border); }
.page-body .wp-block-table tr:last-child td { border-bottom: 0; }
.page-body .wp-block-table td:last-child { font-family: var(--font-display); font-weight: 700; white-space: nowrap; }

/* Related links at the foot of a page. The old site had almost no internal
   linking and it was one of the findings the rebuild is sold against. */
.aw-related { max-width: var(--measure); margin-top: var(--sp-12); padding-top: var(--sp-6);
  border-top: 2px solid var(--text); }
.aw-related__label { font-family: var(--font-display); font-weight: 900; font-size: var(--fs-eyebrow);
  letter-spacing: var(--tr-eyebrow); text-transform: uppercase; color: var(--cyan-ink); }
.aw-related ul { list-style: none; padding: 0; margin: var(--sp-3) 0 0; display: flex;
  flex-wrap: wrap; gap: var(--sp-3) var(--sp-6); }
.aw-related a { font-weight: 600; }

/* Body scroll lock while the mobile menu is open.
   Two things have been tried here and only one works, so it is worth writing down.
   position:fixed on the body, offset by -scrollY, is the usual recipe and it is WRONG on this
   site: the header is position:sticky inside the body, and a fixed body takes the header
   off-screen with it, so the close button becomes unreachable.
   overflow:hidden holds the visual position correctly while the panel is open, but the browser
   drops the offset when the lock is released, which landed the reader at the top of the page and
   read as "opening the menu scrolls the page to the top". motion.js records the position on open
   and scrolls back to it on close. */
html.nav-open, html.nav-open body { overflow: hidden; touch-action: none; }
/* And the header has to be pinned for the duration, which is the part that is easy to miss.
   overflow:hidden on the root takes away the scroll context position:sticky needs, so the
   header drops to its static position: a thousand pixels up the document if the reader is
   partway down the page. Everything then follows it. motion.js publishes --header-h from the
   header's on-screen bottom, that goes negative, and the panel, which is position:fixed at
   top:var(--header-h), lands off-screen too. Open the menu halfway down the page and the
   header and the menu both disappeared. */
html.nav-open .site-header { position: fixed; top: 0; left: 0; right: 0; }

/* ---- The two optional routes to a sharper price, with an OR between them ----
   Side by side when the box itself is wide enough, stacked when it is not. A
   container query rather than a viewport one, because this block sits in a
   column whose width does not track the viewport. ---- */
.quote-layout__form, .aw-form-wrap { container-type: inline-size; }
.compare-box { border: 1.5px solid var(--border-strong); border-radius: var(--r-card);
  padding: var(--sp-6) var(--sp-6) var(--sp-8); margin: var(--sp-8) 0 0; min-width: 0; }
.compare-box__legend { font-family: var(--font-display); font-weight: 800; font-size: 15px;
  padding: 0 var(--sp-3); margin-left: calc(var(--sp-3) * -1); color: var(--text); }
.compare-box__intro { margin: 0 0 var(--sp-4); font-size: var(--fs-small);
  line-height: 1.6; color: var(--text-muted); }
.compare-box .aw-form__field:first-of-type { margin-top: 0; }
.compare-or { display: flex; align-items: center; gap: var(--sp-4); margin: var(--sp-6) 0 var(--sp-2); }
.compare-or::before, .compare-or::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.compare-or span { font-family: var(--font-display); font-weight: 900; font-size: 13px;
  letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-muted); }
.compare-box__questions { display: grid; gap: var(--sp-6); }
/* Match the rhythm of the fields outside the box. An empty hint element was
   adding 16px, so the gap here measured 40px against 24px everywhere else. */
 /* The fields are <p> elements, so they carry a paragraph margin on top of the
    grid gap. That measured 40px against 24px everywhere else. */
.compare-box__questions .aw-form__field { margin: 0; }
.compare-box .aw-form__field { margin-top: 0; }
.compare-box__questions .aw-form__hint:empty { display: none; }

@container (min-width: 560px) {
  .compare-box__body { display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--sp-6);
    align-items: start; }
  .compare-box__body > .aw-form__field { margin-top: 0; }
  .compare-or { flex-direction: column; margin: 0; align-self: stretch; gap: var(--sp-3); }
  .compare-or::before, .compare-or::after { width: 1px; height: auto; flex: 1; }
  .compare-box__questions .aw-form__field:first-child { margin-top: 0; }
  .compare-box .dropzone { padding: var(--sp-6) var(--sp-4); }
}
[id] { scroll-margin-top: calc(var(--header-h, 110px) + 24px); }
#aw-form { scroll-margin-top: calc(var(--header-h, 110px) + 16px); }
/* The sidebar phone link was 21px, under the 24px minimum target. */
.side-card a { display: inline-flex; align-items: center; min-height: 24px; }

/* ---- Case study grid ---- */
.aw-project-grid { max-width: 1180px; margin: var(--sp-12) auto 0; }
/* Three classes deep on purpose. aw-blocks prints
   `.aw-variant-grid-2 .aw-project-grid__items { grid-template-columns: repeat(2, 1fr) }`
   as an inline <style> in the head, so it wins on specificity (0,2,0) and on
   source order. A single-class rule here never applied at all, which is why the
   cards stayed two-up down to 390px and overflowed the viewport by 106px.
   `.page-body ul` also puts a 1.25em list indent on it. */
.page-body .wp-block-aw-project-grid .aw-project-grid__items {
  list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: 1fr; gap: var(--sp-8); max-width: none; }
/* Two up, not auto-fit. With four case studies auto-fit gave three across and a
   lone orphan on the second row; a fixed pair reads as a set. */
@media (min-width: 700px) {
  .page-body .wp-block-aw-project-grid .aw-project-grid__items {
    grid-template-columns: repeat(2, 1fr); }
}
.aw-project-grid__item { border: 1px solid var(--border); border-radius: var(--r-card);
  padding: var(--sp-8); background: var(--c-white);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease); }
.aw-project-grid__item:hover { border-color: var(--action);
  box-shadow: var(--shadow-md); transform: translateY(-3px); }
.aw-project-grid__link { display: block; }
/* WP core underlines a:where(:not(.wp-element-button)), which reaches the card
   link and its heading, so both need it off explicitly. */
.aw-project-grid__link, .aw-project-grid__link:hover,
.aw-project-grid__title { text-decoration: none; }
/* The whole card is the target. The stretched link sits above the card's own
   background but below the text, so the outcome copy stays selectable. */
.aw-project-grid__item { position: relative; }
.aw-project-grid__link::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
.aw-project-grid__title { font-family: var(--font-display); font-weight: 800;
  font-size: var(--fs-h3); margin: 0; color: var(--text); }
.aw-project-grid__item:hover .aw-project-grid__title { color: var(--action); }
.aw-project-grid__meta { margin: var(--sp-2) 0 0; font-size: var(--fs-eyebrow);
  letter-spacing: var(--tr-eyebrow); text-transform: uppercase; color: var(--action);
  font-family: var(--font-display); font-weight: 700; }
.aw-project-grid__outcome { margin: var(--sp-4) 0 0; color: var(--text-muted); line-height: 1.6; }
.aw-project-grid__item:focus-within { outline: 3px solid var(--cyan); outline-offset: 3px; }
/* The listing page is a grid, not prose, so it must not inherit the measure cap. */
.page-body > .wp-block-aw-project-grid { max-width: none; }
.case-entry .page-hero .eyebrow { display: block; margin-bottom: var(--sp-3); }
.case-entry__back { margin-top: var(--sp-12); padding-top: var(--sp-6);
  border-top: 1px solid var(--border); font-family: var(--font-display); font-weight: 700; }

/* ---- Page hero, matched to the body column ---- */
.page-hero { max-width: calc(var(--measure) + var(--gutter) * 2); }

/* ---- CTA banner ----
   The starter ships this unstyled here, so it rendered as a centred blue slab
   with a white pill in the middle: the generic component this project's notes
   specifically warn against. Left-aligned on the brand navy, heading and action
   side by side when there is room.

   Every selector below is doubled up deliberately. aw-blocks prints its block
   styles as an INLINE <style> in the head, which lands after this stylesheet,
   and its `.aw-block-cta-banner.aw-variant-full-width` rule is 0,2,0. A single
   class here loses on both specificity and source order, which is why the first
   attempt at this changed nothing that could be measured. */
.wp-block-aw-cta-banner.aw-block-cta-banner {
  max-width: none; margin: var(--sp-16) 0 0;
  background: var(--navy-900); color: var(--c-white); border-radius: var(--r-panel);
  padding: var(--sp-8); display: grid; gap: var(--sp-6);
  align-items: center; text-align: left; flex-direction: unset; }
.aw-block-cta-banner .aw-cta-banner__content { display: grid; gap: var(--sp-2); text-align: left; }
.aw-block-cta-banner .aw-cta-banner__heading { font-family: var(--font-display); font-weight: 900;
  font-size: var(--fs-h3); margin: 0; color: var(--c-white); max-width: 32ch; text-align: left; }
.aw-block-cta-banner .aw-cta-banner__body { margin: 0; color: var(--navy-200);
  line-height: 1.6; max-width: 64ch; text-align: left; }
.aw-block-cta-banner .aw-cta-banner__button { justify-self: start; display: inline-flex;
  align-items: center; min-height: 46px; padding: 12px 24px; border-radius: var(--r-button);
  background: var(--c-white); color: var(--navy-900); text-decoration: none;
  font-family: var(--font-display); font-weight: 700; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.aw-block-cta-banner .aw-cta-banner__button:hover { background: var(--cyan);
  color: var(--navy-950); text-decoration: none; }
.aw-block-cta-banner .aw-cta-banner__button:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; }
@media (min-width: 700px) {
  .wp-block-aw-cta-banner.aw-block-cta-banner { grid-template-columns: 1fr auto;
    gap: var(--sp-12); padding: var(--sp-12); }
  .aw-block-cta-banner .aw-cta-banner__button { justify-self: end; }
}

/* ---- Footer ---- */
/* Columns sit on the baseline. Top-aligned, the nav floated level with the logo
   and left a ragged gap under the shorter columns. */
.site-footer__inner { align-items: end; }

/* wpautop wraps the whitespace between block children in a <p>, and an empty <p>
   still takes a grid cell. It cost a column in the trust row and a whole second
   row in the hero, where it pushed 80px of dead space under the buttons.
   Written for every container rather than named ones, because listing them one
   at a time is how the second instance got missed: an empty paragraph has no
   purpose anywhere in rendered output. */
.aw-site-main p:empty { display: none; }

/* ---- Promise band ----
   This is the strongest single claim on the site and it used to sit below the
   hero CTAs at sub-heading weight with no ground, reading as an afterthought
   rather than the differentiator. It gets its own band, and it puts the first
   dark ground 1000px higher up the page, which is most of the "too much white"
   problem on its own. */
.promise-band { background: var(--navy-900); color: var(--c-white);
  padding: var(--sp-16) var(--gutter); text-align: center; }
.promise-band__line { font-family: var(--font-display); font-weight: 900;
  font-size: clamp(28px, 3.6vw, 46px); line-height: 1.1; letter-spacing: -0.015em;
  margin: 0 auto; max-width: 22ch; color: var(--c-white); }
.promise-band__line em { font-style: normal; color: var(--cyan); }
.promise-band__sub { margin: var(--sp-6) auto 0; max-width: 60ch;
  font-size: var(--fs-body); line-height: 1.6; color: var(--navy-200); }

/* ---------- Handset comparison ----------
   A table, not a carousel: the buyer's job here is comparing, and a carousel
   hides the alternatives being compared. Scrolls sideways inside its own
   container so the page body never scrolls horizontally, and the first column
   sticks so you can still see which row you are reading on a phone. */
/* The comparison table breaks out of the text measure. Body copy is capped at 68ch
   because that is comfortable to read, but a four-column table inside 68ch forces a
   sideways scroll on a desktop, which is exactly what it should not do. Full page
   width fits all four without scrolling; the sideways scroll stays for phones. */
.page-body > .spec-scroll { max-width: none; }
.spec-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: var(--sp-8) 0;
  border: 1px solid var(--border); border-radius: var(--r-card); background: var(--c-white); }
/* margin-top: 0 overrides `.page-body table` further up, which adds 24px and showed
   as a white strip between the container border and the header row. */
.page-body .spec, .spec { border-collapse: collapse; width: 100%; min-width: 680px;
  table-layout: fixed; font-size: var(--fs-small); margin-top: 0; }
/* The label column is narrower than the handset columns. Without this, table-layout:fixed
   gives all five the same width and "Also worth knowing" fills its cell edge to edge. */
.spec col:first-child { width: 21%; }
.spec col + col { width: 19.75%; }
.spec th, .spec td { padding: var(--sp-4) var(--sp-6); text-align: left; vertical-align: top;
  border-bottom: 1px solid var(--border); }
/* Painted on the row as well as the cells: with border-collapse the cell backgrounds do not
   cover the collapsed top edge, which left a white strip above the header. */
.spec thead, .spec thead tr { background: var(--navy-50); }
.spec thead th { background: var(--navy-50); vertical-align: bottom; }
.spec tbody th, .spec thead th:first-child { position: sticky; left: 0; z-index: 1;
  background: var(--c-white); font-weight: 600; color: var(--navy-900);
  /* was white-space: nowrap, which overflowed the fixed-width column on a phone and
     printed the label straight over the next cell. Row labels wrap now. */
  box-shadow: 1px 0 0 var(--border); }
.spec thead th:first-child { background: var(--navy-50); }
.spec tbody tr:last-child th, .spec tbody tr:last-child td { border-bottom: none; }
.spec__shot { display: block; width: 96px; height: auto; margin: 0 auto var(--sp-3); }
/* Reserve two lines for the name whatever its length. Grandstream GRP2670 wraps and
   the others do not, and with bottom-aligned header cells that shunted its whole
   column up: image, name and link all sat higher than the other three. */
.spec__name { display: block; font-family: var(--font-display); font-weight: 700;
  color: var(--navy-900); font-size: 15px; line-height: 1.3; min-height: 2.6em; }
/* All four renders are square, so a fixed box keeps the handsets on one baseline
   even if a future image is not. */
.spec__shot { height: 96px; object-fit: contain; object-position: center bottom; }
.spec__sheet { display: inline-block; margin-top: var(--sp-2); font-size: 13px; }
.spec-hint { font-size: var(--fs-small); color: var(--text-muted); margin: calc(var(--sp-4) * -1) 0 var(--sp-8); }
@media (min-width: 901px) { .spec-hint { display: none; } }

/* The parent theme underlines nav links on :focus, not :focus-visible, so after a
   tap the first item stays underlined and reads as a broken or "current" item.
   The menu script moves focus into the list when it opens, which is correct for
   keyboard users, so the fix is to show the indicator only when it is wanted. */
.aw-primary-nav a:focus:not(:focus-visible),
.aw-footer-nav a:focus:not(:focus-visible) { text-decoration: none; }
.aw-primary-nav a:focus-visible,
.aw-footer-nav a:focus-visible { text-decoration: underline; }

/* ---- Logo sizing ----
   The header carries the dimensional mark with the tagline removed. At any height
   the header can afford, the tagline would set under 7px and read as a smudge, so
   it is stripped from the artwork rather than hidden with CSS. The mark grows to
   170px wide and the header's own padding comes down from 16px to 10px to pay for
   it, so the bar stays under 120px.

   The footer has the vertical room, so it carries the full reversed lockup with the
   tagline drawn in. The separate tagline line that used to sit under it is gone: two
   copies of the same four words, one of them artwork, read as a mistake. */
.site-header { padding-block: 10px; }
/* Full size. It was briefly cut to 64px on 13 September to make room for the phone number, on a
   measurement that was wrong: the check summed scrollWidth, and .site-nav's scrollWidth includes
   the absolutely positioned dropdowns at min-width 232px, so it over-read the row by 86px. The
   honest measure is .site-nav's own auto margin, which is the free space. At 1440px with the
   number showing and a 28px nav gap that is +20px, so the logo never needed to shrink. Removing
   Home from the menu was the only change the header actually required. */
.logo-slot { height: 72px; }
.logo-slot__img, .logo-slot img { max-width: none; }
@media (min-width: 1121px) {
  .logo-slot { height: 88px; }
}
/* Condensed logo drops to the height of the CTA beside it rather than standing taller, so the
   sticky bar is as short as its tallest element allows: 119px to 73px on desktop, 115px to 73px
   on a phone, where it used to stop at 89 and 95. 44px is a floor, not a number to keep tuning
   down. It is the button's min-height and the smallest comfortable tap target, so going below it
   shrinks nothing and costs accessibility. */
.site-header.is-condensed .logo-slot { height: 44px; }
/* The footer carries the reversed lockup with the tagline cut into the artwork, so the
   separate red "Connecting You to the Future" line underneath is gone. That line existed
   because the tagline was illegible as a small line of red type. Set to 200px at Kieran's
   decision on 13 September 2026, with the readability trade-off understood and accepted:
   CONNECTING and TO THE are present rather than comfortably readable at this size, while
   YOU and FUTURE carry it. 300px was measured as the point where the small words read
   properly, and the brand column is 419px at 1440px so there is room if that is revisited.

   Width-driven, not height-driven, because the tagline lockup is a different aspect ratio
   (2.25:1) to the wordmark alone (1.93:1). Pinning height would have silently shrunk it.

   Scoped to .site-footer deliberately. .logo-slot--footer is a single class and so loses to
   the plain .logo-slot height rules further down the file, which is why it never had any
   effect on its own. Two classes beats one regardless of order. */
.site-footer .logo-slot--footer { height: auto; width: 200px; max-width: 100%; margin: 0 0 var(--sp-5); }
.site-footer .logo-slot--footer .logo-slot__img { width: 100%; height: auto; max-width: 200px; }

/* ------------------------------------------------------------------
   Handset photo lightbox. Built by assets/motion.js on the comparison
   table only. Durations use --dur-fast, which the reduced-motion block
   above already zeroes, so there is no second media query here.
   ------------------------------------------------------------------ */
.spec__zoom { display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: zoom-in; color: inherit; font: inherit; }
.spec__zoom .spec__shot { transition: transform var(--dur-fast) var(--ease); }
.spec__zoom:hover .spec__shot { transform: scale(1.06); }
.spec__zoom { position: relative; }
/* Always visible, including on a phone where there is no hover to reveal it.
   Small and quiet: it is a cue, not a call to action. */
.spec__zoomhint { display: block; margin-top: 2px; font-size: 11px; line-height: 1.4;
  letter-spacing: 0.02em; color: var(--muted, #5b6b7c); }
.spec__zoom:hover .spec__zoomhint { color: var(--action); }
.spec__zoom:focus-visible { outline: 2px solid var(--action); outline-offset: 3px; border-radius: 4px; }

/* display:grid outranks the UA's [hidden]{display:none}, so the closed state has
   to be restated here or the overlay sits invisible over the page and eats clicks. */
.lightbox[hidden] { display: none; }
.lightbox { position: fixed; inset: 0; z-index: 200; display: grid; align-content: center;
  justify-items: center; gap: var(--sp-6); padding: var(--sp-8) var(--gutter);
  /* White, not navy. The handset renders are cut out and carry their own drop
     shadow, which reads as grey mush on a dark ground. Fully opaque: at 0.985 the
     navy worked because everything behind it was darker, but on white the body
     copy and headings read straight through and sat over the product shot. */
  background: #FFFFFF; cursor: zoom-out; }
.lightbox__figure { margin: 0; display: grid; justify-items: center; gap: var(--sp-4);
  max-width: min(680px, 100%); }
.lightbox__img { display: block; width: auto; max-width: 100%; max-height: 62vh;
  object-fit: contain; }
.lightbox__cap { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-h4);
  color: var(--ink); text-align: center; }

/* The X is drawn, so there is no icon file to load and it inherits currentColor. */
.lightbox__close { position: absolute; top: var(--sp-4); right: var(--gutter);
  width: 44px; height: 44px; padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--ink); }
.lightbox__close::before, .lightbox__close::after { content: ""; position: absolute;
  left: 11px; top: 21px; width: 22px; height: 2px; background: currentColor; }
.lightbox__close::before { transform: rotate(45deg); }
.lightbox__close::after { transform: rotate(-45deg); }
.lightbox__close:focus-visible { outline: 2px solid var(--action); outline-offset: 2px; }

/* The other three stay reachable, so two handsets can be compared without
   closing and reopening. The current one is marked by a rule under it. */
.lightbox__strip { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--sp-2);
  cursor: default; }
/* On the old dark ground these needed a light panel to be legible. On white they
   do not, and a faint panel just boxes each thumbnail for no reason. A hairline
   keeps them reading as separate targets. */
.lightbox__pick { width: 64px; padding: var(--sp-1) var(--sp-1) var(--sp-2); border: 0;
  border-bottom: 2px solid transparent; background: none;
  cursor: pointer; opacity: 0.55; transition: opacity var(--dur-fast) var(--ease); }
.lightbox__pick img { display: block; width: 100%; height: 48px; object-fit: contain; }
.lightbox__pick:hover { opacity: 1; }
.lightbox__pick.is-current { opacity: 1; border-bottom-color: var(--cyan); cursor: default; }
.lightbox__pick:focus-visible { outline: 2px solid var(--action); outline-offset: 2px; opacity: 1; }

.lightbox-open, .lightbox-open body { overflow: hidden; }

/* WordPress pins its admin bar to the viewport with position:fixed, so a logged-in
   editor sees the sticky header slide underneath it and the logo clipped off at the
   top. This reads as the header losing its padding on scroll; it is the bar sitting
   over it. Offset the header by the bar's own height. WordPress grows the bar to 46px
   at 782px and switches it to position:absolute below 600px, where it scrolls away
   and the offset has to go back to zero. The mobile panel needs no rule of its own:
   --header-h is published from the header's bottom edge, so it already follows. */
body.admin-bar { --wpbar: 32px; }
@media screen and (max-width: 782px) { body.admin-bar { --wpbar: 46px; } }
@media screen and (max-width: 600px) { body.admin-bar { --wpbar: 0px; } }
body.admin-bar .site-header { top: var(--wpbar); }
html.nav-open body.admin-bar .site-header { top: var(--wpbar); }

/* The hero's lede and a body-copy first paragraph are the same size and weight,
   so the full hero gap between them reads as a mistake rather than a break. It
   was 80px: 48 of hero padding, 16 of lede margin, 16 of paragraph margin. Closed
   to 32 where a paragraph follows. A heading still gets the full separation,
   because there the space is doing work and the change in type size explains it.
   :has() is already used twice in this file, so no new support assumption. */
.page-body > p:first-child { margin-top: 0; }
.page-hero:has( + .page-body > p:first-child ) { padding-bottom: var(--sp-8); }
