/*
Theme Name: IMRSNT
Theme URI: https://imrsnt.com
Author: Immersant
Description: The IMRSNT marketing site as a WordPress block theme. The design tokens live in
 theme.json as WordPress presets (palette, font families, spacing, radius), so the block editor
 offers the brand's own colours and faces; this stylesheet holds only the rules no block setting
 expresses - the hand-built header/footer chrome, the hero, the cards, the contact form and the
 consent notice.
Version: 1.0.1
Requires at least: 6.4
Requires PHP: 7.4
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: imrsnt-web-site
*/

/* THE TOKENS ARE NOT DECLARED HERE ANY MORE.
 *
 * On the static build this :root block was the only copy of docs/tokens.json's values, hand-kept
 * in sync. In a block theme theme.json is that copy: WordPress emits every palette entry, font
 * family, spacing size and `custom` value as a --wp--preset--* / --wp--custom--* variable on
 * :root for us, AND shows them in the editor's own colour and typography pickers - which a
 * stylesheet cannot do. So the names below are aliases onto those variables, not values: change
 * a colour in theme.json and it changes here, in the editor and in every block's controls at once.
 *
 * The literal hexes that remain anywhere in this file are the two that are NOT tokens (see
 * --quiet-border / --footer-text, which theme.json carries under `custom`) and the rgba shadows. */
:root {
  --color-primary: var(--wp--preset--color--primary);
  --color-secondary: var(--wp--preset--color--secondary);
  --color-background: var(--wp--preset--color--background);
  --color-surface: var(--wp--preset--color--surface);
  --color-ink: var(--wp--preset--color--ink);
  --color-muted: var(--wp--preset--color--muted);

  /* The fourth client-supplied brand blue. Reserved for the footer band and the
     primary button's hover - the site's only dark-on-brand surface (US-006 AC1). */
  --color-brand-deep: var(--wp--preset--color--brand-deep);

  /* THE HIGHLIGHT IS MORE BLUE, NOT ANOTHER HUE. A tonal family around the brand blue: a bright sky
     (--accent) and a deep navy (--accent-deep). Used sparingly: the short navy-to-sky rule under
     headings, navy numbered markers ringed in sky, the hero pill's icon. Sky fails as text on white
     (2.2:1), so it is decoration only; navy carries white text at 15.5:1 and works as an icon or
     text colour anywhere. An orange complement was tried first and dropped on 2026-11-02 as too
     loud for the brand. Product pages swap both for their app's own accent. */
  --accent: var(--wp--preset--color--accent);
  --accent-deep: var(--wp--preset--color--accent-deep);

  /* Derived neutrals - not brand colours, so US-006 AC2 is untouched by them. */
  --line: var(--wp--preset--color--line);
  --tint: var(--wp--preset--color--tint);

  /* Quicksand is a free Google font; it is NOT self-hosted in this build and NOT fetched from
     Google (TC-020 asserts no request to fonts.googleapis.com ever fires), so a visitor without
     it installed sees the fallback. The stacks themselves live in theme.json's fontFamilies. */
  --font-display: var(--wp--preset--font-family--display);
  --font-body: var(--wp--preset--font-family--body);

  --radius: var(--wp--custom--radius);
  --shadow: var(--wp--custom--shadow);
  --gutter: var(--wp--custom--gutter);
  --gap: 28px;
  /* ONE WIDTH FOR EVERY PLATE. Hero, page heads, section heads, prose, fact rows, card grids, the
     contact panels and the client names all stop at this, so every card's left and right edges
     line up down the page. There were six widths (760, 820, 860, 900, 1000, 1180) and the eye
     reads each step as a mistake. 1000 is the widest a prose plate can be and still hold a
     readable line, given the inset .prose carries below. */
  --plate: 1000px;
  --quiet-border: var(--wp--custom--quiet-border);
  --footer-text: var(--wp--custom--footer-text);
}

/* WordPress's own wrappers must not reintroduce width or padding: the layout below is the one
   the design was approved at, and every section sets its own gutter. */
.wp-site-blocks > * { margin-block-start: 0; }
main.wp-block-group,
header.wp-block-group,
footer.wp-block-group { max-width: none; padding: 0; }

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

/* THE PAGE ITSELF IS TRANSPARENT, AND THE CANVAS CARRIES THE COLOUR (QUEST-023 round 2).
 *
 * The brand field below is a `position: fixed` layer at `z-index: -1` inside <body>. A
 * negatively-stacked descendant of the root paints ABOVE the canvas background and BELOW every
 * other box on the page — which is exactly the layer a page-wide backdrop wants, and it only
 * works if <body> itself paints nothing. If body kept `background: var(--color-background)` the
 * field would sit behind an opaque sheet and be invisible on all eight routes.
 *
 * `html body` and not a bare `body`: theme.json's styles.color.background makes WordPress emit
 * `body { background-color: … }` into its global-styles block, which is the same specificity as a
 * bare `body` rule here and is not guaranteed to be printed before this stylesheet. Two
 * element selectors beat one, so this wins whichever order they land in — a rule whose
 * correctness depends on enqueue order is a rule that breaks on a core update. */
html { background: var(--color-background); }

html body {
  margin: 0;
  background: transparent;
  color: var(--color-ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  /* NO `overflow-x: hidden` here on purpose. US-006 AC4 says nothing may push the page sideways
     at 375px, and the gate checks that by comparing scrollWidth to clientWidth — which a hidden
     overflow would make equal whatever the layout actually did. The guard would hide the bug it
     is there to catch, so the layout has to be right instead. */
}

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4, h5 { font-family: var(--font-display); font-weight: 600; margin: 0; }

a { color: var(--color-primary); }

/* One focus treatment, everywhere. Nothing on this site relies on :hover alone. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 3px solid var(--color-secondary);
  outline-offset: 3px;
}

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 var(--gutter); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 8px; top: -60px; z-index: 60;
  background: var(--color-surface); color: var(--color-primary);
  padding: 12px 20px; border-radius: var(--radius); font-weight: 700;
  transition: top 0.15s ease;
}
.skip-link:focus { top: 8px; }

/* ---------------------------------------------------------------- header */

header.site {
  background: var(--color-surface);
  border-bottom: 1px solid var(--line);
  position: relative;
  /* 46, above the drawer's backdrop (45). The header is a stacking context and the phone drawer
     lives inside it, so at 40 the backdrop dimmed the open drawer itself on every page. */
  z-index: 46;
}
header.site .wrap {
  display: flex;
  align-items: center;
  min-height: 76px;
  gap: 16px;
}

.logo { display: flex; align-items: center; gap: 12px; text-decoration: none; }
.logo img { height: 38px; width: auto; }

/* THE HEADER STICKS, AND SETTLES AS YOU SCROLL (client, 2026-11-02). The sticky element is the
   template part wrapping the header, because a sticky box only sticks within its parent and the
   header's own parent is exactly its height. Its height never changes, so nothing below it jumps;
   what animates is the surface: on scroll (body.scrolled, set by js/nav.js) it gains a soft shadow,
   and on Home it turns from transparent over the band to solid white, the banner-size logo eases
   down to its normal size, and the floating menu pill dissolves into the bar. */
.wp-block-template-part:has(> header.site) { position: sticky; top: 0; z-index: 46; }
/* In-page links (Home's "How we do integration" -> /solutions#integration) land below the bar,
   not under it. */
html { scroll-padding-top: 92px; }
header.site { transition: background-color 0.28s ease, box-shadow 0.28s ease, border-color 0.28s ease; }
body.scrolled header.site { box-shadow: 0 4px 18px rgba(22, 38, 47, 0.08); }

nav.main { margin-left: auto; }
nav.main ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; align-items: center; gap: 4px;
}
nav.main a {
  display: flex; align-items: center;
  min-height: 44px; padding: 0 16px;
  border-radius: 999px;
  font-size: 15px; color: var(--color-ink); text-decoration: none;
}
nav.main a:hover { background: var(--color-background); color: var(--color-primary); }
nav.main a[aria-current="page"] {
  background: var(--tint); color: var(--color-primary); font-weight: 700;
}

/* The CTA repeated at the foot of the mobile drawer, so the funnel to Contact survives the
   nav collapsing. It exists only inside the drawer — on desktop the page's own hero CTA is
   the one primary action (US-001 AC2), and a second one in the header would compete with it. */
nav.main .drawer-cta { display: none; }

/* The hamburger only exists below the nav breakpoint (see the media query at the
   foot of this file). Resolved contradiction: <1024px collapses — docs/system-diagram.md
   and the design doc's component inventory both say 1024. */
.nav-toggle {
  display: none;
  margin-left: auto;
  min-width: 44px; min-height: 44px;
  align-items: center; justify-content: center; gap: 8px;
  background: none; border: 2px solid var(--line); border-radius: 999px;
  padding: 0 16px;
  font-family: var(--font-display); font-weight: 600; font-size: 15px;
  color: var(--color-primary); cursor: pointer;
}
.nav-toggle svg { width: 20px; height: 20px; }

.drawer-backdrop {
  display: none;
  position: fixed; inset: 0; z-index: 45;
  background: rgba(22, 38, 47, 0.45);
}
body.nav-open .drawer-backdrop { display: block; }

/* ---------------------------------------------------------- the brand field */

/* THE RING IS THE WHOLE SITE'S BACKDROP, NOT THE HERO'S (QUEST-023 round 2).
 *
 * Round 1 put the client's own render inside the Home hero band under a wash whose alpha could
 * never drop below .90. The client rejected it on sight, and they were right about both halves:
 * on seven of the eight routes the artwork was not there at all, and on the eighth it was a pale
 * tint. What they asked for instead is one still, page-wide field that the content scrolls over.
 *
 * WHY A FIXED ELEMENT AND NOT `background-attachment: fixed`. caniuse's support notes for the
 * property say most mobile devices lag the background position while a page with a fixed
 * background is scrolling, and iOS WebKit treats `fixed` as `scroll` outright — there is an open
 * browser-compat-data issue titled exactly that (mdn/browser-compat-data#28856). The standard
 * workaround, and what this is, is to put the image on a `position: fixed` element instead. AC5
 * requires the field to be still on the gate's `phone` project as well as `desktop`, so the
 * property that is ignored on half the phones in the world was never an option.
 *
 * `inset: 0` and not `height: 100vh`: on mobile Safari 100vh is the URL-bar-EXPANDED height, so a
 * 100vh layer jumps as the bar collapses. A fixed box with `inset: 0` tracks the visual viewport.
 *
 * `z-index: -1` puts it under every box on the page and above the canvas background — which is
 * why `html` carries the page colour and `html body` is transparent (see the body rule above).
 *
 * It is an <img> and not a `background-image`: a CSS background is discovered late and pops in,
 * an <img> gets normal fetch priority. It is absolutely out of flow, so it reserves no layout box
 * and there is nothing for constraints.md's "no visible layout jump" to catch. */
.page-backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}
.page-backdrop img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* `cover` crops on whichever axis is tight, so one declaration covers every viewport: at 1280
     the render's 16:9 is wider than the window and it crops left and right; on a phone it crops
     far harder and what stays is the middle of the frame — the torus and the open sweep around
     it, which is what a fixed field wants behind scrolling text. */
  object-position: center center;
  /* ROUND 3 (the client, 2026-11-02): BIGGER, MORE ABSTRACT, DIMMED. At 1:1 the torus read as a
     picture of an object; scaled up past the window it stops being one and becomes a field of
     spheres the page moves over, cropped by the layer's own overflow (TC-035 asserts the image
     covers the layer, no longer that it matches it). The dimming is "a little more than a
     watermark": opacity lets the page colour on <html> through, and the partial grayscale takes
     the render's cool cast off so it sits under the brand blues rather than beside them. The
     origin is off-centre on purpose, so the open middle of the ring is not parked behind the
     hero card on every viewport. */
  /* FULL COLOUR (the client, 2026-11-02): the 0.55 opacity and 0.6 grayscale "watermark" wash is
     gone, so the image shows exactly as rendered. Every block of text still sits on an opaque
     plate, so legibility does not depend on the field being faint. */
}

/* ------------------------------------------------------------------ hero */

/* THE COPY SITS ON A SURFACE, AND THAT IS WHAT PAYS FOR THE WASH BEING GONE.
 *
 * This is a change of METHOD, not of standard (QUEST-023 round 2, US-010 AC7). Round 1 bought
 * WCAG AA with a .90 wash over the artwork; a wash strong enough to protect 13px muted text is a
 * wash strong enough to erase the artwork, which is the complaint that sent this back — and
 * washing all eight routes that way would have spread the problem rather than fixed it. So the
 * legibility moves off the wash and onto opaque surfaces: every block of text on this site sits
 * on one, and the field is shown at full strength in the space between them. */

/* THE HERO IS A FULL-WIDTH BAND WITH THE NETWORK BUILT IN (Option 1, client, 2026-11-02).
 *
 * Earlier rounds tried to make a fixed page-wide network meet a scrolling card. It could not: the
 * two scale and move independently, so their lines only met by accident. Here the network is drawn
 * INTO the band (tools/build-hero-band.py, hero-band.svg): dense at the sides, open in the middle
 * where the copy sits, with the database and code marks in it. One drawing that scrolls with the
 * band, so every line is where it was drawn at every width.
 *
 * The band's white is the opaque surface the copy sits on (US-010 AC7), so `.hero-inner` is no
 * longer a card: no border, shadow or plate of its own, just the copy's measure. On a phone the
 * band takes a portrait drawing with the network along its top and bottom, because cropping the
 * landscape one to a phone's width would cut away the sides, which is where the network is. */
/* THE BAND FADES INTO THE PAGE (client, 2026-11-02) instead of stopping at an edge. Two halves:
   inside the band, a white gradient over the drawing's last stretch lets the art thin out rather than
   be cut, whatever the cover crop; below it, .hero::after carries the white on down into the page's
   own field and lets it go. The band's white stays an opaque background-color, because that is what
   the copy's contrast stands on (US-010 AC7, TC-036). The drawing is 80 units taller at the bottom
   (tools/build-hero-iso.py) and the padding below matches, so nothing it carries sits in the fade. */
.hero {
  position: relative;
  background:
    linear-gradient(to bottom, rgba(255, 255, 255, 0) 78%, #FFFFFF 100%),
    url("assets/hero-band.svg") center top / auto 100% no-repeat;
  background-color: var(--color-surface);
  padding: 96px var(--gutter) 180px;
  text-align: center;
}
.hero::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 160px; pointer-events: none;
  background: linear-gradient(to bottom, #FFFFFF, rgba(255, 255, 255, 0));
}
/* The first block under the band sits above the fade, so its own edge and shadow stay crisp. */
main .entry-content > .hero + .section { position: relative; z-index: 3; }

.hero-inner {
  position: relative;
  max-width: 860px;
  margin: 0 auto;
}

/* HEADER AND BAND ARE ONE SURFACE on Home (client, 2026-11-02). The header goes transparent and the
   band runs up behind it by the header's height (77px at every width); the drawing's top strip
   is a quieter part of the same network, so the logo and menu read over it. The header is not
   sticky, so it never floats over content. Only on Home: every other page keeps its white header. */
/* THE LOGO HAND-OFF (client, 2026-11-02, option 1). js/nav.js sets --p on the header: 0 at the top
   of Home, 1 after 110px of scroll. At 0 the big logo sits in the banner's top-left and the menu
   floats in its white pill; as p rises the big logo shrinks and fades up, .bar-surface unrolls from
   the pill to the full bar (its clip-path is set by the script), and the bar's small logo fades in
   only over the last stretch, once the white is under it, so it never sits on the network. */
body.home header.site,
body.banded header.site {
  background-color: transparent; border-bottom: 0;
  /* Tied to how far the bar has unrolled (--e), not to scroll, so no full-width line shows early. */
  box-shadow: 0 1px 0 rgba(225, 234, 240, var(--e, 0)), 0 4px 18px rgba(22, 38, 47, calc(0.08 * var(--e, 0)));
}
.bar-surface { display: none; }
body.home .bar-surface,
body.banded .bar-surface {
  display: block; position: absolute; inset: 0;
  background: var(--color-surface);
  clip-path: inset(0 0 100% 0);   /* hidden until the script has measured the pill */
}
header.site .wrap { position: relative; z-index: 1; }
.logo-hero { display: none; }
body.home .logo-hero {
  display: block; position: absolute; left: var(--gutter); top: 12px; pointer-events: none;
  transform-origin: left top;
  opacity: calc(1 - var(--p, 0) * 2.5);
  transform: translateY(calc(var(--p, 0) * -28px)) scale(calc(1 - var(--p, 0) * 0.3));
}
body.home .logo-hero img { height: 120px; width: auto; }
/* Between the hamburger breakpoint and 1440px the banner logo ran under, or right up against, the
   menu pill (seen live on a laptop, 2026-11-12): a smaller banner logo and tighter links keep the
   two apart. */
@media (min-width: 1024px) and (max-width: 1439px) {
  body.home .logo-hero img { height: 80px; }
  nav.main a { padding: 0 10px; }
}
/* Below 1280px that still left only ~15px at 1024, too little once Safari's text runs a hair wider. */
@media (min-width: 1024px) and (max-width: 1279px) {
  body.home .logo-hero img { height: 64px; }
}
body.home .logo { opacity: clamp(0, calc((var(--p, 0) - 0.7) / 0.3), 1); }
body.home .logo:focus-visible { opacity: 1; }
/* Small text over the band still sits on an opaque surface (US-010 AC7): the menu floats in a white
   pill on desktop, and the phone's Menu button is filled. As the bar unrolls out of the pill, the
   pill's outline and shadow fade away into it. */
@media (min-width: 1024px) {
  body.home nav.main ul, body.banded nav.main ul { background: var(--color-surface); border-radius: 999px; padding: 4px;
    border: 1px solid rgba(225, 234, 240, calc(1 - var(--p, 0)));
    box-shadow: 0 2px 10px rgba(22, 38, 47, calc(0.06 * (1 - var(--p, 0)))); }
}
body.home .nav-toggle, body.banded .nav-toggle { background: var(--color-surface); }
.entry-content > .hero:first-child { margin-top: -77px; padding-top: calc(96px + 77px); }

/* The band runs edge to edge, so the first section below it gets the gap a plate would. */
/* ...and rides up into the band's fade (client, 2026-11-02), so the fade is the gap. */
main .entry-content > .hero + .section { margin-top: -96px; }

.pill {
  display: inline-flex; align-items: center; gap: 8px;
  background: var(--tint); color: var(--color-primary);
  font-size: 13px; font-weight: 700;
  padding: 8px 16px; border-radius: 999px; margin: 0 0 20px;
}
.pill svg { width: 16px; height: 16px; color: var(--accent-deep); }

h1 { font-size: 46px; line-height: 1.14; letter-spacing: -0.015em; margin: 0 0 16px; }

.lede {
  font-size: 17px; line-height: 1.65; color: var(--color-muted);
  max-width: 62ch; margin: 0 auto 28px;
}

.hero-actions { display: flex; gap: 16px; justify-content: center; flex-wrap: wrap; }
.reassure { font-size: 13px; color: var(--color-muted); margin: 16px 0 0; }

/* --------------------------------------------------------------- buttons */

.btn {
  font-family: var(--font-body); font-size: 16px; font-weight: 700;
  min-height: 52px; padding: 0 32px;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  border: 2px solid transparent; border-radius: 999px;
  text-decoration: none; cursor: pointer;
}
.btn.primary { background: var(--color-primary); color: #FFFFFF; box-shadow: var(--shadow); }
.btn.primary:hover { background: var(--color-brand-deep); }
/* `background: none` became an opaque `--color-background` with the brand field (QUEST-023 round
   2): a quiet button is 16px bold, which WCAG does NOT count as large text, and three of them
   (Home's "See all seven services", About/Clients/Privacy's closing links) sit in sections with
   nothing but the field behind them. #006BA1 on #F7FAFC is 5.5:1; on the render's darker pixels
   it is not. The hover still resolves to white, so the two states stay distinct. */
.btn.quiet { background: var(--color-background); color: var(--color-primary); border-color: var(--quiet-border); }
.btn.quiet:hover { background: var(--color-surface); }
.btn svg { width: 18px; height: 18px; }

/* -------------------------------------------------------------- sections */

/* THE SECTION BANDS THEMSELVES ARE TRANSPARENT, ON PURPOSE. `.section`'s padding is where the
   brand field shows: 32px of it above and below every block, plus the gutters either side and
   the gaps inside every grid. That is what makes a still, page-wide field actually read as you
   scroll — the alternative, tinting the whole page, is the thing round 1 was sent back for. */
/* ONE GAP, EVERYWHERE (client, 2026-11-02). Every block on every page sits --gap from the next:
   a heading plate from its cards, one section from the next, the page heading from what follows,
   and the cards inside a grid from each other. Sections carry no vertical padding of their own,
   and WordPress's own flow spacing between them is replaced, not added to. */
.section { padding: 0 var(--gutter); }
main .entry-content > * { margin-block-start: 0; margin-block-end: 0; }
main .entry-content > * + * { margin-block-start: var(--gap); }

/* `.section-head` and `.page-head` were transparent and are now plates, for the reason set out
   above `.hero-inner`: their ledes and sub-lines are 15–17px --color-muted, which needs 4.5:1,
   and an opaque surface answers that instead of a number nobody re-checks. The headings keep
   their size and centring; only what is behind them changed. */
.section-head {
  text-align: center; margin: 0 auto var(--gap); max-width: var(--plate);
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px 28px;
}
.section-head h2 { font-size: 28px; margin: 0 0 8px; }
.section-head p { font-size: 15px; color: var(--color-muted); margin: 0; }
/* Home: the way on to the full catalogue sits in the heading plate, under the line that names it. */
.section-head .head-more { margin-top: 16px; }

/* `width: calc(100% - 2 * gutter)` with `margin: … auto` rather than a horizontal padding: the
   plate has to be a card with the field visible around it at 1280 AND stay clear of the screen
   edges at 375, and those are the same two numbers. */
.page-head {
  max-width: var(--plate);
  width: calc(100% - 2 * var(--gutter));
  margin: 40px auto 0;
  padding: 32px 32px 28px;
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  text-align: center;
}
/* WordPress's flow layout zeroes the top margin of the first block in the post content
   (`.wp-block-post-content-is-layout-flow > :first-child`), which beat `.page-head`'s 40px and
   left every inner page's heading plate flush against the header while Home's hero, spaced by
   padding, kept its gap. This selector out-ranks that rule so the plate sits as far under the
   header as the hero does: 40px, or 24px on a phone. */
main .entry-content > .page-head:first-child { margin-top: 40px; }
.page-head h1 { font-size: 40px; }

/* The accent's main job: one short rule under every page and section heading. */
.page-head h1::after,
.section-head h2::after,
.clients-band h2::after {
  content: ""; display: block; width: 48px; height: 3px; border-radius: 2px;
  background: linear-gradient(90deg, var(--accent-deep), var(--accent)); margin: 12px auto 0;
}
.page-head .lede { margin-bottom: 0; }

/* INNER PAGES OPEN ON A BAND, NOT A PLATE (client, 2026-11-02: the headers "are very plain"). The
   heading runs the full width on white, with that page's own isometric scene at its sides
   (tools/build-page-bands.py), and fades into the page the way Home's hero does: a white gradient
   over the drawing's last stretch, then .page-head::after carrying the white on below. The white is
   an opaque background-color, which is what the lede's contrast stands on (TC-036). A product's own
   page keeps its app-styled plate (.product-head). The first block below rides up into the fade. */
.page-head:not(.product-head) {
  --band-fade: linear-gradient(to bottom, rgba(255, 255, 255, 0) 82%, #FFFFFF 100%);
  position: relative; max-width: none; width: auto; margin: 0;
  border: 0; border-radius: 0; box-shadow: none;
  background: var(--band-fade), url("assets/bands/plain.svg") center top / auto 100% no-repeat;
  background-color: var(--color-surface);
  padding: calc(64px + 77px) var(--gutter) 150px;
}
.page-head:not(.product-head) > * { max-width: 640px; margin-left: auto; margin-right: auto; }
.page-head:not(.product-head)::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 140px; pointer-events: none;
  background: linear-gradient(to bottom, #FFFFFF, rgba(255, 255, 255, 0));
}
main .entry-content > .page-head:not(.product-head):first-child { margin-top: -77px; }
main .entry-content > .page-head:not(.product-head) + * { position: relative; z-index: 3; margin-top: -64px; }
.page-head.band-about { background-image: var(--band-fade), url("assets/bands/about.svg"); }
.page-head.band-solutions { background-image: var(--band-fade), url("assets/bands/solutions.svg"); }
.page-head.band-engineers { background-image: var(--band-fade), url("assets/bands/engineers.svg"); }
.page-head.band-products { background-image: var(--band-fade), url("assets/bands/products.svg"); }
.page-head.band-clients { background-image: var(--band-fade), url("assets/bands/clients.svg"); }
.page-head.band-contact { background-image: var(--band-fade), url("assets/bands/contact.svg"); }
.page-head.band-ai { background-image: var(--band-fade), url("assets/bands/ai.svg"); }


/* ----------------------------------------------------------------- cards */

.cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--gap);
  max-width: var(--plate); margin: 0 auto;
}
.card {
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: var(--shadow);
  display: flex; flex-direction: column;
}
.card .ic {
  width: 48px; height: 48px; border-radius: 12px;
  background: var(--tint); color: var(--color-primary);
  display: flex; align-items: center; justify-content: center;
  margin-bottom: 16px;
}
.card .ic svg { width: 24px; height: 24px; }
.card h3 { font-size: 19px; margin: 0 0 8px; }
.card p { font-size: 14px; line-height: 1.65; color: var(--color-muted); margin: 0 0 16px; }
.card .card-link {
  margin-top: auto;
  min-height: 44px;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 700;
  color: var(--color-primary); text-decoration: none;
}
.card .card-link:hover { text-decoration: underline; }
.card .card-link svg { width: 15px; height: 15px; }

.more { text-align: center; margin-top: 24px; }

/* HOME: three services in one card, the words on the left and one infographic on the right that
   shows how they connect. The orange numbers tie each row to its stage of the picture. */
.card.overview {
  display: grid; grid-template-columns: 1fr 1fr; gap: 40px; align-items: center;
  max-width: var(--plate); margin: 0 auto; padding: 28px 36px;
}
.ov-item { display: grid; grid-template-columns: 48px 1fr; gap: 16px; padding: 18px 0; border-top: 1px solid var(--line); }
.ov-item:first-child { border-top: 0; padding-top: 4px; }
.ov-item:last-child { padding-bottom: 4px; }
.ov-item .ic { position: relative; margin: 0; }
.ov-item h3 { font-size: 18px; margin: 0 0 4px; }
.ov-item p { margin: 0 0 4px; }
.ov-item .card-link { min-height: 32px; }
.ic .n {
  position: absolute; top: -7px; right: -7px;
  width: 20px; height: 20px; border-radius: 50%;
  background: var(--accent-deep); color: #FFFFFF;
  box-shadow: 0 0 0 2px #FFFFFF, 0 2px 6px rgba(11, 46, 74, 0.28);
  font-family: var(--font-display); font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
.overview-fig { margin: 0; align-self: stretch; display: flex; align-items: center; }
.overview-fig .fig-art { max-width: 443px; width: 100%; height: auto; }
/* Colour classes for the drawn graphics: k-* fills, s-* strokes, every one a theme token (TC-045).
   Teal and violet are the graphics' supporting hues (theme.json), used only inside figures. */
.fig-art .k-none { fill: none; }
.fig-art .k-surface { fill: var(--color-surface); } .fig-art .k-ink { fill: var(--color-ink); }
.fig-art .k-primary { fill: var(--color-primary); } .fig-art .s-primary { stroke: var(--color-primary); }
.fig-art .s-secondary { stroke: var(--color-secondary); } .fig-art .k-tint { fill: var(--tint); }
.fig-art .k-navy { fill: var(--accent-deep); } .fig-art .k-sky { fill: var(--accent); } .fig-art .s-sky { stroke: var(--accent); }
.fig-art .k-teal { fill: var(--wp--preset--color--teal); } .fig-art .s-teal { stroke: var(--wp--preset--color--teal); }
.fig-art .k-teal-tint { fill: var(--wp--preset--color--teal-tint); }
.fig-art .k-violet { fill: var(--wp--preset--color--violet); } .fig-art .s-violet { stroke: var(--wp--preset--color--violet); }
.fig-art .k-violet-tint { fill: var(--wp--preset--color--violet-tint); }

/* ---------------------------------------------- embedded engineers page */

/* How a placement works: four numbered plates in a row, on the same --plate width as everything else. */
.steps {
  list-style: none; margin: 0 auto; padding: 0;
  max-width: var(--plate);
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gap);
}
.steps li {
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px;
}
.steps .step-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: 50%;
  /* The site's one number badge: solid navy with a soft shadow, as on Home and About. */
  background: var(--accent-deep); color: #FFFFFF;
  box-shadow: 0 0 0 2px #FFFFFF, 0 2px 6px rgba(11, 46, 74, 0.28);
  font-family: var(--font-display); font-weight: 700; font-size: 15px;
  margin-bottom: 12px;
}
/* Inside an app's pages --accent-deep is that app's accent, so its steps keep the app's primary. */
body.brand-formvault main .steps .step-n, body.brand-adora main .steps .step-n { background: var(--color-primary); }
.steps h3 { font-size: 17px; margin: 0 0 6px; }
.steps p { font-size: 14px; line-height: 1.65; color: var(--color-muted); margin: 0; }

/* ---------------------------------------------------------------- products */

/* One product, featured: copy on the left, a real screenshot in a phone-shaped plate on the right. */
.product {
  max-width: var(--plate); margin: 0 auto;
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 36px 44px;
  display: grid; grid-template-columns: 1fr 240px; gap: 48px; align-items: center;
}
.product .device { max-width: 240px; }
.app-icon { width: 64px; height: 64px; border-radius: 16px; box-shadow: var(--shadow); }
.product-id { display: flex; align-items: center; gap: 16px; margin-bottom: 16px; }
.product h2 { font-size: 28px; margin: 0; }
.product .product-kind { font-size: 14px; color: var(--color-muted); margin: 2px 0 0; }
.product .product-line { font-size: 17px; color: var(--color-ink); margin: 0 0 16px; }
.product .points { margin: 0 0 24px; padding-left: 20px; }
.product .points li { font-size: 15px; line-height: 1.6; color: var(--color-muted); margin-bottom: 6px; }
.product-actions { display: flex; gap: 12px; flex-wrap: wrap; }
/* EVERY APP SCREENSHOT SITS IN A PHONE (client, 2026-11-02; 20:9 like today's phones since 2026-11-05): a dark bezel, a punch-hole camera and
   two side keys, drawn in CSS around whatever is inside, a real screenshot or a placeholder. The
   bezel is a device colour, not a brand one, so it stays the same inside the app scopes. */
.device {
  position: relative; width: 100%; max-width: 260px; margin: 0 auto;
  padding: 8px; border-radius: 34px;
  background: #151A21;
  box-shadow: 0 0 0 1.5px #343C47, 0 18px 36px rgba(11, 46, 74, 0.22), 0 4px 10px rgba(11, 46, 74, 0.12);
}
.device::before {
  content: ""; position: absolute; z-index: 2; top: 15px; left: 50%;
  width: 9px; height: 9px; margin-left: -4.5px; border-radius: 50%;
  background: #05070A; box-shadow: 0 0 0 1.5px #262D36;
}
.device::after {
  content: ""; position: absolute; right: -3px; top: 22%;
  width: 3px; height: 56px; border-radius: 0 2px 2px 0; background: #343C47;
  box-shadow: 0 74px 0 #343C47;
}
.device > img, .device > .ph {
  display: block; width: 100%; aspect-ratio: 9 / 20; object-fit: cover;
  border-radius: 26px; border: 0;
}
.device > .ph { display: flex; background: var(--color-surface); border: 0; color: var(--color-muted); }

/* The 404's route cards are whole links: the card lifts on hover, its heading takes the link colour. */
.card.card-route { text-decoration: none; color: inherit; transition: transform 0.15s ease, box-shadow 0.15s ease; }
.card.card-route:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(11, 46, 74, 0.12); }
.card.card-route h2 { font-size: 19px; margin: 0 0 8px; color: var(--color-ink); }
.card.card-route:hover h2 { color: var(--color-primary); }

/* A product's own page: the icon above the name in the heading plate. */
.product-head .app-icon { margin: 0 auto 16px; }
.product-head .product-meta { font-size: 14px; color: var(--color-muted); margin: 12px 0 0; }

/* Real screenshots, four across, each in a plate with its caption. */
.shots {
  max-width: var(--plate); margin: 0 auto;
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--gap);
}
/* Each screenshot is a phone on one shared plate, its caption beneath it. The plate keeps the
   captions on an opaque surface (TC-036) and holds the four phones together as one block. */
.shots {
  background: var(--color-surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 36px 32px 28px;
}
.shot { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 18px; }
.shot figcaption {
  font-family: var(--font-display); font-size: 15px; font-weight: 700; color: var(--color-ink);
  text-align: center; line-height: 1.4; max-width: 200px;
}
.product-actions.center { justify-content: center; margin-top: 20px; }

/* The product's explainer video and its banner, each a plate on the shared width. */
.video, .banner {
  max-width: var(--plate); margin: 0 auto;
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.video { padding: 12px; }
.video video { display: block; width: 100%; height: auto; border-radius: 12px; }
.banner img { width: 100%; }

/* PLACEHOLDERS for a product page that has no content yet (Adora). A dashed box that says what
   belongs in it, sized like the real thing so the layout reads true before the assets exist. */
.ph {
  display: flex; align-items: center; justify-content: center; text-align: center;
  background: var(--color-surface);
  border: 2px dashed var(--quiet-border);
  border-radius: 12px;
  color: var(--color-muted); font-size: 14px; font-weight: 700;
  padding: 8px;
}
.ph-icon { flex: none; width: 64px; height: 64px; border-radius: 16px; font-size: 11px; padding: 4px; }
.ph-center { margin: 0 auto 16px; }
.ph-button { display: inline-flex; min-height: 48px; padding: 0 24px; border-radius: 999px; }
.ph-screen { aspect-ratio: 9 / 16; }
.video.ph { aspect-ratio: 16 / 9; box-shadow: none; }
.banner.ph { aspect-ratio: 1600 / 331; box-shadow: none; }

/* ------------------------------------------------------ product brands */

/* A PRODUCT SPEAKS IN ITS OWN APP'S STYLE; THE SITE AROUND IT STAYS IMRSNT.
 *
 * Every plate on this site is drawn from the variables in :root, so an app's look is applied by
 * re-pointing those variables inside a scope, never by restyling components. Two scopes:
 *   - `.brand-formvault` / `.brand-adora` on a product card (the /products listing), and
 *   - the same class on <body> for that product's own page (functions.php adds it), applied to
 *     <main> only, so the header, nav, footer and the IMRSNT field behind the page are untouched.
 * Values are each app's own docs/tokens.json (FormVault "Kept", Adora "On Shift"). The plate
 * surface is the app's warm background, which is what makes the card read as the app. Hover and
 * line/tint colours are derived; Adora's tint is lightened to #EDF6F6 so its teal tags pass AA.
 * The display variables are set twice because WordPress's own heading styles read the preset
 * variable directly, while this stylesheet reads --font-display, already resolved on :root. */
/* THE BRAND FONT, SELF-HOSTED (2026-11-02). theme.json names Quicksand first, but no file shipped,
   so every visitor without it installed read Trebuchet MS. One variable file covers every weight the
   site uses (Latin, 28KB, @fontsource-variable/quicksand 5.3.0, SIL OFL: OFL-Quicksand.txt). */
@font-face {
  font-family: "Quicksand"; font-style: normal; font-weight: 300 700; font-display: swap;
  src: url("assets/fonts/Quicksand-latin-wght.woff2") format("woff2-variations"),
       url("assets/fonts/Quicksand-latin-wght.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins"; font-weight: 700; font-style: normal; font-display: swap;
  src: local("Poppins Bold"), local("Poppins-Bold"), url("assets/fonts/Poppins-Bold.ttf") format("truetype");
}
@font-face {
  font-family: "Poppins"; font-weight: 600; font-style: normal; font-display: swap;
  src: local("Poppins SemiBold"), local("Poppins-SemiBold"), url("assets/fonts/Poppins-SemiBold.ttf") format("truetype");
}
.product.brand-formvault,
body.brand-formvault main {
  --color-primary: #1F6F5C;
  --color-brand-deep: #175546;
  --color-secondary: #A85A16;
  --accent: #A85A16;
  --accent-deep: #A85A16;
  --color-surface: #FBF7F1;
  --color-background: #FFFFFF;
  --color-ink: #24211E;
  --color-muted: #6B6257;
  --line: #E8DFD2;
  --tint: #E4EFEA;
  --quiet-border: #CDBFAE;
  --radius: 14px;
  --shadow: 0 2px 4px rgba(36, 33, 30, 0.05), 0 12px 28px rgba(36, 33, 30, 0.08);
  --font-display: "Poppins", "Segoe UI", system-ui, sans-serif;
  --wp--preset--font-family--display: "Poppins", "Segoe UI", system-ui, sans-serif;
}
/* Adora wears its "Signal" direction (docs/design-options.json in forge-adora), not the chosen
   "On Shift" teal: On Shift sat too close to FormVault's warm green to show how far apart two
   products can look. To go back, use On Shift's values: primary #0E7C7B, deep #0A5F5E, secondary
   #E8A33D, surface #FBF7F0, ink #26323A, muted #5F6C73, line #E6DFD3, tint #EDF6F6, quiet border
   #C9C2B6, radius 12px, display "Sora". Signal's coral fails as text (2.6:1), so it is only ever
   the decorative rule under the product name. Space Grotesk is not bundled anywhere, so it falls
   back to a system face where it is not installed. */
.product.brand-adora,
body.brand-adora main {
  --color-primary: #1B1F3B;
  --color-brand-deep: #343A6B;
  --color-secondary: #FF6B4A;
  --accent: #FF6B4A;
  --accent-deep: #FF6B4A;
  --color-surface: #F6F5FB;
  --color-background: #FFFFFF;
  --color-ink: #14162B;
  --color-muted: #6A6C85;
  --line: #E3E1EF;
  --tint: #E9E8F4;
  --quiet-border: #C9C7DC;
  --radius: 10px;
  --shadow: 0 2px 4px rgba(20, 22, 43, 0.05), 0 12px 28px rgba(20, 22, 43, 0.09);
  --font-display: "Space Grotesk", "Segoe UI", system-ui, sans-serif;
  --wp--preset--font-family--display: "Space Grotesk", "Segoe UI", system-ui, sans-serif;
}
/* Headings inside a scope take the app's display face even where a rule names the WordPress
   preset rather than --font-display. */
.product.brand-formvault :is(h1, h2, h3), body.brand-formvault main :is(h1, h2, h3),
.product.brand-adora :is(h1, h2, h3), body.brand-adora main :is(h1, h2, h3) { font-family: var(--font-display); color: var(--color-ink); }
/* The app's own accent, used the way the app uses it: a thin rule under the product's name. */
/* The closing panel's sub-line goes full white on an app's own colour, where the site's pale blue
   would fall under 4.5:1. */
body.brand-formvault main .product-head h1::after,
body.brand-adora main .product-head h1::after {
  content: ""; display: block; width: 40px; height: 3px; border-radius: 2px;
  background: var(--color-secondary); margin: 12px auto 0;
}

/* Engineer profiles. Sample content for now; the monogram stands in for a photo. */
.profiles {
  max-width: var(--plate); margin: 0 auto;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap);
}
.profile {
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px;
  display: flex; flex-direction: column;
}
.profile-top { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }
.profile .avatar {
  flex: none; width: 52px; height: 52px; border-radius: 50%;
  background: var(--tint); color: var(--color-primary);
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 700; font-size: 17px;
}
.profile h3 { font-size: 17px; margin: 0; }
.profile .profile-meta { font-size: 13px; color: var(--color-muted); margin: 2px 0 0; }
.profile p { font-size: 14px; line-height: 1.65; color: var(--color-muted); margin: 0 0 12px; }
.profile .sectors { font-size: 13px; }
.profile .sectors strong { color: var(--color-ink); }
.tags { list-style: none; padding: 0; margin: auto 0 0; display: flex; flex-wrap: wrap; gap: 6px; }
.tags li {
  font-size: 12px; font-weight: 700; padding: 4px 10px; border-radius: 999px;
  background: var(--tint); color: var(--color-primary);
}

/* --------------------------------------------------------------- clients */

/* A plate like every other block (face lift, 2026-11-02), no longer a full-bleed white band: the
   band was the one block on the site that ran edge to edge, and on Clients it sat oddly between
   two floating plates. */
.clients-band {
  max-width: var(--plate); margin: 0 auto;
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 32px 40px 36px;
  text-align: center;
}
.clients-band h2 { font-size: 26px; margin: 0 0 8px; }
.clients-band p { font-size: 15px; color: var(--color-muted); margin: 0 0 24px; }

.names {
  list-style: none; margin: 0 auto; padding: 0;
  display: flex; flex-wrap: wrap; gap: 12px; justify-content: center;
  max-width: var(--plate);
}
/* A SECTOR MARK, NEVER A LOGO (QUEST-023 round 2, US-004 out-of-scope line unchanged).
   Each badge carries a small drawn glyph for the sector the organisation is in — asset
   management, banking, higher education, telematics, property. They are ours, drawn in this
   theme's own stroke weight and recoloured from the tokens; none of the five organisations'
   own marks appears anywhere on this site, and none may be added without the permission
   US-004 says we do not have. */
.names li {
  background: var(--color-background);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 10px 20px;
  display: flex; align-items: center; gap: 10px;
}
.names li .sector {
  width: 22px; height: 22px; flex: 0 0 22px;
  color: var(--color-primary);
}
.names li .who {
  font-family: var(--font-display); font-weight: 600; font-size: 15px;
}
.names li .sector-name {
  font-family: var(--font-body); font-weight: 400; font-size: 13px;
  color: var(--color-muted);
}

/* ------------------------------------------------------------ prose bits */

/* `.prose` IS A PANEL NOW (QUEST-023 round 2). Two reasons, and both come from the client:
   it is 16px body copy with nothing but the brand field behind it, which AC7 says must sit on an
   opaque surface; and "integrated into the page design, not dropped in as standalone pictures"
   needs something for a figure to be integrated INTO. A bare 760px column had neither. */
.prose {
  max-width: var(--plate); margin: 0 auto;
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  /* The wide side inset keeps the line near 100 characters now the plate matches the rest. */
  padding: 40px 64px;
}
/* The panel's padding stops the first heading's 32px top margin collapsing out of the box, which
   would otherwise open a 64px gap at the top of every prose page. TC-041 measures the rhythm
   between two MID-document headings, which this does not touch. */
.prose > :first-child { margin-top: 0; }
.prose > :last-child { margin-bottom: 0; }
.prose p { font-size: 16px; line-height: 1.75; color: var(--color-ink); margin: 0 0 20px; }
.prose h2 { font-size: 26px; margin: 32px 0 12px; }
.prose h3 { font-size: 19px; margin: 24px 0 8px; }
.prose ul { padding-left: 22px; margin: 0 0 20px; }
.prose li { margin-bottom: 8px; color: var(--color-ink); }

.panel {
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 28px;
}

/* ABOUT (face lift, client 2026-11-02). One column of plates at one even gap: the facts strip, the
   navy mission statement, who we are beside the four kinds of specialist, how we work in three
   numbered principles, where we are beside the offices graphic, then the two calls to action. */
.section.about {
  display: flex; flex-direction: column; gap: var(--gap);
}
.section.about > * { width: 100%; max-width: var(--plate); margin: 0 auto; }

.facts {
  list-style: none; padding: 0; max-width: var(--plate); margin: 0 auto;
  display: grid; grid-template-columns: repeat(4, 1fr);
  background: var(--color-surface);
  border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow);
  overflow: hidden;
}
.facts li { padding: 26px 22px 24px; text-align: center; border-left: 1px solid var(--line); position: relative; }
.facts li:first-child { border-left: 0; }
/* A short bar of the graphics' supporting hues tops each figure, in the order the drawings use them. */
.facts li::before {
  content: ""; position: absolute; top: 0; left: 50%; width: 40px; height: 4px; margin-left: -20px;
  border-radius: 0 0 3px 3px; background: var(--wp--preset--color--teal);
}
.facts li:nth-child(2)::before { background: var(--color-primary); }
.facts li:nth-child(3)::before { background: var(--wp--preset--color--violet); }
.facts li:nth-child(4)::before { background: var(--accent); }
.facts .fact-value {
  display: block;
  font-family: var(--font-display); font-weight: 700; font-size: 38px; line-height: 1.1;
  color: var(--accent-deep); margin-bottom: 6px;
}
.facts .fact-label { font-size: 14px; color: var(--color-muted); }

.mission {
  position: relative; overflow: hidden;
  background: var(--accent-deep); color: #FFFFFF;
  border-radius: var(--radius); box-shadow: 0 12px 32px rgba(11, 46, 74, 0.22);
  padding: 44px 56px 40px;
}
/* A quiet ring in the corner, the hero band's motif at its faintest. */
.mission::after {
  content: ""; position: absolute; right: -90px; top: -90px; width: 280px; height: 280px;
  border-radius: 50%; border: 36px solid rgba(56, 189, 240, 0.08); pointer-events: none;
}
.mission h2 {
  font-size: 14px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--accent); margin: 0 0 18px;
}
.mission blockquote { margin: 0; display: grid; grid-template-columns: 40px 1fr; gap: 16px; align-items: start; }
.mission .mark { width: 40px; height: 40px; color: var(--accent); }
.mission blockquote p {
  font-family: var(--font-display); font-weight: 700; font-size: 28px; line-height: 1.35;
  color: #FFFFFF; margin: 0; max-width: 760px;
}
.mission .mission-note {
  font-size: 16px; line-height: 1.7; color: #C9DCE8;
  margin: 22px 0 0 56px; padding-top: 20px; border-top: 1px solid rgba(255, 255, 255, 0.14); max-width: 700px;
}

.card.about-split {
  display: grid; grid-template-columns: 1fr 1fr; gap: 48px; align-items: center; padding: 40px 44px;
}
.about-split h2, .principles h2 { font-size: 26px; margin: 0 0 14px; }
.card.about-split .about-copy p { font-size: 16px; line-height: 1.75; color: var(--color-ink); margin: 0 0 16px; }
.card.about-split .about-copy p:last-child { margin-bottom: 0; }

.roles { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.roles li {
  display: grid; grid-template-columns: 44px 1fr; gap: 14px; align-items: center;
  padding: 12px 14px; border-radius: 12px; background: var(--color-background);
}
.roles .ic {
  width: 44px; height: 44px; border-radius: 12px; margin: 0;
  background: var(--tint); color: var(--color-primary);
  display: flex; align-items: center; justify-content: center;
}
.roles li:nth-child(1) .ic { background: var(--wp--preset--color--teal-tint); color: var(--wp--preset--color--teal); }
.roles li:nth-child(3) .ic { background: var(--wp--preset--color--violet-tint); color: var(--wp--preset--color--violet); }
.roles .ic svg { width: 22px; height: 22px; }
.roles strong { display: block; font-family: var(--font-display); font-size: 16px; color: var(--color-ink); }
.roles li > span:last-child > span { display: block; font-size: 14px; line-height: 1.5; color: var(--color-muted); }

.card.principles { padding: 40px 44px; }
.principles ol { list-style: none; margin: 8px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; }
.principles li { border-top: 1px solid var(--line); padding-top: 22px; }
.principles .n {
  width: 34px; height: 34px; border-radius: 50%;
  background: var(--accent-deep); color: #FFFFFF; box-shadow: 0 0 0 2px #FFFFFF, 0 2px 6px rgba(11, 46, 74, 0.28);
  font-family: var(--font-display); font-size: 15px; font-weight: 700;
  display: flex; align-items: center; justify-content: center; margin: 0 0 16px 3px;
}
.principles h3 { font-size: 18px; margin: 0 0 8px; }
.card.principles p { font-size: 15px; line-height: 1.7; margin: 0; }
.card.principles .principles-lede { font-size: 17px; color: var(--color-ink); max-width: 70ch; margin: 0 0 28px; }

.offices { list-style: none; margin: 20px 0 0; padding: 0; display: grid; gap: 10px; }
.offices li {
  display: grid; grid-template-columns: 12px 1fr auto; gap: 14px; align-items: center;
  padding: 12px 16px; border: 1px solid var(--line); border-radius: 12px;
}
.offices li::before { content: ""; width: 12px; height: 12px; border-radius: 50%; background: var(--color-primary); }
.offices li:nth-child(2)::before { background: var(--wp--preset--color--teal); }
.offices li:nth-child(3)::before { background: var(--wp--preset--color--violet); }
.offices li:first-child { background: var(--tint); border-color: transparent; }
.offices strong { font-family: var(--font-display); font-size: 16px; color: var(--color-ink); }
.offices span { font-size: 14px; color: var(--color-muted); }
.about-fig { margin: 0; }
.about-fig .fig-art { max-width: 460px; }

/* --------------------------------------------------------- drawn figures */

/* `.about-art` is gone with the image it framed (QUEST-023 round 1) and is not coming back: it
   rendered a fictional company's homepage and six third-party logos. What replaces it is not
   another file — it is the figure system below.
 *
 * EVERY FIGURE ON THIS SITE IS DRAWN IN THIS PROJECT, INLINE, AND RECOLOURS FROM THE TOKENS.
 * The client asked for more imagery, and for imagery that "makes sense based on what we do"
 * (QUEST-023, option B). A photograph of a torus does not depict integration; four feeds becoming
 * one line does. So the figures are authored here in the site's own visual language — the same
 * 2px stroke, the same radius, the same palette as the 24px glyphs already on every card, scaled
 * up into real figures.
 *
 * Inline SVG rather than files, deliberately: nothing to licence, no third party's marks anywhere
 * near them by construction, no download on the largest-contentful-paint path, crisp at any
 * density, and — the reason the classes below exist instead of hard-coded hexes — they recolour
 * from theme.json. Change a palette entry and the figures change with it, instead of becoming the
 * one stale thing on the page.
 *
 * EVERY FIGURE LIVES INSIDE A BLOCK IT ILLUSTRATES (US-010 AC6): a `.card`, a `.service`, a
 * `.prose` panel or a `.names` badge. There is no standalone picture on this site.
 *
 * They are `aria-hidden` and carry no caption. Each one restates the paragraph it sits with, so
 * announcing it again would read the same sentence twice to a screen-reader user; the prose is
 * the accessible version and is never the thing that gets cut. */
.fig { margin: 0 0 18px; }
.fig-art {
  display: block;
  width: 100%;
  /* Capped so the 330-unit viewBox never scales up far past 1:1 in a two-column card grid —
     past that the 15-unit labels inside start reading as headings. The floor matters more than
     the ceiling: at 375px a card is ~279px wide, so a label still renders at ~12.7px. */
  max-width: 380px;
  height: auto;
  margin: 0 auto;
}
.prose .fig-art { max-width: 440px; }

.fig-art .f-line  { fill: none; stroke: var(--color-primary); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* Text inside a figure: the default face and colour; each label sets its own size inline. */
.fig-art text     { font-family: var(--font-body); font-size: 15px; fill: var(--color-muted); }

/* ---------------------------------------------------- solutions list/grid */

.service {
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 24px;
  scroll-margin-top: 90px;
}
.service .ic {
  width: 48px; height: 48px; border-radius: 12px;
  background: var(--tint); color: var(--color-primary);
  display: flex; align-items: center; justify-content: center; margin-bottom: 16px;
}
.service .ic svg { width: 24px; height: 24px; }
.service h3 { font-size: 19px; margin: 0 0 8px; }
.service p { font-size: 14px; line-height: 1.7; color: var(--color-muted); margin: 0; }

/* SOLUTIONS: ONE SERVICE PER ROW (client, 2026-11-02). Each card runs the full plate width, copy on
   one side and its isometric graphic on the other, alternating sides down the page. The outcome
   that used to be a pill inside each graphic is a line in the copy: a teal tick and the result. */
.cards.services { grid-template-columns: 1fr; gap: var(--gap); }
.cards.services .service {
  display: grid; grid-template-columns: 1fr 1.05fr; gap: 40px; align-items: center; padding: 36px 40px;
}
.cards.services .service:nth-child(even) .svc-copy { order: 2; }
.service h2 { font-size: 26px; margin: 0 0 12px; }
.cards.services .service p { font-size: 15px; }
.service .outcome {
  display: flex; align-items: center; gap: 10px; margin-top: 18px;
  font-family: var(--font-display); font-weight: 700; font-size: 15px; color: var(--color-ink);
}
.service .outcome .tick {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  background: var(--wp--preset--color--teal); color: #FFFFFF;
  display: flex; align-items: center; justify-content: center;
}
.service .outcome .tick svg { width: 14px; height: 14px; }
/* CALLS TO ACTION READ AS SUCH (client, 2026-11-02). The heading, its line and the button share one
   panel instead of the button floating under a heading card. .cta is the supporting kind (tint
   panel, primary button); .cta-strong closes a page (white card over the footer edge, filled button) and is its one main
   action. The button text stays the brand blue on white, 5.6:1. */
.cta {
  max-width: var(--plate); margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 32px;
  padding: 32px 40px;
  background: var(--color-surface) linear-gradient(120deg, var(--tint), var(--color-surface) 70%);
  border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
/* A CTA straight after another section closes up to the site's usual gap between plates. */
.cta h2 { font-size: 24px; margin: 0 0 6px; }
.cta p { font-size: 15px; line-height: 1.65; color: var(--color-muted); margin: 0; max-width: 560px; }
.cta .btn { flex: none; }
.cta-actions { flex: none; display: flex; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }
/* THE PAGE'S CLOSING CARD BRIDGES THE PAGE AND THE FOOTER (client's pick, concept C, 2026-11-02).
   A white card half over the light page and half over the dark footer, its deep shadow carrying it
   across the edge, so the overlap reads as intended rather than as a navy slab that stopped short.
   The faint ring in its corner is the brand blue at a whisper. Its button is the filled primary in
   every case, including Home's, which is .quiet by class because Home keeps one primary (TC-003). */
.cta-strong {
  position: relative; overflow: hidden;
  background: var(--color-surface); border: 1px solid var(--line);
  box-shadow: 0 18px 40px rgba(11, 46, 74, 0.26), 0 2px 6px rgba(11, 46, 74, 0.08);
}
.cta-strong::after {
  content: ""; position: absolute; right: -80px; bottom: -120px; width: 260px; height: 260px;
  border-radius: 50%; border: 34px solid rgba(0, 107, 161, 0.05); pointer-events: none;
}
.cta-strong > * { position: relative; z-index: 1; }
.cta-strong h2 { color: var(--color-ink); }
.cta-strong p { color: var(--color-muted); }
.cta-strong > .btn.quiet { background: var(--color-primary); color: #FFFFFF; border-color: var(--color-primary); }
.cta-strong > .btn.quiet:hover { background: var(--color-brand-deep); border-color: var(--color-brand-deep); }

/* A card of two halves divided by a hairline, each an icon, a heading and its copy (FormVault's and
   Adora's "private by design" and "what it works with"). */
.card.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 0; padding: 0; max-width: var(--plate); margin: 0 auto; }
.card.pair.solo { grid-template-columns: 1fr; }
.pair > div { padding: 36px 40px; }
.pair > div + div { border-left: 1px solid var(--line); }
.pair .ic { margin-bottom: 16px; }
.pair h2 { font-size: 22px; margin: 0 0 10px; }
.card.pair p { font-size: 15px; line-height: 1.7; margin: 0 0 12px; }
.card.pair p:last-child { margin-bottom: 0; }

/* HOME: how an engagement runs, one card under the hero (client, 2026-11-02). The isometric stages run
   left to right across the full card, and the four steps sit in equal columns beneath, each centred
   under its stage (the drawing's stage centres are at 12.5 / 37.5 / 62.5 / 87.5 % of its width, so
   the columns carry no gap between them, only inner padding). */
.card.engage { max-width: var(--plate); margin: 0 auto; padding: 36px 32px 32px; }
.engage-head { text-align: center; }
.engage-head h2 { font-size: 28px; margin: 0 0 8px; }
.engage-head h2::after {
  content: ""; display: block; width: 48px; height: 3px; border-radius: 2px;
  background: linear-gradient(90deg, var(--accent-deep), var(--accent)); margin: 12px auto 0;
}
.card.engage .engage-head p { font-size: 15px; color: var(--color-muted); margin: 0; }
.engage-fig { margin: 8px 0 0; }
.engage-fig .fig-art { max-width: none; width: 100%; }
.engage-steps { list-style: none; margin: 4px 0 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); }
.engage-steps li { text-align: center; padding: 0 14px; }
.engage-steps .step-n {
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent-deep); color: #FFFFFF; box-shadow: 0 0 0 2px #FFFFFF, 0 2px 6px rgba(11, 46, 74, 0.28);
  font-family: var(--font-display); font-weight: 700; font-size: 14px; margin-bottom: 12px;
}
.engage-steps h3 { font-size: 17px; margin: 0 0 6px; }
.card.engage .engage-steps p { font-size: 14px; line-height: 1.6; color: var(--color-muted); margin: 0; }

/* HOME: our own products, a card with the copy on one side and FormVault's phone on the other. */
.card.showcase {
  display: grid; grid-template-columns: 1.3fr 1fr; gap: 40px; align-items: center;
  max-width: var(--plate); margin: 0 auto; padding: 40px 44px; overflow: hidden;
  background: var(--color-surface) linear-gradient(115deg, var(--color-surface) 55%, var(--tint));
}
.showcase h2 { font-size: 26px; margin: 0 0 12px; }
.card.showcase p { font-size: 16px; line-height: 1.7; color: var(--color-ink); margin: 0 0 18px; }
.showcase .app-line { display: flex; align-items: center; gap: 14px; margin: 0 0 22px; }
.showcase .app-line .app-icon { width: 52px; height: 52px; border-radius: 14px; }
.showcase .app-line strong { display: block; font-family: var(--font-display); font-size: 17px; color: var(--color-ink); }
.showcase .app-line span { font-size: 14px; color: var(--color-muted); }
.showcase .device { max-width: 210px; margin-bottom: -96px; }
.showcase .stage { align-self: stretch; display: flex; align-items: flex-start; justify-content: center; padding-top: 4px; }

.svc-fig { margin: 0; }
.svc-fig .fig-art { width: 100%; max-width: 520px; height: auto; margin: 0 auto; display: block; }
.fig-art .k-muted { fill: var(--color-muted); } .fig-art .s-line { stroke: var(--line); }
.fig-art .s-surface { stroke: var(--color-surface); }

/* ------------------------------------------------- the sections added 2026-11-02 */

/* Contact: what happens after you write, three numbered steps. */
.steps.three { grid-template-columns: repeat(3, 1fr); }

/* Contact: the FAQ, native <details> rows (no script, keyboard and screen-reader ready). */
.card.faq { max-width: var(--plate); margin: 0 auto; padding: 6px 36px; }
.faq details { border-top: 1px solid var(--line); }
.faq details:first-child { border-top: 0; }
.faq summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 20px 0; font-family: var(--font-display); font-weight: 700; font-size: 17px; color: var(--color-ink);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: ""; flex: none; width: 10px; height: 10px; margin-right: 4px;
  border-right: 2px solid var(--color-primary); border-bottom: 2px solid var(--color-primary);
  transform: rotate(45deg) translate(-2px, -2px); transition: transform 0.15s ease;
}
.faq details[open] summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.faq summary:hover { color: var(--color-primary); }
.faq summary:focus-visible { outline: 3px solid var(--color-secondary); outline-offset: 4px; border-radius: 4px; }
.card.faq details p { font-size: 15px; line-height: 1.7; color: var(--color-muted); margin: 0 0 20px; max-width: 760px; }

/* Solutions: ways to work with us. */
.card.way .best {
  display: flex; align-items: flex-start; gap: 8px; margin: auto 0 0; padding-top: 14px; border-top: 1px solid var(--line);
  font-size: 14px; font-weight: 700; color: var(--color-ink);
}
.card.way .best svg { flex: none; width: 16px; height: 16px; margin-top: 2px; color: var(--wp--preset--color--teal); }

/* Solutions: the platforms we work in. */
.card.platforms {
  max-width: var(--plate); margin: 0 auto; padding: 36px 40px;
  display: grid; grid-template-columns: 1fr 1.7fr; gap: 40px; align-items: start;
}
.platforms h2 { font-size: 24px; margin: 0 0 10px; }
.card.platforms .platforms-head p { font-size: 15px; margin: 0; }
.platforms-list { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
.platforms-list h3 {
  font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-muted); margin: 0 0 12px;
}
.platforms-list ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.platforms-list li { display: flex; align-items: flex-start; gap: 8px; font-size: 15px; color: var(--color-ink); }
.platforms-list li svg { flex: none; width: 16px; height: 16px; margin-top: 3px; color: var(--wp--preset--color--teal); }


/* About: careers. */
.card.careers {
  display: grid; grid-template-columns: 1.1fr 1fr; gap: 40px; align-items: start; padding: 40px 44px;
  scroll-margin-top: 96px;
}
.careers h2 { font-size: 26px; margin: 0 0 12px; }
.card.careers .careers-copy p { font-size: 16px; line-height: 1.75; color: var(--color-ink); margin: 0 0 20px; }
.careers-roles { background: var(--color-background); border-radius: 12px; padding: 22px 24px; }
.careers-roles h3 { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-muted); margin: 0 0 12px; }
.careers-roles ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.careers-roles strong { display: block; font-family: var(--font-display); font-size: 15px; color: var(--color-ink); }
.careers-roles span { font-size: 14px; color: var(--color-muted); }

/* ------------------------------------------------------------------ form */

.contact-grid {
  display: grid; grid-template-columns: 1.3fr 1fr; gap: var(--gap);
  max-width: var(--plate); margin: 0 auto; align-items: start;
}

.field { margin-bottom: 20px; }
.field label { display: block; font-weight: 700; font-size: 14px; margin-bottom: 6px; }
.field .hint { display: block; font-weight: 400; font-size: 13px; color: var(--color-muted); }
.field input,
.field textarea {
  width: 100%;
  font-family: var(--font-body); font-size: 16px; color: var(--color-ink);
  background: var(--color-surface);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  padding: 12px 14px;
  min-height: 48px;
}
.field textarea { min-height: 140px; resize: vertical; }
.field input:hover, .field textarea:hover { border-color: var(--quiet-border); }
.field .error {
  display: none;
  margin: 6px 0 0; font-size: 13px; font-weight: 700; color: var(--color-brand-deep);
}
.field.invalid input, .field.invalid textarea { border-color: var(--color-brand-deep); }
.field.invalid .error { display: block; }

.form-summary {
  display: none;
  margin: 0 0 20px; padding: 14px 18px;
  border: 2px solid var(--color-brand-deep); border-radius: var(--radius);
  background: var(--tint); color: var(--color-brand-deep);
  font-size: 14px; font-weight: 700;
}
.form-summary.show { display: block; }

.handoff { display: none; }
.handoff.show { display: block; }
.handoff h2 { font-size: 26px; margin: 0 0 12px; }
.handoff ul { list-style: none; padding: 0; margin: 0 0 20px; }
.handoff li {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: 15px; color: var(--color-ink); margin-bottom: 10px;
}
.handoff li svg { width: 20px; height: 20px; color: var(--color-primary); flex: 0 0 20px; margin-top: 2px; }

.aside-card { background: var(--color-surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 24px; }
.aside-card h2 { font-size: 19px; margin: 0 0 8px; }
.aside-card p { font-size: 14px; color: var(--color-muted); margin: 0 0 16px; line-height: 1.7; }
.aside-card ul { list-style: none; margin: 0; padding: 0; }
.aside-card li { font-size: 14px; margin-bottom: 6px; }
/* Contact's side panel: its three answers divided by hairlines; the offices read like About's list. */
.aside-card { padding: 28px; }
.aside-card h2 + p, .aside-card h2 + ul { margin-bottom: 0; }
.aside-card h2:not(:first-child) { margin-top: 22px; padding-top: 22px; border-top: 1px solid var(--line); }
.aside-card ul.offices { margin-top: 12px; gap: 8px; }
.aside-card .offices li { margin: 0; padding: 10px 14px; }

/* ---------------------------------------------------------------- footer */

/* THE FOOTER JOINS THE NEW LOOK (client, 2026-11-02). It stays the site's one dark brand surface
   (background-color #005A87, TC-005) but runs from that blue into the navy the closing panels use,
   with the isometric floor grid over it and one outlined scene in the bottom-right corner, sources,
   warehouse and dashboard rising toward the corner (tools/build-page-bands.py footer_scene). */
/* Thinner since concept C. The floor grid is the header's own tile at the header's scale (69.3 x 40),
   repeated, not a drawing stretched to fit; the see-through blocks are scattered across it as in the
   header (footer-far.svg, drawn at the footer's height); the corner scene sits clear of the line
   above the copyright. */
footer.site {
  position: relative; color: #FFFFFF; margin-top: calc(2 * var(--gap));
  background: linear-gradient(to bottom, #005A87 0, rgba(0, 90, 135, 0) 120px),
    url("assets/bands/footer-scene.svg") right max(12px, calc(50% - 640px)) bottom 66px / 300px auto no-repeat,
    url("assets/bands/footer-far.svg") center / auto 100% no-repeat,
    url("assets/bands/footer-grid-tile.svg") 0 0 / 69.282px 40px repeat,
    linear-gradient(to bottom, var(--color-brand-deep) 0%, var(--accent-deep) 100%);
  background-color: var(--color-brand-deep);
}
/* A page that closes on the navy panel lets it ride over the footer's top edge, so the page runs
   into the footer instead of stopping above it. */
body:has(main .entry-content > .section:last-child > .cta-strong) footer.site { margin-top: -84px; padding-top: 84px; }
main .entry-content > .section:last-child:has(> .cta-strong) { position: relative; z-index: 3; }
/* Between a tablet and a small laptop the last column reaches the corner, so the scene shrinks. */
@media (min-width: 721px) and (max-width: 1180px) {
  footer.site { background-size: auto, 250px auto, auto 100%, 69.282px 40px, auto;
    background-position: 0 0, right 10px bottom 60px, center, 0 0, 0 0; }
}
footer.site nav a { text-decoration: none; }
footer.site nav a:hover { text-decoration: underline; }
footer.site .wrap.foot-base { display: block; padding-top: 12px; padding-bottom: 14px; border-top: 1px solid rgba(255, 255, 255, 0.12); }
footer.site .foot-base p { font-size: 12px; }
footer.site .wrap {
  display: grid; grid-template-columns: 1.3fr 1fr 1fr 1fr; gap: 32px;
  padding-top: 34px; padding-bottom: 26px;
}
footer.site img { height: 32px; width: auto; margin-bottom: 8px; }
footer.site p { font-size: 13px; line-height: 1.75; color: var(--footer-text); margin: 0; }
footer.site a { color: #FFFFFF; }
footer.site h2 {
  font-size: 13px; font-weight: 700; letter-spacing: 0.06em;
  margin: 0 0 8px; text-transform: uppercase;
}
footer.site ul { list-style: none; margin: 0; padding: 0; }
footer.site li { font-size: 13px; line-height: 1.75; }
footer.site .foot-link {
  display: inline-flex; align-items: center; min-height: 44px;
}

/* ------------------------------------------------------- consent banner */

.consent {
  position: fixed; z-index: 50;
  left: 16px; right: 16px; bottom: 16px;
  max-width: 1100px; margin: 0 auto;
  background: var(--color-surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 24px;
  display: flex; align-items: center; gap: 20px;
}
.consent[hidden] { display: none; }
.consent p { margin: 0; flex: 1; font-size: 13px; line-height: 1.6; color: var(--color-muted); }
.consent a { color: var(--color-primary); font-weight: 700; }
.consent .consent-btn {
  font-family: var(--font-body); font-size: 14px; font-weight: 700;
  min-height: 44px; padding: 0 24px;
  border-radius: 999px; border: 2px solid transparent; cursor: pointer;
  display: inline-flex; align-items: center;
}
.consent .consent-btn.accept { background: var(--color-primary); color: #FFFFFF; }
.consent .consent-btn.accept:hover { background: var(--color-brand-deep); }
.consent .consent-btn.decline {
  background: none; color: var(--color-primary); border-color: var(--quiet-border);
}

/* ============================================================ responsive */

/* Narrower desktops: the heading spans more of the card, so the corners shrink to stay clear. */

@media (max-width: 1023px) {
  :root { --gutter: 24px; }

  nav.main {
    position: fixed; top: 0; right: 0; bottom: 0; z-index: 50;
    width: min(320px, 86vw);
    background: var(--color-surface);
    border-left: 1px solid var(--line);
    padding: 76px 20px 24px;
    transform: translateX(100%);
    transition: transform 0.2s ease;
    overflow-y: auto;
  }
  body.nav-open nav.main { transform: translateX(0); }
  nav.main ul { flex-direction: column; align-items: stretch; gap: 4px; }
  nav.main a { font-size: 17px; padding: 12px 16px; min-height: 48px; border-radius: var(--radius); }
  nav.main .drawer-cta { display: inline-flex; margin-top: 16px; width: 100%; }

  .nav-toggle { display: inline-flex; }

  .cards { grid-template-columns: repeat(2, 1fr); }
  .cards.services { grid-template-columns: 1fr; }
  .cards.services .service { gap: 28px; padding: 28px; }
  .prose { padding: 32px 36px; }
  .steps, .profiles, .shots { grid-template-columns: repeat(2, 1fr); }
  .card.overview { grid-template-columns: 1fr; gap: 24px; }
  .overview-fig .fig-art { margin: 0 auto; }
  .product { grid-template-columns: 1fr 200px; gap: 28px; padding: 28px; }
  .facts { grid-template-columns: repeat(2, 1fr); }
  .facts li:nth-child(3) { border-left: 0; }
  .facts li:nth-child(n+3) { border-top: 1px solid var(--line); }
  .card.about-split { grid-template-columns: 1fr; gap: 28px; padding: 32px 36px; }
  .card.principles { padding: 32px 36px; }
  .mission { padding: 36px 40px 32px; }
  .card.showcase { grid-template-columns: 1fr; gap: 28px; padding: 32px 36px 0; }
  .card.platforms, .card.careers { grid-template-columns: 1fr; gap: 24px; padding: 32px 36px; }
  .steps.three { grid-template-columns: 1fr; }
  .showcase .device { margin-bottom: -120px; }
  .showcase .stage { max-height: 300px; }
  .shots { padding: 28px 24px 24px; }
  .contact-grid { grid-template-columns: 1fr; }
  footer.site .wrap { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 720px) {
  .hero {
    background-image: linear-gradient(to bottom, rgba(255, 255, 255, 0) 82%, #FFFFFF 100%), url("assets/hero-band-portrait.svg");
    background-size: auto, cover; background-position: 0 0, center;
    padding: 150px var(--gutter) 230px;
  }
  .hero::after { height: 110px; }
  .entry-content > .hero:first-child { padding-top: calc(150px + 77px); }
  body.home .logo-hero img { height: 80px; }
  h1 { font-size: 30px; }
  .page-head h1 { font-size: 28px; }
  .pill { font-size: 12px; margin-bottom: 14px; }
  .lede { font-size: 15px; margin-bottom: 20px; }
  .hero-actions { flex-direction: column; }
  .hero-actions .btn { width: 100%; }
  .btn { min-height: 48px; }

  /* The plates keep their surfaces (AC7 does not bend on a phone) and lose their inset, so a
     375px screen spends its width on the words rather than on padding. */
  /* The field's shapes live at its sides and corners; a phone's centre crop would show only the
     empty middle, so it is anchored to the left edge instead. */
  .page-backdrop img { object-position: left center; }
  .page-head { margin-top: 24px; padding: 24px 20px 22px; }
  .page-head:not(.product-head) { padding: calc(44px + 77px) var(--gutter) 110px; }
  .page-head[class*="band-"] { background-image: var(--band-fade), url("assets/bands/phone.svg"); background-size: auto, cover; }
  .page-head:not(.product-head)::after { height: 100px; }
  main .entry-content > .page-head:not(.product-head) + * { margin-top: -48px; }
  main .entry-content > .hero + .section { margin-top: -56px; }
  main .entry-content > .page-head:first-child { margin-top: 24px; }
  .section-head { padding: 20px 18px; }
  .prose { padding: 24px 20px; }

  .cards, .steps, .profiles { grid-template-columns: 1fr; }
  :root { --gap: 20px; }
  .facts li { padding: 22px 12px 18px; }
  .facts .fact-value { font-size: 30px; }
  .mission { padding: 28px 20px 24px; }
  .mission blockquote { grid-template-columns: 1fr; gap: 10px; }
  .mission .mark { width: 30px; height: 30px; }
  .mission blockquote p { font-size: 21px; }
  .mission .mission-note { margin-left: 0; font-size: 15px; }
  .card.about-split, .card.principles { padding: 24px 20px; }
  .principles ol { grid-template-columns: 1fr; gap: 20px; }
  .offices li { grid-template-columns: 12px 1fr; }
  .offices li span { grid-column: 2; margin-top: -10px; }
  .cards.services .service { grid-template-columns: 1fr; gap: 20px; padding: 24px 20px; }
  .cards.services .service:nth-child(even) .svc-copy { order: 0; }
  .cta { flex-direction: column; align-items: stretch; text-align: left; padding: 24px 20px; gap: 20px; }
  .cta .btn { width: 100%; justify-content: center; text-align: center; }
  .cta-actions { flex-direction: column; }
  .card.faq { padding: 4px 20px; }
  .faq summary { font-size: 16px; padding: 18px 0; }
  .card.platforms, .card.careers { padding: 24px 20px; }
  .platforms-list { grid-template-columns: 1fr; gap: 18px; }
  .card.engage { padding: 24px 16px 24px; }
  .engage-head h2 { font-size: 24px; }
  .engage-steps { grid-template-columns: 1fr 1fr; row-gap: 22px; margin-top: 12px; }
  .engage-steps li { padding: 0 8px; }
  .card.pair { grid-template-columns: 1fr; }
  .pair > div { padding: 24px 20px; }
  .pair > div + div { border-left: 0; border-top: 1px solid var(--line); }
  .card.showcase { padding: 24px 20px 0; }
  .clients-band { padding: 24px 20px 28px; }
  .shots { padding: 24px 16px 20px; gap: 24px 14px; }
  .shot figcaption { font-size: 13px; }
  .device { padding: 6px; border-radius: 26px; }
  .device > img, .device > .ph { border-radius: 20px; }
  .device::before { top: 11px; width: 7px; height: 7px; margin-left: -3.5px; }
  .product .device { max-width: 220px; }
  .product { grid-template-columns: 1fr; padding: 24px 20px; }
  .product .phone { max-width: 220px; margin: 0 auto; }
  .names { flex-direction: column; align-items: stretch; }
  .names li { justify-content: center; }

  footer.site .wrap { grid-template-columns: 1fr; }
  footer.site { background-size: auto, 230px auto, auto 100%, 69.282px 40px, auto;
    background-position: 0 0, right 8px bottom 104px, center, 0 0, 0 0; }
  footer.site .wrap.foot-base { padding-bottom: 20px; }

  .consent { flex-direction: column; align-items: stretch; text-align: left; }
  .consent .consent-btn { justify-content: center; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ------------------------------------------- additions, 2026-11-05 */

/* FormVault's five screens: five across on a laptop, three then two on a tablet, two on a phone
   with the fifth centred under them. */
.shots.five { grid-template-columns: repeat(5, 1fr); gap: 20px; padding: 32px 24px 26px; }
.shots.five .shot figcaption { font-size: 14px; }

/* ABOUT: how to say the name, and the B-BBEE level, side by side. */
.duo { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap); }
.duo .card { padding: 32px 36px; }
.duo h2 { font-size: 22px; margin: 0 0 12px; }
.duo .card p { font-size: 15px; color: var(--color-ink); }
.duo .btn { align-self: flex-start; margin-top: auto; }
.duo .say .say-word { font-family: var(--font-display); font-size: 40px; font-weight: 700; line-height: 1.1; color: var(--color-primary) !important; margin: 0 0 6px; }
.duo .say .say-phon { display: flex; flex-wrap: wrap; gap: 6px 14px; align-items: baseline; margin: 0 0 14px; }
.say .respell { font-family: var(--font-display); font-size: 20px; font-weight: 700; letter-spacing: 0.02em; color: var(--color-ink); }
.say .ipa { font-size: 16px; color: var(--color-muted); }
.say .syllables { font-size: 15px; color: var(--color-muted); }
.say-name svg { width: 20px; height: 20px; }
.say-name.playing svg { color: var(--accent); }
.duo .bbbee .level { display: inline-flex; align-items: baseline; gap: 8px; margin: 0 0 14px; padding: 6px 14px; border-radius: 999px; background: var(--color-brand-deep); color: #FFFFFF !important; align-self: flex-start; }
.bbbee .level span { font-size: 13px; font-weight: 700; letter-spacing: 0.06em; }
.bbbee .level strong { font-family: var(--font-display); font-size: 20px; }
.principles-more { margin: 28px 0 0; padding-top: 20px; border-top: 1px solid var(--line); font-size: 15px; color: var(--color-muted); }
.principles-more a { font-weight: 700; color: var(--color-primary); }

/* Each Solutions service ends with a link into the form, already about that service. */
.service .card-link {
  align-self: flex-start; margin-top: 12px; min-height: 44px;
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 14px; font-weight: 700; color: var(--color-primary); text-decoration: none;
}
.service .card-link:hover { text-decoration: underline; }
.service .card-link svg { width: 15px; height: 15px; }

/* The promises card on the AI page stands on its own, so it keeps to the plate width. */
.section > .card.principles { max-width: var(--plate); margin: 0 auto; }

/* The footer's "said Immersant" button sits under the logo, as quiet as the text around it. */
footer.site .foot-say {
  display: inline-flex; align-items: center; gap: 8px; margin: 0 0 10px; min-height: 36px;
  padding: 4px 12px 4px 8px; border-radius: 999px; cursor: pointer;
  font: 700 13px var(--font-body); color: #FFFFFF;
  background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.28);
}
footer.site .foot-say:hover { background: rgba(255, 255, 255, 0.16); }
footer.site .foot-say svg { width: 18px; height: 18px; }
footer.site .foot-say.playing svg { color: var(--accent); }

/* CONTACT: the topic and the optional details are dropdowns (client, 2026-11-05: chips read as
   clutter). The details sit two by two in one quiet group under the message. */
.field select {
  width: 100%; min-height: 48px; padding: 12px 44px 12px 14px;
  font-family: var(--font-body); font-size: 16px; color: var(--color-ink);
  background: var(--color-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23006BA1' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") right 14px center / 18px no-repeat;
  border: 2px solid var(--line); border-radius: var(--radius);
  appearance: none; -webkit-appearance: none; cursor: pointer;
}
.field select:hover { border-color: var(--quiet-border); }
fieldset.details { border: 0; border-top: 1px solid var(--line); margin: 4px 0 8px; padding: 20px 0 0; min-width: 0; }
.details legend { float: left; width: 100%; padding: 0; margin: 0 0 16px; font-weight: 700; font-size: 15px; }
.details legend .hint { display: inline; margin-left: 6px; font-weight: 400; font-size: 13px; color: var(--color-muted); }
.details-grid { clear: both; display: grid; grid-template-columns: 1fr 1fr; column-gap: 16px; }

@media (max-width: 1023px) {
  .shots.five { grid-template-columns: repeat(3, 1fr); }
  .duo { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .shots.five { grid-template-columns: repeat(2, 1fr); padding: 24px 16px 20px; gap: 24px 14px; }
  .shots.five .shot:last-child { grid-column: 1 / -1; width: 50%; justify-self: center; }
  .duo .card { padding: 24px 20px; }
  .duo .say .say-word { font-size: 34px; }
  .details-grid { grid-template-columns: 1fr; }
}
