/* The product website.
   Direction: enterprise datasheet. A cool tinted ground and a paper band carry
   the argument; one confident brand blue gives the page its spine (actions,
   links, section markers); seal red is held in reserve for risk, holds and
   rejections. Depth is a quiet ladder: ground, paper, raised card, dark accent
   band (hero, booking panel, footer) and one black artefact surface for real
   machine output. Rules group information; they are not an edge on every box.
   Mono is for machine evidence only. Sentence case everywhere; never all caps. */

/* ---------------------------------------------------------------------------
   1. Fonts. Self-hosted, no CDN, SIL Open Font License 1.1 (see
   assets/fonts/LICENCES.md). font-display is optional so a late font is never
   swapped in and cannot shift the layout.
   --------------------------------------------------------------------------- */

@font-face {
  font-family: "Archivo Variable";
  src: url("fonts/archivo-latin-wght-normal.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/plex-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: optional;
}

@font-face {
  font-family: "IBM Plex Mono";
  src: url("fonts/plex-mono-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: optional;
}

/* ---------------------------------------------------------------------------
   2. Tokens. The whole system is here: nothing below this block hardcodes a
   colour, a size or a spacing value. (The two exceptions are recorded where
   they occur: the select control's inline arrow, which cannot take a custom
   property inside a data URI, and the print block, which must be absolute.)
   --------------------------------------------------------------------------- */

:root {
  /* Colour. Surface ladder: ground, paper, card, dark band, artefact black.
     Text pairs and their measured WCAG 2.1 contrast ratios:
       ink #10171d on ground   15.81:1   on paper  18.07:1   on card  17.12:1
       ink-2 #24313a on ground 11.66:1   on paper  13.33:1
       slate #57646d on ground  5.33:1   on paper   6.09:1   on card   5.77:1
       brand #1749c4 on ground  6.59:1   on paper   7.54:1   on card   7.14:1
       seal #9a2b1f on ground   6.71:1   on paper   7.67:1   on seal-tint 6.47:1
       on-dark #eef2f7 on navy  15.49:1  on ink    16.07:1
       on-dark-muted #a3b4c6 on navy 8.21:1  on ink  8.52:1
       brand-on-dark #8fb0ff on navy 8.14:1
       on-brand #ffffff on brand 7.54:1  on brand-deep 9.88:1
       brand-deep #123a9e on brand-tint 8.52:1
     Non-text (WCAG 1.4.11, 3:1): rule-2 #7d8684 is 3.27:1 on the ground,
     3.74:1 on paper and 3.54:1 on the card fill, so a form field's boundary and
     the menu button's boundary count as perceivable components. The value before
     that fix was #9aa4a2 at 2.56:1 and 2.28:1. Do not lighten rule-2. */
  --ground: #edf0f4;
  --paper: #ffffff;
  --card: #f7f9fb;
  --ink: #10171d;
  --ink-2: #24313a;
  --slate: #57646d;
  --rule: #d8dee5;
  --rule-2: #7d8684;
  --brand: #1749c4;
  --brand-deep: #123a9e;
  --brand-tint: #e9eefc;
  --navy: #0c1a30;
  --seal: #9a2b1f;
  --seal-tint: #f6e9e6;
  --on-brand: #ffffff;
  --on-dark: #eef2f7;
  --on-dark-muted: #a3b4c6;
  --on-dark-rule: #2c3b52;
  --brand-on-dark: #8fb0ff;
  /* The proof-point tick on the dark band: #7fb894 on navy is 7.6:1. Added
   * because --ok (#1d6b3f) is a paper-side colour and fails on navy. */
  --ok-on-dark: #7fb894;

  /* Two objects hold one colour in both themes, because the dark design
     leaves them alone and both would otherwise flip to something unreadable:
     the call-to-action blue (white on #1749c4, 7.54:1; the review keeps the
     button's blue) and the artefact black behind exhibit code (--ink becomes
     light in dark and the exhibit would lose its surface). */
  --action: #1749c4;
  --action-deep: #123a9e;
  --artefact: #10171d;

  /* The browser's own surfaces follow the system setting as well. The theme
     is the reader's system setting and nothing else: no toggle, no script,
     no storage. */
  color-scheme: light dark;

  /* Type. Archivo Variable for language, IBM Plex Mono for machine evidence
     only: exhibit bodies, exhibit tables, code. Body is 18px on 1.7 for long
     reading; the display end is tighter and larger so the masthead reads as a
     product statement rather than a heading in a document. */
  --font-sans: "Archivo Variable", Archivo, ui-sans-serif, system-ui,
    "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "Cascadia Mono", Consolas,
    monospace;

  --fs-display: clamp(2.5rem, 5.4vw, 3.625rem);
  --fs-h2: clamp(1.625rem, 3vw, 2.25rem);
  --fs-h3: clamp(1.1875rem, 2vw, 1.375rem);
  --fs-h4: 1.125rem;
  --fs-lead: clamp(1.125rem, 1.7vw, 1.3125rem);
  --fs-body: 1.125rem;
  --fs-sm: 1rem;
  --fs-label: 0.875rem;
  --fs-xs: 0.75rem;
  --fs-mono: 0.8125rem;
  --fs-answer: clamp(1.875rem, 4vw, 2.5rem);
  /* The home hero's headline: 40px on a phone to 70px at 1280 and above
   * (the Option B mockup). Added because --fs-display stops at 58px. */
  --fs-hero: clamp(2.5rem, 5.4vw, 4.375rem);

  --lh-display: 1.03;
  --lh-heading: 1.15;
  --lh-body: 1.7;
  --lh-lead: 1.55;
  --lh-tight: 1.35;

  --track-display: clamp(-0.035em, -0.16vw, -0.022em);
  --track-heading: clamp(-0.028em, -0.12vw, -0.012em);
  --track-tight: -0.015em;
  --track-mark: -0.02em;

  --measure-lead: 46ch;
  --measure-prose: 68ch;
  --measure-sm: 70ch;
  --measure-note: 50ch;
  --measure-callout: 60ch;

  /* Space */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 96px;
  --space-10: 128px;

  /* Radius. One radius, on an 8px pitch: enough to read as product, not enough
     to read as decoration. */
  --radius-surface: 8px;

  /* Rule weights. Hairlines separate rows; the strong rule opens a group. */
  --rule-hair: 1px;
  --rule-strong: 2px;

  /* Elevation. A quiet four-step ladder, shadows only where an element must
     read as an object: a price table, a provenance artefact, a screenshot
     frame, the booking panel. Everything else is carried by ground change and
     rule weight.
       flat     = ground or paper bands
       raised   = a hairline rule and a card fill
       object   = a low-alpha shadow on paper
       floating = a wider shadow on the dark band, and the artefact black  */
  --shadow-object: 0 1px 2px rgba(16, 23, 29, 0.05),
    0 10px 28px rgba(16, 23, 29, 0.07);
  --shadow-lift: 0 2px 6px rgba(16, 23, 29, 0.06),
    0 16px 40px rgba(16, 23, 29, 0.1);
  --shadow-floating: 0 2px 6px rgba(4, 10, 20, 0.24),
    0 18px 48px rgba(4, 10, 20, 0.32);
  --elevation-raised: var(--rule-hair) solid var(--rule);
  --elevation-sunken: var(--card);
  --elevation-floating: var(--artefact);

  /* Layout */
  --container: 1120px;
  --container-wide: 1280px;
  --gutter: 20px;
  --nav-h: 64px;
  --touch-min: 44px;
  --control-h: 46px;
  --step-marker-w: 56px;
  --dropdown-w: 240px;
  --shot-thumb-h: 520px;
  --focus-ring: 2px;
  --focus-offset: 2px;

  --transition: background-color 120ms cubic-bezier(0.2, 0, 0, 1),
    border-color 120ms cubic-bezier(0.2, 0, 0, 1),
    color 120ms cubic-bezier(0.2, 0, 0, 1),
    box-shadow 120ms cubic-bezier(0.2, 0, 0, 1);
}

@media (min-width: 768px) {
  :root {
    --gutter: 32px;
  }
}

@media (min-width: 1024px) {
  :root {
    --gutter: 48px;
    --nav-h: 72px;
    --shot-thumb-h: 620px;
  }
}

/* ---------------------------------------------------------------------------
   3. Reset and base
   --------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--nav-h) + var(--space-6));
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4,
p,
ul,
ol,
dl,
dd,
figure,
blockquote,
caption {
  margin: 0;
}

ul,
ol {
  padding: 0;
  list-style: none;
}

p {
  text-wrap: pretty;
}

/* Unbreakable tokens: licence paths, URLs without their scheme, revision ids.
 * A 60-character huggingface.co citation in a verdict's plain prose (the "Sources
 * checked" line is not marked as record text) set the page's minimum content
 * width at 390px, and Chrome responded by widening the layout viewport to 413px
 * rather than overflowing, which the browser check reports as a failure rather
 * than the false pass the overflow assertion would otherwise give. Applied from
 * the body so a citation in authored prose and one in record text are treated
 * the same, and any future page inherits the protection. `anywhere` rather than
 * `break-word`: only `anywhere` shrinks the min-content size the viewport is
 * widened to, and a token breaks only when the line would otherwise overflow. */
body {
  overflow-wrap: anywhere;
}

table {
  border-collapse: collapse;
  width: 100%;
}

pre,
code {
  font-family: var(--font-mono);
}

button,
input,
select,
textarea,
summary {
  font: inherit;
  color: inherit;
  margin: 0;
}

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

svg {
  height: auto;
}

/* A link with no class of its own. The generated verdict pages link their
   record files and attestation with a bare anchor, and with no base rule those
   rendered browser-default blue (#0000ee), off-system on the site's most
   important page: the one thing the design review called out first. Zero
   specificity, so every styled link keeps its own rule. */
:where(a:not([class])) {
  color: var(--brand);
  text-decoration-thickness: var(--rule-hair);
  text-underline-offset: 3px;
}

:where(a:not([class])):hover {
  color: var(--brand-deep);
}

:where(.hero, .footer, #book, .section--dark, .exhibit) :where(a:not([class])) {
  color: var(--brand-on-dark);
}

:focus-visible {
  outline: var(--focus-ring) solid var(--brand);
  outline-offset: var(--focus-offset);
}

/* On the dark band the brand ring is too close to the ground it sits on, so
   the ring turns to the light accent there. Focus stays visible everywhere. */
.nav :focus-visible,
.hero :focus-visible,
.footer :focus-visible,
#book :focus-visible,
.section--dark :focus-visible,
.exhibit :focus-visible {
  outline-color: var(--brand-on-dark);
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    transition-duration: 0ms !important;
    animation: none !important;
  }
}

/* ---------------------------------------------------------------------------
   4. Layout primitives
   --------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.container--wide {
  max-width: var(--container-wide);
}

.section {
  padding-block: var(--space-8);
}

@media (min-width: 1024px) {
  .section {
    padding-block: var(--space-9);
  }
}

/* A section that continues the masthead on the same ground is one surface, so
   the masthead's own bottom padding is the whole gap. Before this rule the two
   paddings stacked: 64px under the masthead plus 128px on top of the section,
   about 200px of nothing between a verdict's h1 and its verdict panel, and the
   same between the pilot page's lead and its first heading. A paper band keeps
   its padding, because the change of ground is the separator there. */
.masthead + .section:not(.section--paper) {
  padding-top: 0;
}

.section--tight {
  padding-block: var(--space-7);
}

@media (min-width: 1024px) {
  .section--tight {
    padding-block: var(--space-8);
  }
}

.section--paper {
  background: var(--paper);
  border-block: var(--elevation-raised);
}

/* One column below the desktop split, sized minmax(0, 1fr) rather than the
   implicit auto: an auto column grows to its widest unbreakable child, so at
   320px the security page's egress allow-list widened the page to 364px
   instead of scrolling inside its own frame. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-6);
}

@media (min-width: 1024px) {
  .split {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-9);
    align-items: start;
  }

  .split--wide-left {
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  }

  .split--wide-right {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
  }
}

.mt-3 {
  margin-top: var(--space-3);
}
.mt-4 {
  margin-top: var(--space-4);
}
.mt-5 {
  margin-top: var(--space-5);
}
.mt-6 {
  margin-top: var(--space-6);
}
.mt-7 {
  margin-top: var(--space-7);
}
.mt-8 {
  margin-top: var(--space-8);
}

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

[hidden] {
  display: none !important;
}

/* ---------------------------------------------------------------------------
   5. Type
   --------------------------------------------------------------------------- */

.h1 {
  font-size: var(--fs-display);
  font-weight: 640;
  line-height: var(--lh-display);
  letter-spacing: var(--track-display);
  text-wrap: balance;
}

.h2 {
  font-size: var(--fs-h2);
  font-weight: 620;
  line-height: var(--lh-heading);
  letter-spacing: var(--track-heading);
  text-wrap: balance;
}

.h3 {
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.28;
  letter-spacing: var(--track-tight);
}

.h4 {
  font-size: var(--fs-h4);
  font-weight: 600;
  line-height: 1.4;
}

/* The lede carries the argument of the page. Its measure is held to 46ch so
   the rag stays balanced at every width, and its leading is looser than the
   display above it so the eye drops from statement into reading. */
.lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--slate);
  max-width: var(--measure-lead);
}

.sm {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--slate);
  max-width: var(--measure-sm);
}

.prose {
  max-width: var(--measure-prose);
}

.prose > * + * {
  margin-top: var(--space-4);
}

.prose h2 {
  margin-top: var(--space-7);
  font-size: var(--fs-h3);
  font-weight: 600;
  line-height: 1.28;
}

.prose h3 {
  margin-top: var(--space-6);
  font-size: var(--fs-h4);
  font-weight: 600;
}

.prose ul {
  padding-left: 0;
}

.prose ul li {
  position: relative;
  padding-left: var(--space-5);
  margin-top: var(--space-2);
}

.prose ul li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.65em;
  width: var(--space-2);
  height: var(--rule-hair);
  background: var(--rule-2);
}

a.link {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: var(--rule-hair);
  transition: var(--transition);
}

a.link:hover {
  color: var(--brand-deep);
}

.eyebrow {
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--brand);
}

/* ---------------------------------------------------------------------------
   6. Skip link and navigation
   --------------------------------------------------------------------------- */

.skip {
  position: absolute;
  left: var(--space-4);
  top: var(--space-2);
  z-index: 30;
  padding: var(--space-3) var(--space-4);
  background: var(--paper);
  color: var(--ink);
  font-size: var(--fs-label);
  font-weight: 600;
  text-decoration: none;
  border-radius: var(--radius-surface);
  box-shadow: var(--shadow-object);
  transform: translateY(-200%);
}

.skip:focus {
  transform: none;
}

/* The bar is the dark band: quiet, precise, and the same surface the hero and
   the footer sit on, so a page opens and closes inside one frame. */
.nav {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--navy);
  border-bottom: var(--rule-hair) solid var(--on-dark-rule);
}

.nav__inner {
  min-height: var(--nav-h);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
}

.nav__mark {
  font-size: var(--fs-h4);
  font-weight: 650;
  letter-spacing: var(--track-mark);
  color: var(--on-dark);
  text-decoration: none;
  padding-block: var(--space-3);
}

.nav__links {
  display: none;
}

/* Two classes deep on purpose. `.btn` also sets display on this element and sits
   later in the sheet, so a single class here loses the cascade and the button
   shows on a phone, wrapping in the bar and taking the whole block. That is
   exactly what shipped in the first release review. The mobile panel carries the
   same call to action at the bottom of its list. */
.nav .nav__cta {
  display: none;
}

.nav__menu {
  position: static;
}

.nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--touch-min);
  min-width: var(--touch-min);
  padding: var(--space-3) var(--space-4);
  background: transparent;
  border: var(--rule-hair) solid var(--on-dark-rule);
  border-radius: var(--radius-surface);
  color: var(--on-dark);
  font-size: var(--fs-label);
  font-weight: 600;
  cursor: pointer;
  list-style: none;
  transition: var(--transition);
}

.nav__toggle::-webkit-details-marker {
  display: none;
}

.nav__toggle:hover {
  border-color: var(--on-dark-muted);
  background: var(--on-dark-rule);
}

.nav__panel {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  max-height: calc(100vh - var(--nav-h));
  overflow-y: auto;
  background: var(--navy);
  border-top: var(--rule-hair) solid var(--on-dark-rule);
  border-bottom: var(--rule-hair) solid var(--on-dark-rule);
  box-shadow: var(--shadow-floating);
}

.nav__panel-list a {
  display: flex;
  align-items: center;
  min-height: 48px;
  color: var(--on-dark);
  text-decoration: none;
  font-size: var(--fs-label);
  font-weight: 500;
  border-bottom: var(--rule-hair) solid var(--on-dark-rule);
  transition: var(--transition);
}

.nav__panel-list li:last-child a {
  border-bottom: 0;
}

.nav__panel-list a:hover {
  color: var(--on-dark);
  background: var(--on-dark-rule);
}

.nav__panel-list a[aria-current="page"] {
  color: var(--brand-on-dark);
  font-weight: 600;
}

.nav__panel-group {
  margin: var(--space-5) 0 0;
  padding: 0 var(--space-4) var(--space-2);
  color: var(--on-dark-muted);
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.nav__panel-cta {
  padding-block: var(--space-5);
  border-top: var(--rule-hair) solid var(--on-dark-rule);
}

.nav__panel-cta .btn {
  width: 100%;
}

@media (min-width: 1024px) {
  .nav__menu {
    display: none;
  }

  .nav__links {
    display: block;
    margin-left: auto;
  }

  /* The list is the flex row. The reset that removes list markers targets ul
     and ol, so an li must sit inside one or its marker renders: see the list
     structure rule in site/check.mjs. */
  .nav__list {
    display: flex;
    align-items: center;
    gap: var(--space-5);
  }

  /* The one group in the primary navigation. A details element, so it opens
     without JavaScript and the browser owns the expanded state. */
  .nav__dropdown {
    position: relative;
  }

  .nav__summary {
    cursor: pointer;
    list-style: none;
  }

  .nav__summary::-webkit-details-marker {
    display: none;
  }

  .nav__dropdown[open] > .nav__summary,
  .nav__dropdown[data-section="true"] > .nav__summary {
    color: var(--on-dark);
  }

  .nav__dropdown[open] > .nav__summary {
    box-shadow: inset 0 calc(-1 * var(--rule-strong)) 0 var(--brand-on-dark);
  }

  .nav__dropdown-list {
    position: absolute;
    top: calc(100% + var(--space-3));
    left: calc(-1 * var(--space-4));
    z-index: 25;
    min-width: var(--dropdown-w);
    padding-block: var(--space-2);
    background: var(--paper);
    border: var(--elevation-raised);
    border-radius: var(--radius-surface);
    box-shadow: var(--shadow-lift);
  }

  .nav__dropdown-link {
    display: flex;
    align-items: center;
    min-height: 40px;
    padding: var(--space-2) var(--space-4);
    color: var(--slate);
    text-decoration: none;
    font-size: var(--fs-label);
    font-weight: 500;
    transition: var(--transition);
  }

  .nav__dropdown-link:hover {
    color: var(--ink);
    background: var(--card);
  }

  .nav__dropdown-link[aria-current="page"] {
    color: var(--brand);
    font-weight: 600;
  }

  .nav .nav__cta {
    display: inline-flex;
    margin-left: var(--space-5);
  }

  /* One box model for both kinds of nav item. An anchor is an inline box and a
     summary is a block by default, so giving them one class did not give them one
     height: measured at 31px against 39px, which offset the group label by four
     pixels. An inline-flex box with a minimum height makes them identical by
     construction rather than by coincidence. */
  .nav__link {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    /* A navigation label never wraps. Two-word labels ("How it works",
     * "Demonstration") broke onto a second line as soon as the bar had a
     * seventh item, which made those two 6px taller than their neighbours and
     * offset the row. The layout assertion now checks the height as well as the
     * centre, which is how this was caught rather than shipped. */
    white-space: nowrap;
    color: var(--on-dark-muted);
    text-decoration: none;
    font-size: var(--fs-label);
    font-weight: 500;
    transition: var(--transition);
  }

  .nav__link:hover {
    color: var(--on-dark);
  }

  .nav__link[aria-current="page"] {
    color: var(--on-dark);
    font-weight: 600;
    box-shadow: inset 0 calc(-1 * var(--rule-strong)) 0 var(--brand-on-dark);
  }
}

/* ---------------------------------------------------------------------------
   7. Buttons and links
   --------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-h);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-surface);
  font-size: var(--fs-label);
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  transition: var(--transition);
}

/* Buttons are flat. The primary used to carry the object shadow and lift
   further on hover while the secondary and on-dark buttons carried none, so two
   buttons side by side in one row read as two different systems. A button is a
   control, not an object: colour and border carry it, and hover deepens the
   colour. */
.btn--primary {
  background: var(--action);
  color: var(--on-brand);
  border: var(--rule-hair) solid var(--action);
}

.btn--primary:hover {
  background: var(--action-deep);
  border-color: var(--action-deep);
}

.btn--secondary {
  background: var(--paper);
  color: var(--ink);
  border: var(--rule-hair) solid var(--rule-2);
}

.btn--secondary:hover {
  border-color: var(--ink);
  background: var(--card);
}

.btn--on-dark {
  background: transparent;
  color: var(--on-dark);
  border: var(--rule-hair) solid var(--on-dark-rule);
}

.btn--on-dark:hover {
  border-color: var(--on-dark);
  background: var(--on-dark-rule);
}

.btn[disabled] {
  background: var(--card);
  color: var(--slate);
  border: var(--rule-hair) solid var(--rule);
  box-shadow: none;
  cursor: not-allowed;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-6);
}

.text-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  color: var(--brand);
  font-size: var(--fs-label);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: var(--rule-hair);
  transition: var(--transition);
}

.text-link:hover {
  color: var(--brand-deep);
}

/* Inside a sentence the text link is part of the line. As an inline-flex box
   with a 44px minimum height and a smaller size it pushed its own line apart
   and shrank mid-sentence (the verdicts lead, "How the gate decides"). The
   sentence's line height already gives the tap target its height. */
:is(.lead, .prose, .entry-verdict__lead) .text-link {
  display: inline;
  min-height: 0;
  font-size: inherit;
}

/* ---------------------------------------------------------------------------
   8. Page furniture
   --------------------------------------------------------------------------- */

.masthead {
  padding-block: var(--space-7) var(--space-6);
}

@media (min-width: 1024px) {
  .masthead {
    padding-block: var(--space-8) var(--space-7);
  }
}

.masthead__lead {
  margin-top: var(--space-5);
}

.breadcrumb {
  font-size: var(--fs-label);
  font-weight: 500;
  color: var(--slate);
  margin-bottom: var(--space-5);
}

.breadcrumb a {
  color: var(--slate);
  text-decoration: none;
  transition: var(--transition);
}

.breadcrumb a:hover {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.breadcrumb span {
  margin-inline: var(--space-2);
  color: var(--slate);
}

/* A pager after a section on the same ground continues it, so the section's
   bottom padding is the gap; stacked with the pager's own it left about 160px
   of nothing under every page's last block. After a paper band the change of
   ground is the separator and the pager keeps its padding. */
.section:not(.section--paper) + .section--tight:has(.pager) {
  padding-top: 0;
}

/* The pager says where to go next, and nothing else. It used to carry a "You are
   reading X" label on the left, which restated the page title, the h1 and the
   highlighted navigation item: orientation the reader already has, in the one
   place they are looking for the next step. One item now, pushed to the end. */
.pager {
  display: flex;
  justify-content: flex-end;
  border-top: var(--elevation-raised);
  padding-top: var(--space-5);
}

.pager__label {
  font-size: var(--fs-sm);
  color: var(--slate);
}

.pager__next {
  font-weight: 500;
}

/* A verdict entry's pager carries previous and next: one at each end, and
 * the links as inline boxes, because as inline-flex boxes the space between
 * "Previous:" and the model id collapsed at the flex item's edge. */
.pager:has(.pager__prev) {
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.pager .text-link {
  display: inline-block;
  min-height: 0;
  padding-block: var(--space-3);
}

/* An in-page section rail: anchor links to the sections below, for pages too
 * long to scan. Wraps to two columns on a phone, one quiet line on desktop. */
.section-rail {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--rule);
  font-size: var(--fs-sm);
}

/* ---------------------------------------------------------------------------
   9. Hero and the verdict record
   --------------------------------------------------------------------------- */

/* The hero is the dark accent band: a product statement, not a page heading.
   The verdict record beside it is a raised white card: the one object in the
   masthead, and the public record in numbers. */
.hero {
  background: var(--navy);
  color: var(--on-dark);
  padding-block: var(--space-8) var(--space-8);
  border-bottom: var(--rule-hair) solid var(--on-dark-rule);
}

.hero .h1 {
  color: var(--on-dark);
}

.hero .lead {
  color: var(--on-dark-muted);
}

.hero__statement .lead {
  margin-top: var(--space-5);
}

.hero__actions {
  margin-top: var(--space-6);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
}

/* On the dark band the brightest object is the action: a light button with navy
   text (17.30:1 in dark, 15.49:1 in light). The two surfaces it uses hold one
   colour in both themes, so dark mode keeps the button the brightest thing
   on the band. The brand blue owns links and focus here instead. */
.hero .btn--primary {
  background: var(--on-dark);
  color: var(--navy);
  border-color: var(--on-dark);
}

.hero .btn--primary:hover {
  background: var(--on-brand);
  border-color: var(--on-brand);
}

.hero .btn--secondary {
  background: transparent;
  color: var(--on-dark);
  border-color: var(--on-dark-rule);
}

.hero .btn--secondary:hover {
  background: var(--on-dark-rule);
  border-color: var(--on-dark-muted);
}

@media (min-width: 1024px) {
  .hero {
    padding-block: var(--space-9);
  }

  .hero .split {
    align-items: center;
  }
}

/* The Option B hero (site/lib/hero.mjs). Two columns from 1024px, the card
   fixed at 520px from 1280px; the card stacks under the statement below
   1024px, and at 390px the buttons and proof points stack and the check rows
   switch to their short results. */
.hero__grid {
  display: grid;
  gap: var(--space-7);
  align-items: center;
}

@media (min-width: 1024px) {
  .hero__grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
    gap: var(--space-8);
  }
}

@media (min-width: 1280px) {
  .hero__grid {
    grid-template-columns: minmax(0, 1fr) 32.5rem;
  }
}

.hero__title {
  margin: 0;
  color: var(--on-dark);
  font-size: var(--fs-hero);
  font-weight: 700;
  line-height: 1.04;
  letter-spacing: var(--track-display);
  text-wrap: balance;
}

.hero__lead {
  max-width: 40rem;
  margin-top: var(--space-5);
  color: var(--on-dark-muted);
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
}

.hero__lead a {
  color: var(--on-dark);
}

.btn--large {
  min-height: 3.5rem;
  padding-inline: var(--space-6);
  font-size: var(--fs-sm);
}

.hero__proof {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  margin: var(--space-6) 0 0;
  padding: 0;
  list-style: none;
  color: var(--on-dark-muted);
  font-size: var(--fs-label);
}

.hero__proof li {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.hero__tick {
  width: 1rem;
  height: 1rem;
  flex: none;
  fill: none;
  stroke: var(--ok-on-dark);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

@media (max-width: 599px) {
  .hero__actions {
    flex-direction: column;
    align-items: stretch;
  }

  .hero__actions .btn {
    width: 100%;
  }

  .hero__proof {
    flex-direction: column;
  }
}

/* The latest-verdict card. Paper on the dark band, the one object in the
   hero; every value in it is generated from the verdict data. */
.vcard {
  display: grid;
  gap: var(--space-5);
  padding: var(--space-5);
  background: var(--paper);
  color: var(--ink);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
  box-shadow: var(--shadow-floating);
}

@media (min-width: 600px) {
  .vcard {
    padding: var(--space-6);
  }
}

.vcard__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-4);
}

.vcard__label {
  color: var(--slate);
  font-size: var(--fs-label);
  font-weight: 600;
}

.vcard__date {
  color: var(--slate);
  font-size: var(--fs-label);
}

.vcard__model {
  font-size: var(--fs-h3);
  font-weight: 700;
  line-height: var(--lh-heading);
  letter-spacing: var(--track-heading);
  overflow-wrap: anywhere;
}

.vcard__org {
  color: var(--slate);
  font-weight: 500;
}

.vcard__rev {
  margin-top: var(--space-1);
  color: var(--slate);
  font-size: var(--fs-label);
}

.vcard__rev code {
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
}

.vcard__verdict {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.vcard__reason {
  font-size: var(--fs-sm);
}

.vcard__checks {
  margin: 0;
  padding: 0;
  list-style: none;
  border-top: var(--rule-strong) solid var(--ink);
}

.vcard__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
  padding-block: var(--space-3);
  border-bottom: var(--elevation-raised);
  font-size: var(--fs-label);
}

.vcard__key {
  color: var(--slate);
}

.vcard__val {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: 500;
  text-align: right;
}

.vcard__val--ok { color: var(--ok); }
.vcard__val--held { color: var(--held); }
.vcard__val--rej { color: var(--rej); }
.vcard__val--na { color: var(--slate); }

.vcard__dot {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 50%;
  background: currentColor;
}

/* Not assessed is an outline, so it reads as absent rather than as a state. */
.vcard__dot--na {
  background: transparent;
  border: 1.5px solid var(--rule-2);
}

.vcard__short {
  display: none;
}

@media (max-width: 599px) {
  .vcard__long {
    display: none;
  }

  .vcard__short {
    display: inline;
  }
}

.vcard__speed {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-1) var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: var(--card);
  border-radius: var(--radius-surface);
}

.vcard__speed-main {
  font-weight: 600;
}

.vcard__speed-target {
  color: var(--slate);
  font-size: var(--fs-label);
}

.vcard__links {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  font-size: var(--fs-label);
}

.vcard__links a {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  text-underline-offset: 3px;
}

.hero .vcard__verify {
  color: var(--brand);
  font-weight: 600;
}

.hero .vcard__all {
  color: var(--slate);
}

/* The strip under the hero: Admit, Compare, Prove. */
.hero__strip {
  display: grid;
  gap: var(--space-5);
  margin: var(--space-8) 0 0;
  padding: var(--space-6) 0 0;
  list-style: none;
  border-top: var(--rule-hair) solid var(--on-dark-rule);
}

@media (min-width: 768px) {
  .hero__strip {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-8);
  }
}

.hero__strip-title {
  color: var(--brand-on-dark);
  font-size: var(--fs-label);
  font-weight: 600;
}

.hero__strip-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--touch-min);
  color: var(--on-dark);
  font-size: var(--fs-label);
  font-weight: 600;
  text-underline-offset: 3px;
}

.hero__strip-link:hover {
  color: var(--brand-on-dark);
}

.hero__strip p {
  margin-top: var(--space-2);
  color: var(--on-dark-muted);
  font-size: var(--fs-sm);
  line-height: var(--lh-lead);
}

/* The mobile menu button: a 44px square with the three-line mark. */
.nav__toggle {
  width: var(--touch-min);
  padding: 0;
}

.nav__toggle-icon {
  width: 1.25rem;
  height: 1.25rem;
  fill: none;
  stroke: var(--on-dark);
  stroke-width: 2;
  stroke-linecap: round;
}

/* ---------------------------------------------------------------------------
   10. Lists. Form lines that group information.
   --------------------------------------------------------------------------- */

.list {
  border-top: var(--rule-strong) solid var(--ink);
}

.list__item {
  padding-block: var(--space-4);
  border-bottom: var(--elevation-raised);
}

.list__item .h3 {
  margin-bottom: var(--space-2);
}

.list__item p {
  max-width: var(--measure-sm);
  color: var(--slate);
}

.list--plain {
  border-top: var(--elevation-raised);
}

/* The pillars: the product's parts, as a row of cards. They were rows with
   the heading in a left column and the text in a right one, which left half of
   every row empty at 1440 and made three short ideas read as a long document.
   Side by side they read as the parts of one thing. On a phone they stack. */
.pillars {
  display: grid;
  gap: var(--space-4);
}

.pillar {
  display: flex;
  flex-direction: column;
  padding: var(--space-5);
  background: var(--card);
  border: var(--elevation-raised);
  border-top: var(--rule-strong) solid var(--brand);
  border-radius: var(--radius-surface);
}

.pillar__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  margin-top: var(--space-3);
  color: var(--slate);
  font-size: var(--fs-sm);
}

/* The link sits at the foot of its card, so a row of cards ends on one line. */
.pillar__body > p:last-child:has(.text-link) {
  margin-top: auto;
  padding-top: var(--space-4);
}

@media (min-width: 768px) {
  .pillars {
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: var(--space-5);
  }
}

@media (min-width: 1024px) {
  .pillar {
    padding: var(--space-6);
  }
}

/* Definition rows. Glossary and the capability tables. */
.defs {
  border-top: var(--rule-strong) solid var(--ink);
}

.defs__row {
  padding-block: var(--space-5);
  border-bottom: var(--elevation-raised);
}

.defs__term {
  font-weight: 600;
  font-size: var(--fs-body);
}

.defs__desc {
  color: var(--slate);
  font-size: var(--fs-sm);
  line-height: 1.65;
  max-width: var(--measure-prose);
  margin-top: var(--space-2);
}

@media (min-width: 1024px) {
  .defs__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    gap: var(--space-7);
    align-items: baseline;
  }

  .defs__desc {
    margin-top: 0;
  }
}

/* Step rows. A genuine sequence, so it keeps numbered markers. The marker is a
   brand tab rather than a mono numeral: this is a document with an order, not a
   dump of machine output. Mono is reserved for real artefacts. */
.steps {
  border-top: var(--rule-strong) solid var(--ink);
}

.step {
  display: grid;
  gap: var(--space-2);
  padding-block: var(--space-5);
  border-bottom: var(--elevation-raised);
}

.step__marker {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: start;
  min-width: var(--step-marker-w);
  width: fit-content;
  padding: var(--space-1) var(--space-3);
  background: var(--brand-tint);
  color: var(--brand-deep);
  font-size: var(--fs-label);
  font-weight: 650;
  letter-spacing: var(--track-tight);
  border-radius: var(--radius-surface);
}

.step__title {
  font-weight: 600;
  font-size: var(--fs-body);
}

.step__body {
  color: var(--slate);
  font-size: var(--fs-sm);
  line-height: 1.65;
  max-width: var(--measure-prose);
}

@media (min-width: 768px) {
  .step {
    grid-template-columns: var(--step-marker-w) minmax(0, 1fr) minmax(0, 2fr);
    gap: var(--space-5);
    align-items: start;
  }

  .step__title {
    padding-top: var(--space-1);
  }

  .step__body {
    margin-top: 0;
    padding-top: var(--space-1);
  }
}

/* Caveats. Headings and prose, no box. */
.caveats {
  display: grid;
  gap: var(--space-6);
}

.caveat {
  border-top: var(--rule-strong) solid var(--ink-2);
  padding-top: var(--space-4);
}

.caveat .h3 {
  margin-bottom: var(--space-3);
}

.caveat p {
  color: var(--slate);
  max-width: var(--measure-note);
}

@media (min-width: 1024px) {
  .caveats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--space-9);
    row-gap: var(--space-7);
  }
}

/* A pull statement, used sparingly. */
/* A stand-out opening line. It carried a brand top rule, which with the
   section's padding above it read as a lone blue line on a phone. */
.note {
  font-size: var(--fs-lead);
  line-height: 1.5;
  font-weight: 500;
  max-width: var(--measure-note);
}

/* The price statement. Retained as .price because the compliance check asserts
   that every price mention carries the hardware separation line inside it.
   A price is the one number a buyer and a security reviewer both stop on, so it
   is the one block on a light page lifted into a signed-document card. */
.price {
  background: var(--paper);
  border: var(--elevation-raised);
  border-top: var(--rule-strong) solid var(--brand);
  border-radius: var(--radius-surface);
  box-shadow: var(--shadow-object);
  padding: var(--space-5);
  font-size: var(--fs-lead);
  line-height: 1.5;
}

.price > p,
.price > .table__footnote {
  max-width: var(--measure-sm);
}

.price strong {
  font-weight: 650;
  color: var(--ink);
}

.price + .price {
  margin-top: var(--space-6);
}

@media (min-width: 1024px) {
  .price {
    padding: var(--space-6);
  }
}

/* The artefact card. Same document metaphor as .price and the same register, so
   the two read as one family: a paper object picked up off the ground. .price is
   that card signed (the brand top edge is the signature on the one number a
   buyer and a security reviewer both stop on). .card is the same object for the
   moments that are evidence rather than a price: what the form sends, the exit
   inventory, what a qualifying environment looks like. .card--artefact carries
   the signature and the darker hairline, because those three carry no eyebrow of
   their own and need the stronger object presence. No seal, no badge, no icon:
   nothing that implies verification the copy does not claim. */
.card {
  background: var(--paper);
  border: var(--elevation-raised);
  border-radius: var(--radius-surface);
  box-shadow: var(--shadow-object);
  padding: var(--space-5);
  min-width: 0;
  max-width: 100%;
}

.card > * + * {
  margin-top: var(--space-4);
}

.card > p,
.card > .table__footnote,
.card > .note {
  max-width: var(--measure-sm);
}

.card--artefact {
  border-color: var(--rule-2);
  border-top: var(--rule-strong) solid var(--brand);
}

/* The label over a rule, mirroring the register caption. Pages that supply one
   get the artefact named; none do today, so this is defined and quiet. */
.card__label {
  font-family: var(--font-sans);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--brand);
  padding-bottom: var(--space-3);
  border-bottom: var(--rule-hair) solid var(--rule);
}

@media (min-width: 1024px) {
  .card {
    padding: var(--space-6);
  }
}

/* The wide content: a table or a screenshot pair that earns the breakout. The
   guard below 768px means an unstacked wide table can never break the 390px
   no-overflow assertion. */
.cmp,
.rank {
  overflow-x: auto;
}

@media (min-width: 768px) {
  .cmp,
  .rank {
    overflow-x: visible;
  }
}

/* ---------------------------------------------------------------------------
   11. Tables. They should read like instruments that were designed, not dumped.
   --------------------------------------------------------------------------- */

.table-caption {
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--slate);
  text-align: left;
  padding: 0 0 var(--space-3) var(--space-4);
  caption-side: top;
}

/* Every cell has an inner left edge, so a striped row's text sits inside its
 * fill rather than flush against the edge where the fill starts; the caption
 * and headers line up on the same edge. */
.table th,
.table td {
  text-align: left;
  padding: var(--space-4) var(--space-5) var(--space-4) var(--space-4);
  vertical-align: top;
  border-bottom: var(--elevation-raised);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.table th {
  font-weight: 600;
  color: var(--ink);
  font-size: var(--fs-label);
  border-bottom: var(--rule-strong) solid var(--ink);
  vertical-align: bottom;
}

.table tbody tr:nth-child(even) td {
  background: var(--card);
}

.table tbody tr:nth-child(even) td:first-child {
  border-top-left-radius: var(--radius-surface);
  border-bottom-left-radius: var(--radius-surface);
}

.table tbody tr:nth-child(even) td:last-child {
  border-top-right-radius: var(--radius-surface);
  border-bottom-right-radius: var(--radius-surface);
  padding-right: var(--space-3);
}

.table td {
  color: var(--slate);
}

/* Two classes deep: `.table td` sets the slate body colour and outranked a
 * single class, so the key column rendered grey rather than ink. */
.table .table__key {
  color: var(--ink);
  font-weight: 600;
}

.table__footnote {
  margin-top: var(--space-4);
  font-size: var(--fs-label);
  color: var(--slate);
  max-width: var(--measure-prose);
}

.price .table__footnote {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: var(--elevation-raised);
}

.td-k {
  display: block;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-1);
}

/* In a table, a word is the smallest unit a column may shrink to. The body's
   `overflow-wrap: anywhere` shrinks every token's minimum width to one
   character, which is right for prose and wrong for a table: the automatic
   layout then squeezed the price list's figure column at 768px until it read
   "Figur e" and "NZ$ 24,0 00 a year". `break-word` still breaks a token that
   cannot fit, but it leaves each word's minimum width alone, so the columns size
   to their words. */
@media (min-width: 768px) {
  .table th,
  .table td {
    overflow-wrap: break-word;
  }
}

@media (max-width: 767px) {
  .table--stack caption {
    display: block;
    width: 100%;
    padding-left: 0;
  }

  .table--stack thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .table--stack,
  .table--stack tbody,
  .table--stack tr,
  .table--stack td {
    display: block;
    width: 100%;
  }

  .table--stack tr {
    padding-block: var(--space-4);
    border-bottom: var(--elevation-raised);
  }

  .table--stack td {
    padding: 0;
    border: 0;
    background: transparent;
  }

  .table--stack tbody tr:nth-child(even) td,
  .table--stack tbody tr:nth-child(even) td:first-child,
  .table--stack tbody tr:nth-child(even) td:last-child {
    background: transparent;
    border-radius: 0;
    padding-right: 0;
  }

  .table--stack td + td {
    margin-top: var(--space-2);
  }
}

@media (min-width: 768px) {
  .td-k {
    display: none;
  }
}

/* ---------------------------------------------------------------------------
   12. The exhibit. The artefact black surface, used only for a real product
   artefact: a policy bundle, an audit ledger row, a Compare report line. It is
   machine evidence, so it is also the only place mono is allowed to speak.
   --------------------------------------------------------------------------- */

.exhibit {
  background: var(--elevation-floating);
  color: var(--on-dark);
  border-radius: var(--radius-surface);
  overflow: hidden;
  box-shadow: var(--shadow-lift);
}

.exhibit__head {
  padding: var(--space-3) var(--space-5);
  border-bottom: var(--rule-hair) solid var(--on-dark-rule);
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--on-dark);
}

.exhibit__head span {
  color: var(--on-dark-muted);
  font-weight: 400;
}

.exhibit__body {
  margin: 0;
  padding: var(--space-5);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  line-height: 1.75;
  overflow-x: auto;
  tab-size: 2;
}

.exhibit__body .c {
  color: var(--on-dark-muted);
}

.exhibit__body .k {
  color: var(--on-dark-muted);
}

.exhibit__table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
}

/* Instrument tables. Nothing is nowrap: a value stays on one line only if the
 * column is wide enough, and forcing it produced a scrollbar inside the figure at
 * 1024px, where the split column is about 350px. Letting a cell wrap costs a
 * little tidiness at the narrow end and removes the scrollbar entirely. The
 * scroll container stays as a safety net rather than the mechanism. */
.exhibit__table th,
.exhibit__table td {
  text-align: left;
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--rule-hair) solid var(--on-dark-rule);
  line-height: 1.5;
}

.exhibit__table th {
  color: var(--on-dark-muted);
  font-weight: 500;
}

.exhibit__table tbody tr:last-child > * {
  border-bottom: 0;
}

/* The exhibit's value columns are short ("pass or fail", "measured") and fit
 * on one line in the narrowest card the split gives them (about 350px at 390px
 * and at 1024px, where the columns need about 330px), so they hold together
 * and the measure column takes the wrap. Below 390px they wrap again: at 320px
 * holding them widened the page to 373px. */
@media (min-width: 390px) {
  /* Words stay whole, as in .table: under the body's `anywhere` the header
   * split to "Candidate / A" in a 395px card. */
  .exhibit__table th,
  .exhibit__table td {
    overflow-wrap: break-word;
  }

  .exhibit__table--compact :is(td, thead th:not(:first-child)) {
    white-space: nowrap;
  }

  /* A step less padding, so the held columns fit the 1024px split with room
   * for a scrollbar: at 16px a side the table needed 354px of a 348px column. */
  .exhibit__table--compact :is(th, td) {
    padding-inline: var(--space-3);
  }
}

.exhibit__scroll {
  overflow-x: auto;
}

.exhibit__note {
  margin-top: var(--space-4);
  font-size: var(--fs-label);
  color: var(--slate);
  max-width: 62ch;
}

/* ---------------------------------------------------------------------------
   13. Figures and screenshots. A capture is product evidence, so it is framed
   like a product window rather than pasted on the page.
   --------------------------------------------------------------------------- */

.shot {
  border: var(--elevation-raised);
  border-radius: var(--radius-surface);
  overflow: hidden;
  background: var(--paper);
  box-shadow: var(--shadow-object);
}

.shot img {
  width: 100%;
  height: auto;
  border-bottom: var(--elevation-raised);
}

.shot figcaption {
  padding: var(--space-4) var(--space-5);
  font-size: var(--fs-label);
  line-height: 1.6;
  color: var(--slate);
}

@media (max-width: 767px) {
  /* On a phone the pair stacks, so both captures render: the desktop shot is
     squeezed to about 350px where it is illegible, and it is 2.99MB of the page's
     5.34MB of images. The mobile capture is the one that shows what a phone user
     would get, so the desktop shot is not rendered below the breakpoint at all.
     That halves the image weight and removes an image nobody can read. */
  .shots--pair .shot:not(.shot--mobile) {
    display: none;
  }
}

/* A full-page capture at 390px is many screens tall. The thumbnail shows the
   top of it at a bounded height so a gallery of them stays readable. The file
   is unmodified; the caption states the full capture height. */
.shot--mobile img {
  height: var(--shot-thumb-h);
  object-fit: cover;
  object-position: top center;
}

.shots {
  display: grid;
  gap: var(--space-6);
}

/* Side by side, the phone capture takes the desktop frame's height rather
   than its own fixed thumbnail height. At 620px it ran about 120px past the
   desktop frame beside it at 1440, and at 768px (two equal columns) nearly
   twice that, so every pair left a block of empty ground between the desktop
   frame and the capture note under the pair. The phone image is taken out of
   flow and covers its frame from the top, so the row's height is the desktop
   frame's and both frames end on one line. */
@media (min-width: 768px) {
  .shots--pair {
    grid-template-columns: minmax(0, 1fr) 220px;
    gap: var(--space-6);
    align-items: stretch;
  }

  .shots--pair .shot--mobile {
    position: relative;
    min-height: var(--space-10);
  }

  .shots--pair .shot--mobile img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border-bottom: 0;
  }
}

@media (min-width: 1024px) {
  .shots--pair {
    grid-template-columns: minmax(0, 1fr) 260px;
    gap: var(--space-7);
  }
}

/* The deployment stages as a compact numbered grid: the names in order,
 * three across at desktop. The gating rule is stated once above it. */
.stages {
  display: grid;
  gap: var(--space-2) var(--space-5);
  margin-inline: 0;
  padding: 0;
  list-style: none;
  counter-reset: stage;
}

@media (min-width: 600px) {
  .stages {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.stages li {
  counter-increment: stage;
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
  padding-block: var(--space-3);
  border-bottom: var(--elevation-raised);
  font-weight: 600;
}

.stages li::before {
  content: counter(stage, decimal-leading-zero);
  color: var(--brand);
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
}

/* The walkthrough recording slot. A 16:9 frame sized for a screen recording,
 * holding an honest empty state until the file exists: no player element with
 * no source, no poster pretending to be video, and nothing fetched. The empty
 * state keeps the existing state contrast pair; only its box changes, so it
 * fills the window frame instead of floating inside it. */
.video-slot__frame {
  aspect-ratio: 16 / 9;
  display: grid;
  place-content: center;
  text-align: center;
  margin: 0;
  max-width: none;
  border: 0;
  border-radius: 0;
}

/* ---------------------------------------------------------------------------
   14. States: empty, loading, error. Consistent everywhere.
   --------------------------------------------------------------------------- */

.state {
  padding: var(--space-5);
  border: var(--elevation-raised);
  border-radius: var(--radius-surface);
  background: var(--paper);
  font-size: var(--fs-sm);
  color: var(--slate);
  max-width: 62ch;
}

.state__title {
  display: block;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: var(--space-2);
}

.state--empty {
  border-style: dashed;
  background: var(--card);
}

.state--loading {
  background: var(--elevation-sunken);
}

.state--loading .state__title::after {
  content: "";
  display: inline-block;
  width: 0.6em;
  height: 0.6em;
  margin-left: var(--space-2);
  border-radius: 50%;
  background: var(--rule-2);
  animation: pulse 1.2s ease-in-out infinite;
}

.state--error {
  border-color: var(--seal);
  background: var(--seal-tint);
  color: var(--ink);
}

.state--error .state__title {
  color: var(--seal);
}

@keyframes pulse {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0.25;
  }
}

/* ---------------------------------------------------------------------------
   15. Callout. One use: the honest limit beside a claim. A card, because the
   limit is part of the product and deserves the same weight as the claim.
   --------------------------------------------------------------------------- */

.callout {
  background: var(--card);
  border-left: var(--rule-strong) solid var(--brand);
  border-radius: var(--radius-surface);
  padding: var(--space-4) var(--space-5);
  max-width: var(--measure-callout);
}

.callout .h4 {
  margin-bottom: var(--space-2);
}

.callout p {
  color: var(--slate);
  font-size: var(--fs-sm);
  line-height: 1.65;
}

/* Limits are not failures and must not be dressed as one.
 *
 * Before this, .callout--limit shared --seal and --seal-tint with
 * .state--error, .field--invalid and .status--failure, so every honest
 * disclaimer on the site was styled as an error. The design review's reading
 * is right and worth quoting: "the same limit said once, clearly, at the point
 * of the claim, reads as confidence. Said five times on one page it reads as
 * anxiety." Red now means one thing: a rejection, a failure or an invalid
 * field. A limit is a limit.
 *
 * Neutral paper, a rule-2 left rule (the control-border token, 3.74:1, so the
 * rule is a real boundary and not a hairline), and ink at body size rather
 * than slate at small size: the limit is part of the claim and is read at the
 * same weight as the claim. */
.callout--limit {
  background: var(--paper);
  border-left-color: var(--rule-2);
  border-left-width: 4px;
}

.callout--limit p {
  color: var(--ink);
  font-size: var(--fs-body);
  line-height: 1.65;
}

.callout--limit .h4 {
  color: var(--ink);
  font-size: var(--fs-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-weight: 600;
}

/* ---------------------------------------------------------------------------
   Verdict state badges (design review 2026-09-25, trust-wave item 4)
   --------------------------------------------------------------------------- */

/* Three verdict states, each distinct in shape as well as colour, so the state
 * survives greyscale printing and a colour-blind reader:
 *
 *   admitted   fully rounded pill     green
 *   held       rounded square        amber, not red: a hold is not a failure
 *   rejected   sharp square           red, the one state that earns it
 *
 * Red is reserved for a rejection, a failure or an invalid field. Before this
 * the verdict was plain uppercase body text and nothing but the word separated
 * the three states.
 *
 * Contrast, measured (WCAG 2.1), text on tint:
 *   admitted  #1d6b3f on #e6f2ea  5.66
 *   held      #7a5200 on #fbf0d9  6.12
 *   rejected  #9a2b1f on #f6e9e6  6.47
 *
 * The dark pairings are in the dark-theme tokens below. */
:root {
  --ok: #1d6b3f;
  --ok-tint: #e6f2ea;
  --held: #7a5200;
  --held-tint: #fbf0d9;
  --rej: #9a2b1f;
  --rej-tint: #f6e9e6;
}

/* ---------------------------------------------------------------------------
   Dark theme (design review 2026-09-25, item 16).
   --------------------------------------------------------------------------- */

/* The theme follows the reader's system setting and nothing else: no toggle,
 * no JavaScript, no storage. The light values above are unchanged; these are
 * their dark companions, each measured (WCAG 2.1) in the review:
 *
 *   ground #0b1220     ink on ground       15.90
 *   paper  #111a2b     ink on paper        14.79
 *   card   #16213a     slate on card        7.59
 *   slate  #a7b4c4     slate on paper       8.26
 *   brand  #8fb0ff     brand on paper       8.14
 *   rule-2 #7f8ea6     control borders      5.24
 *   rule   #2a3752     decorative only      1.46
 *   admitted #74d39c on #12301f             7.86
 *   held     #f0c46a on #33270c             8.92
 *   rejected #ff9b8c on #3a1713             7.87
 *
 * --navy darkens to #070d18 so the header and the footer stay bands rather
 * than panels. Against the ground that is 1.04:1, which is why the hairline
 * under the sticky bar is lifted to the control-border token below: the edge
 * between bar and page is the one thing the dark surfaces cannot say
 * themselves.
 *
 * Unchanged in dark, by design: the fonts, the spacing, the call-to-action
 * blue and the artefact black. Both hold one colour in both themes through the
 * token group in section 2. */
@media (prefers-color-scheme: dark) {
  :root {
    --ground: #0b1220;
    --paper: #111a2b;
    --card: #16213a;
    --ink: #e8edf3;
    --ink-2: #d2dae4;
    --slate: #a7b4c4;
    --rule: #2a3752;
    --rule-2: #7f8ea6;
    --brand: #8fb0ff;
    --brand-deep: #b5caff;
    --brand-tint: #1a2848;
    --navy: #070d18;
    --seal: #ff9b8c;
    --seal-tint: #3a1713;
    --ok: #74d39c;
    --ok-tint: #12301f;
    --held: #f0c46a;
    --held-tint: #33270c;
    --rej: #ff9b8c;
    --rej-tint: #3a1713;
  }

  /* 5.64:1 against the ground, where the bar itself measures 1.04:1. */
  .nav {
    border-bottom-color: var(--rule-2);
  }
}

/* A verdict's reason, in two layers (design review 2026-09-25, trust-wave
 * item 5).
 *
 * The plain sentence is ours and is written from the gate name alone. The
 * verbatim line is the gate's own words: the code and the message, unaltered.
 * They are stacked rather than inline so the reader's line and the evidence
 * never blur into one account, and both stay on the page. Nothing is moved to
 * the full record and nothing is hidden behind a disclosure: a reason a reader
 * can act on and a reason an auditor can check are the same fact at two
 * depths, and hiding either one is how a verdict starts to look like a claim.
 *
 * The verbatim line is deliberately quieter than the plain one. It is evidence
 * and it is for someone who went looking for it. */
/* Each reason is a row of the list it sits in, like every other list on the
 * site. Without the row rhythm the plain sentence of one reason sat directly
 * under the verbatim gate text of the one before, and a rejected record with
 * six reasons read as one paragraph. */
.reason {
  display: block;
  padding-block: var(--space-4);
  border-bottom: var(--elevation-raised);
}

.reason__plain {
  margin: 0 0 var(--space-2);
  color: var(--ink);
  font-size: var(--fs-body);
  line-height: 1.6;
}

.reason__verbatim {
  margin: 0;
  color: var(--slate);
  font-size: var(--fs-sm);
  line-height: 1.6;
}

.reason__verbatim .record-code {
  color: var(--ink);
  font-weight: 600;
}

.verdict {
  display: inline-block;
  padding: 0.15em 0.7em;
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.5;
  white-space: nowrap;
  border: 1px solid transparent;
}

.verdict__word {
  display: inline-block;
}

/* Admitted: a pill. The most permissive shape for the most permissive state. */
.verdict--admitted {
  background: var(--ok-tint);
  color: var(--ok);
  border-color: var(--ok);
  border-radius: 999px;
}

/* Held: a rounded square, not a pill and not a sharp square. It sits between
 * the other two because the state sits between the other two: not a failure,
 * not admitted until a human rules or the licensor publishes the evidence. */
.verdict--held {
  background: var(--held-tint);
  color: var(--held);
  border-color: var(--held);
  border-radius: 4px;
}

/* Rejected: a sharp square. The only state with no softening at all. */
.verdict--rejected {
  background: var(--rej-tint);
  color: var(--rej);
  border-color: var(--rej);
  border-radius: 0;
}

/* Verdict table model links. Before this they were the only unstyled links on
 * the site, on the page that matters most: browser-default blue with an
 * underline. They now take the brand link colour and the site's own link
 * treatment. */
.table__key a {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}

.table__key a:hover,
.table__key a:focus-visible {
  text-decoration-thickness: 2px;
}

/* ---------------------------------------------------------------------------
   16. Form
   --------------------------------------------------------------------------- */

.form {
  display: grid;
  gap: var(--space-5);
  container-type: inline-size;
}

.field {
  display: grid;
  gap: var(--space-2);
}

.field__label {
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--ink);
}

.field__optional {
  font-weight: 400;
  color: var(--slate);
}

.field__help {
  font-size: var(--fs-label);
  color: var(--slate);
}

.field__control {
  width: 100%;
  min-height: var(--control-h);
  padding: var(--space-3);
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule-2);
  border-radius: var(--radius-surface);
  color: var(--ink);
  font-size: var(--fs-sm);
  transition: var(--transition);
}

.field__control:hover {
  border-color: var(--ink-2);
}

.field__control:focus-visible {
  border-color: var(--brand);
  outline: var(--focus-ring) solid var(--brand);
  outline-offset: var(--focus-offset);
}

textarea.field__control {
  resize: vertical;
}

select.field__control {
  appearance: none;
  padding-right: var(--space-7);
  /* The one hardcoded colour below the token block: a data URI cannot read a
     custom property, and the arrow is decorative (1.4.11 does not apply). The
     stroke is the slate value from the ramp. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%2357646d' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--space-4) center;
}

.field__control[aria-invalid="true"],
.field--invalid .field__control {
  border-color: var(--seal);
  background-color: var(--seal-tint);
}

.field__control[disabled] {
  background: var(--card);
  color: var(--slate);
  cursor: not-allowed;
}

.field__error {
  font-size: var(--fs-label);
  font-weight: 500;
  color: var(--seal);
}

.field__reason {
  font-size: var(--fs-label);
  color: var(--slate);
}

.field-row {
  display: grid;
  gap: var(--space-5);
}

/* Two fields side by side only when the form itself is wide enough. The
   rows keyed off the viewport, so beside the booking copy at 1440, in a card
   about 330px inside, the role select clipped "Choose one" and the email and
   estate fields sat at different heights under their help text. */
@container (min-width: 520px) {
  .field-row {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.form__submit {
  display: grid;
  gap: var(--space-3);
  justify-items: start;
}

.form__submit > .btn {
  width: 100%;
}

@media (min-width: 768px) {
  .form__submit > .btn {
    width: auto;
  }
}

.status {
  padding: var(--space-4);
  font-size: var(--fs-sm);
  border-radius: var(--radius-surface);
}

.status--sending {
  background: var(--elevation-sunken);
  color: var(--slate);
}

.status--success {
  background: var(--paper);
  border: var(--elevation-raised);
  color: var(--ink);
}

.status--failure {
  background: var(--seal-tint);
  border: var(--rule-hair) solid var(--seal);
  color: var(--ink);
  display: grid;
  gap: var(--space-3);
  justify-items: start;
}

/* ---------------------------------------------------------------------------
   17. The booking panel. The dark accent surface used with intent: the one
   place on a light page where the ask gets a band of its own. The form itself
   is a raised paper card inside it, so every field keeps the light-theme pairs.
   --------------------------------------------------------------------------- */

/* One dark band treatment, shared by the about page's booking section and any
   .section--dark (the home page's closing CTA). Identical declarations, so the
   about page's output is unchanged and the two read as the same treatment. */
#book,
.section--dark {
  background: var(--navy);
  color: var(--on-dark);
  border-block: var(--rule-hair) solid var(--on-dark-rule);
}

#book .h2,
.section--dark .h2 {
  color: var(--on-dark);
}

#book .prose,
#book .sm,
#book .lead,
.section--dark .prose,
.section--dark .sm,
.section--dark .lead {
  color: var(--on-dark-muted);
}

#book a.link,
.section--dark a.link,
.section--dark .text-link,
.hero a.link,
.hero .text-link {
  color: var(--brand-on-dark);
}

#book a.link:hover,
.section--dark a.link:hover,
.section--dark .text-link:hover,
.hero a.link:hover,
.hero .text-link:hover {
  color: var(--on-dark);
}

#book .form,
.section--dark .form {
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
  box-shadow: var(--shadow-floating);
  padding: var(--space-5);
}

@media (min-width: 1024px) {
  #book .form,
  .section--dark .form {
    padding: var(--space-6);
  }
}

/* On the dark band the action is the brightest object: the light button with
   navy text, the hero's rule. Inside a light card or a light form the band
   must not tint the control. The light-theme pairs are restored there, because
   brand-on-dark is 2.16:1 on paper, under the 3:1 floor. */
.section--dark .btn--primary {
  background: var(--on-dark);
  color: var(--navy);
  border-color: var(--on-dark);
}

.section--dark .btn--primary:hover {
  background: var(--on-brand);
  color: var(--navy);
  border-color: var(--on-brand);
}

.section--dark .btn--secondary {
  background: transparent;
  color: var(--on-dark);
  border-color: var(--on-dark-rule);
}

.section--dark .btn--secondary:hover {
  border-color: var(--on-dark);
  color: var(--on-dark);
}

.section--dark .form .btn--primary,
.section--dark .card .btn--primary {
  background: var(--brand);
  color: var(--paper);
  border-color: var(--brand);
}

.section--dark .form .btn--primary:hover,
.section--dark .card .btn--primary:hover {
  background: var(--brand-deep);
  border-color: var(--brand-deep);
}

.section--dark .form .btn--secondary,
.section--dark .card .btn--secondary {
  background: transparent;
  color: var(--brand);
  border-color: var(--rule-2);
}

.section--dark .form .btn--secondary:hover,
.section--dark .card .btn--secondary:hover {
  border-color: var(--brand);
  color: var(--brand-deep);
}

/* ---------------------------------------------------------------------------
   18. Footer. A company footer: the frame the hero opens, and the one place
   the disclaimer is pinned. The dark band is the same navy as the masthead.
   --------------------------------------------------------------------------- */

.footer {
  background: var(--navy);
  color: var(--on-dark-muted);
  padding-block: var(--space-8) var(--space-6);
}

.footer__grid {
  display: grid;
  gap: var(--space-6);
}

.footer__heading {
  font-size: var(--fs-label);
  font-weight: 600;
  color: var(--on-dark);
  margin-bottom: var(--space-4);
}

.footer__mark {
  font-size: var(--fs-h4);
  font-weight: 650;
  letter-spacing: var(--track-mark);
  color: var(--on-dark);
}

.footer__text {
  font-size: var(--fs-label);
  color: var(--on-dark-muted);
  margin-top: var(--space-2);
  max-width: 36ch;
}

.footer__list {
  display: grid;
  gap: var(--space-3);
}

.footer__list a {
  color: var(--on-dark-muted);
  text-decoration: none;
  font-size: var(--fs-label);
  transition: var(--transition);
}

.footer__list a:hover {
  color: var(--on-dark);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer__bottom {
  margin-top: var(--space-8);
  padding-top: var(--space-5);
  border-top: var(--rule-hair) solid var(--on-dark-rule);
  display: grid;
  gap: var(--space-3);
}

.footer__note,
.footer__legal {
  font-size: var(--fs-label);
  color: var(--on-dark-muted);
}

.footer__note {
  max-width: 74ch;
}

@media (max-width: 767px) {
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--space-5) var(--space-4);
  }

  .footer__grid > :first-child {
    grid-column: 1 / -1;
  }
}

@media (min-width: 768px) {
  .footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .footer__grid {
    grid-template-columns: 1.6fr 1fr 1fr 1fr;
    gap: var(--space-6);
  }

  .footer__bottom {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    gap: var(--space-6);
  }
}

/* ---------------------------------------------------------------------------
   19. Diagram
   --------------------------------------------------------------------------- */

.diagram {
  display: block;
  width: 100%;
  max-width: 560px;
  height: auto;
  margin-top: var(--space-6);
}

.diagram text {
  font-family: var(--font-sans);
  fill: var(--ink);
}

.diagram .d-title {
  font-size: 18px;
  font-weight: 600;
}

.diagram .d-note {
  font-size: 16px;
  fill: var(--slate);
}

.diagram .d-box {
  fill: var(--paper);
  stroke: var(--rule-2);
  stroke-width: 1.5;
}

.diagram .d-accent {
  fill: var(--brand-tint);
  stroke: var(--brand);
  stroke-width: 2;
}

.diagram .d-boundary {
  fill: none;
  stroke: var(--ink);
  stroke-width: 2;
}

.diagram .d-severable {
  fill: none;
  stroke: var(--rule-2);
  stroke-width: 2;
  stroke-dasharray: 7 6;
}

.diagram .d-arrow {
  stroke: var(--ink);
  stroke-width: 1.5;
}

.diagram .d-head {
  fill: var(--ink);
}

/* ---------------------------------------------------------------------------
   20. The verdict record pages (design review 2026-09-25, item 8).

   The index is data-led and the detail page reads in the order a CISO does:
   the verdict first, then what was checked, then why, then what the verdict
   does not cover, then how to verify it, then the full record. The facts sit
   in a side panel that sticks beside the argument at desktop width and folds
   below it on a phone. The limit callout, the not-verified labels and the
   backfill marker are never collapsed and never smaller than body: they are
   the parts that must never be hidden.

   The list rows are the compact record card (design review item 17): the
   labels are visually hidden and the fields sit on one wrapping line, which
   is right for a list of records and wrong for a key/value table. At desktop
   the same rows align into columns under their labels.
   --------------------------------------------------------------------------- */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.tag {
  display: inline-block;
  padding: 0 0.35em;
  border: var(--rule-hair) solid var(--rule-2);
  border-radius: 4px;
  font-family: var(--font-mono);
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--slate);
  white-space: nowrap;
}

.mono {
  font-family: var(--font-mono);
  font-size: 0.92em;
  overflow-wrap: anywhere;
}

/* The counts sentence: the record's size stated before the rows. */
.counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 0.5rem;
  margin: var(--space-4) 0 0;
  font-size: var(--fs-body);
}

.counts strong {
  font-size: var(--fs-h4);
}

.counts__latest {
  color: var(--slate);
}

/* The entry layout: the argument, and the facts beside it. */
.entry-grid {
  display: grid;
  gap: var(--space-6);
}

@media (min-width: 1000px) {
  .entry-grid {
    grid-template-columns: minmax(0, 1fr) 20rem;
    align-items: start;
  }

  .entry-side {
    position: sticky;
    top: calc(var(--nav-h) + var(--space-4));
  }
}

.entry__org {
  display: block;
  margin-bottom: 0.2rem;
  color: var(--slate);
  font-size: 0.55em;
  font-weight: 500;
  letter-spacing: 0;
}

/* The verdict panel: the badge, one plain sentence, and what the state
 * means. The top rule is the state colour, so the panel's edge carries the
 * verdict too. */
.entry-verdict {
  padding: var(--space-5);
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule);
  border-top: 6px solid var(--held);
  border-radius: var(--radius-surface);
}

.entry-verdict--admitted {
  border-top-color: var(--ok);
}

.entry-verdict--held {
  border-top-color: var(--held);
}

.entry-verdict--rejected {
  border-top-color: var(--rej);
}

.entry-verdict > .verdict {
  padding: 0.45rem 0.85rem 0.45rem 0.65rem;
  font-size: var(--fs-body);
}

.entry-verdict > .verdict .v-ico {
  width: 1.2rem;
  height: 1.2rem;
}

.entry-verdict__lead {
  max-width: var(--measure-callout);
  margin: var(--space-4) 0 0;
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
}

.entry-verdict__what {
  margin: var(--space-3) 0 0;
  color: var(--ink-2);
}

/* The mandatory limit, in one line at the foot of the panel, with the link
 * to the page that explains what a verdict covers. */
.entry-verdict__limit {
  margin: var(--space-4) 0 0;
  padding-top: var(--space-3);
  border-top: var(--rule-hair) solid var(--rule);
  color: var(--slate);
  font-size: var(--fs-label);
}

/* What was checked: one card, four cells divided by hairlines. The card's
 * rule colour shows through a 1px gap, so the dividers are exact at every
 * width and there is no loose ground between separately bordered boxes. */
.checks.checks--grid {
  display: grid;
  gap: var(--rule-hair);
  overflow: hidden;
  background: var(--rule);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
}

.checks--grid .chk,
.checks--grid .chk:first-child {
  grid-template-columns: 1.25rem minmax(0, 1fr);
  padding: var(--space-5);
  background: var(--paper);
  border: 0;
}

@media (min-width: 600px) {
  .checks.checks--grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.chk__t {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--space-2);
  font-size: var(--fs-body);
  font-weight: 650;
  line-height: var(--lh-tight);
}

.chk__t .chk__w {
  margin-left: 0;
}

.chk__d {
  margin-top: var(--space-2);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-lead);
}

/* More than one kind of finding: the reasons as a short list in the panel,
 * each marked in the state's colour. */
.entry-verdict__reasons {
  display: grid;
  gap: var(--space-2);
  max-width: var(--measure-callout);
  margin: var(--space-4) 0 0;
  padding: 0;
  list-style: none;
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
}

.entry-verdict__reasons li {
  position: relative;
  padding-left: var(--space-5);
}

.entry-verdict__reasons li::before {
  content: "";
  position: absolute;
  left: var(--space-1);
  top: 0.65em;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--held);
}

.entry-verdict--rejected .entry-verdict__reasons li::before {
  background: var(--rej);
}

/* Verify this verdict: one line and the command. */
.entry-verify {
  padding: var(--space-5);
  background: var(--card);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
}

.entry-verify p {
  margin-top: var(--space-2);
  font-size: var(--fs-sm);
}

.entry-verify .verify-cmd {
  margin-bottom: 0;
  background: var(--paper);
}

/* The list's one-line limit under the legend. */
.vlegend__limit {
  margin-top: var(--space-5);
  color: var(--slate);
  font-size: var(--fs-sm);
}

/* What was checked: one row per aspect, each with its own state. */
.checks {
  margin: 0;
  padding: 0;
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
  list-style: none;
}

.chk {
  display: grid;
  grid-template-columns: 1.5rem minmax(0, 1fr);
  gap: var(--space-3);
  padding: var(--space-4);
  border-top: var(--rule-hair) solid var(--rule);
}

.chk:first-child {
  border-top: 0;
}

.chk__i {
  display: block;
  margin-top: 0.15rem;
}

.chk__i svg {
  width: 1.25rem;
  height: 1.25rem;
}

.chk__i--ok {
  color: var(--ok);
}

.chk__i--held {
  color: var(--held);
}

.chk__i--rej {
  color: var(--rej);
}

.chk__i--na {
  color: var(--slate);
}

.chk__w {
  margin-left: 0.35rem;
  color: var(--slate);
  font-size: var(--fs-label);
  font-weight: 600;
}

/* The side panel: the facts a reader checks first. */
.entry-side {
  padding: var(--space-5);
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
}

.facts {
  display: grid;
  gap: var(--space-3);
  margin: 0;
}

.facts div {
  display: grid;
  gap: 0.15rem;
}

.facts dt {
  color: var(--slate);
  font-size: var(--fs-label);
  font-weight: 650;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.facts dd {
  margin: 0;
  font-size: var(--fs-sm);
  line-height: var(--lh-lead);
  overflow-wrap: anywhere;
}

/* The full record: the only thing on the page allowed to collapse, because
 * it is the record rather than a caveat. */
.raw > summary {
  cursor: pointer;
  font-weight: 650;
}

.raw[open] > summary {
  margin-bottom: var(--space-3);
}

/* The badge, in the mockup's shape: the state mark (circle with a tick,
   pause bars, an octagon with a cross) and the word together, so each state
   reads in greyscale and to a colour-blind reader. */
.verdict {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.65rem 0.35rem 0.5rem;
  font-size: var(--fs-label);
  font-weight: 650;
}

.v-ico {
  width: 1rem;
  height: 1rem;
  flex: none;
}

/* The one notice under the list's counts: the backfill disclosure in the
   review's compact shape. */
.vnotice {
  max-width: 48rem;
  margin: var(--space-4) 0 0;
  padding: 0.75rem 1rem;
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule);
  border-left: 4px solid var(--rule-2);
  border-radius: 6px;
  font-size: var(--fs-sm);
}

.verify-cmd {
  margin: 0.5rem 0;
  padding: 0.75rem;
  overflow-x: auto;
  background: var(--card);
  border: var(--rule-hair) solid var(--rule);
  border-radius: 8px;
  font-family: var(--font-mono);
  font-size: var(--fs-mono);
}

.copy {
  margin-left: 0.4rem;
  padding: 0.1rem 0.45rem;
  background: var(--paper);
  color: var(--ink);
  border: var(--rule-hair) solid var(--rule-2);
  border-radius: 6px;
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}
/* The booking panel, beside the argument's end. */
.entry-cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  align-items: center;
  justify-content: space-between;
  padding: var(--space-5);
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
}

.entry-cta p {
  max-width: 36rem;
  margin: 0;
}

/* The index opens with an ordinary section rather than a masthead, and the
 * filter bar sits between it and the list. With a full section's padding on
 * both sides of the bar there was 128px of ground above it and 128px below,
 * which put the first row 845px down a 900px viewport: the problem the
 * redesign was meant to fix. The intro takes the masthead's rhythm, and the
 * list starts right under the bar. */
.section:has(+ .vbar) {
  padding-block: var(--space-7) var(--space-6);
}

.vbar + .section {
  padding-top: var(--space-5);
}

@media (min-width: 1024px) {
  .section:has(+ .vbar) {
    padding-block: var(--space-8) var(--space-6);
  }
}

/* The list's filter bar: hidden without the script, sticky on desktop and
 * scrolling away on a phone. */
.vbar {
  padding: var(--space-3) 0;
  background: var(--ground);
  border-block: var(--rule-hair) solid var(--rule);
}

@media (min-width: 900px) {
  .vbar {
    position: sticky;
    top: var(--nav-h);
    z-index: 3;
  }
}

.vbar .container {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  align-items: center;
}

.seg {
  display: inline-flex;
  overflow: hidden;
  border: var(--rule-hair) solid var(--rule-2);
  border-radius: var(--radius-surface);
}

.seg button {
  min-height: 2.5rem;
  padding: 0.45rem 0.75rem;
  background: var(--paper);
  color: var(--ink);
  border: 0;
  border-right: var(--rule-hair) solid var(--rule);
  font: inherit;
  font-size: var(--fs-label);
  cursor: pointer;
}

.seg button:last-child {
  border-right: 0;
}

.seg button[aria-pressed="true"] {
  background: var(--ink);
  color: var(--paper);
}

.vbar__sel,
.vbar__q {
  min-height: 2.5rem;
  padding: 0.35rem 0.6rem;
  background: var(--paper);
  color: var(--ink);
  border: var(--rule-hair) solid var(--rule-2);
  border-radius: var(--radius-surface);
  font: inherit;
  font-size: var(--fs-label);
}

.vbar__q {
  flex: 1 1 12rem;
}

.vbar__shown {
  margin-left: auto;
  color: var(--slate);
  font-size: var(--fs-label);
}

/* The rows. One record per row, the verdict first. At desktop the same
 * fields line up under the column labels. */
.vmonth {
  margin: var(--space-5) 0 var(--space-2);
  color: var(--slate);
  font-size: var(--fs-label);
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vcols {
  display: none;
}

/* The month label sits under the column labels, so it closes up to them. */
.vcols + .vmonth {
  margin-top: var(--space-2);
}

.vlist {
  margin: 0;
  padding: 0;
  background: var(--paper);
  border: var(--rule-hair) solid var(--rule);
  border-radius: var(--radius-surface);
  list-style: none;
}

.vrow {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.3rem;
  padding: var(--space-3) var(--space-4);
  border-top: var(--rule-hair) solid var(--rule);
  transition: var(--transition);
}

.vrow:hover {
  background: var(--card);
}

.vrow:first-child {
  border-top: 0;
}

.vrow[hidden] {
  display: none;
}

/* The name is the row's link, so it reads as a name: no underline until the
 * row is pointed at, the way the mockup sets it. */
.vrow__name {
  color: var(--ink);
  font-weight: 650;
  text-decoration: none;
  overflow-wrap: anywhere;
}

.vrow:hover .vrow__name,
.vrow__name:focus-visible {
  text-decoration: underline;
  text-decoration-thickness: var(--rule-hair);
  text-underline-offset: 3px;
}

.vrow__org {
  color: var(--slate);
  font-weight: 450;
}

.vrow__why {
  margin: 0.2rem 0 0;
  color: var(--ink-2);
  font-size: var(--fs-sm);
}

.vrow__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.2rem var(--space-4);
  margin: 0;
  color: var(--slate);
  font-size: var(--fs-label);
}

.vrow__meta div {
  display: flex;
  gap: 0.3rem;
}

.vrow__meta dt {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

.vrow__meta dd {
  margin: 0;
}

/* The backfill label on each entry is pinned and stays visible; it reads as
 * a label beside the date rather than a shouted word in the date column. */
.vrow__meta strong,
.facts strong {
  display: inline-block;
  padding: 0 0.4em;
  border: var(--rule-hair) solid var(--rule-2);
  border-radius: 4px;
  color: var(--slate);
  font-size: var(--fs-xs);
  font-weight: 650;
  letter-spacing: 0.04em;
  line-height: 1.6;
  vertical-align: 0.1em;
}

/* On a phone the revision waits for the entry page, as in the mockup. Two
 * classes deep, because `.vrow__meta div` sets display and would otherwise win
 * and wrap every row's facts onto a second line. */
.vrow__meta .vrow__rev {
  display: none;
}

@media (min-width: 900px) {
  /* The verdict column fits the longest badge on one line; the other
   * columns are sized to their longest value. */
  .vcols {
    display: grid;
    grid-template-columns: 9rem minmax(0, 1fr) 5.5rem 8.5rem 10rem 5.5rem;
    gap: var(--space-4);
    padding: var(--space-2) var(--space-4);
    color: var(--slate);
    font-size: var(--fs-label);
    font-weight: 650;
    letter-spacing: 0.05em;
    text-transform: uppercase;
  }

  .vrow {
    grid-template-columns: 9rem minmax(0, 1fr) 5.5rem 8.5rem 10rem 5.5rem;
    gap: var(--space-4);
    align-items: baseline;
  }

  .vrow__name {
    font-size: var(--fs-sm);
  }


  .vrow__meta {
    display: contents;
  }

  .vrow__meta div,
  .vrow__meta .vrow__rev {
    display: block;
  }

  .vrow__meta dt {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }
}

/* The legend: the three states and the evidence tiers, defined beside the
 * badges that carry them. */
.vlegend {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-6);
  font-size: var(--fs-sm);
}

.vlegend div {
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
}

.vlegend div > span:last-child {
  flex: 1;
  min-width: 0;
}

/* The regulator letter guide. A reading page: the four areas as a numbered list,
   the mapping as the site table (stacked into labelled cards on a phone), and
   status as a labelled chip with an icon, never colour alone. */
.guide__byline {
  margin-top: var(--space-5);
  color: var(--slate);
  font-size: var(--fs-label);
}

.prose-stack {
  display: grid;
  gap: var(--space-4);
}

.guide__areas {
  display: grid;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: area;
}

@media (min-width: 768px) {
  .guide__areas {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.guide__areas li {
  counter-increment: area;
  padding: var(--space-5);
  background: var(--paper);
  border: var(--elevation-raised);
  border-top: var(--rule-strong) solid var(--brand);
  border-radius: var(--radius-surface);
}

.guide__areas .h3::before {
  content: counter(area) ". ";
  color: var(--brand);
}

.guide__areas p {
  margin-top: var(--space-3);
  color: var(--ink-2);
  font-size: var(--fs-sm);
  line-height: var(--lh-lead);
}

.guide__note {
  max-width: var(--measure-prose);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.2rem 0.6rem;
  border: var(--rule-hair) solid currentColor;
  border-radius: 999px;
  font-size: var(--fs-label);
  font-weight: 600;
  white-space: nowrap;
}

.chip__icon {
  width: 0.7rem;
  height: 0.7rem;
  flex: none;
  border-radius: 50%;
}

.chip--available {
  color: var(--ok);
  background: var(--ok-tint);
}

.chip--available .chip__icon {
  background: currentColor;
}

.chip--partial {
  color: var(--held);
  background: var(--held-tint);
}

/* Half filled: partly there. */
.chip--partial .chip__icon {
  background: linear-gradient(90deg, currentColor 50%, transparent 50%);
  border: 1.5px solid currentColor;
}

.chip--none {
  color: var(--slate);
  background: var(--paper);
}

/* An outline: not provided. */
.chip--none .chip__icon {
  border: 1.5px solid currentColor;
}

.guide__map td:nth-child(3) {
  white-space: nowrap;
}

@media (max-width: 767px) {
  .guide__map td:nth-child(3) {
    white-space: normal;
    margin-block: var(--space-2);
  }
}

.guide__disclaimer p {
  max-width: var(--measure-prose);
}

.guide__print-source {
  display: none;
}

/* ---------------------------------------------------------------------------
   21. Print. The second and last place absolute colours appear: a printer does
   not print backgrounds by default, so every dark band would put light text on
   white. Footer, hero and booking panel go to ink on paper; the black artefacts
   in the body are hidden rather than printed as unreadable blocks.
   --------------------------------------------------------------------------- */

@media print {
  body {
    background: #fff;
  }

  /* Controls that do nothing on paper: the verdict filter bar and the
     revision's copy button. The record they act on prints in full. */
  .vbar,
  .copy {
    display: none !important;
  }

  /* The letter guide prints for a risk team: no navigation or buttons, the
     mapping kept together, and the source and review date on the last page. */
  .guide .btn-row,
  .guide .breadcrumb,
  .nav,
  .skip {
    display: none !important;
  }

  .guide .section,
  .guide .masthead {
    padding-block: 12pt;
  }

  .guide__map {
    font-size: 9pt;
  }

  .guide__map tr {
    break-inside: avoid;
  }

  .guide__map th,
  .guide__map td {
    padding: 4pt 6pt;
  }

  .guide__print-source {
    display: block;
    margin-top: 12pt;
    font-size: 9pt;
  }

  .guide__byline a::after {
    content: " (" attr(href) ")";
  }

  .entry-side {
    position: static;
  }

  .footer,
  .footer__bottom,
  .hero,
  #book,
  .section--dark {
    background: #fff;
    color: #000;
    border-color: #000;
    box-shadow: none;
  }

  .footer__mark,
  .footer__heading,
  .footer__text,
  .footer__note,
  .footer__legal,
  .footer__list a,
  .hero .h1,
  .hero .lead,
  #book .h2,
  #book .prose,
  #book .sm,
  #book a.link,
  .section--dark .h2,
  .section--dark .prose,
  .section--dark .sm,
  .section--dark a.link,
  .section--dark .text-link {
    color: #000;
  }

  .hero .btn--primary {
    background: #fff;
    color: #000;
    border-color: #000;
  }

  .nav,
  .skip,
  .form,
  .hero__actions,
  .footer__grid,
  .footer__note,
  .btn-row,
  .pager,
  .exhibit {
    display: none !important;
  }

  .section,
  .hero,
  .masthead {
    padding-block: 12pt;
    break-inside: avoid;
  }

  .caveat,
  .list__item,
  .pillar,
  .step,
  .shot,
  .price,
  .card,
  .vcard {
    break-inside: avoid;
    box-shadow: none;
  }

  a {
    color: inherit;
    text-decoration: none;
  }
}

/* ---------------------------------------------------------------------------
   22. Mobile body size and compact list tables
   (design review 2026-09-25, item 17)
   --------------------------------------------------------------------------- */

/* Body text on a phone drops from 1.125rem / 1.7 to 1.0625rem / 1.6. Combined
 * with the long pages, the larger setting is why Pricing and How it works ran
 * to about 11,000 px on a phone. The measure is unchanged: only the size and
 * the leading move. Below 600px only, so nothing shifts on a tablet or a
 * laptop. */
@media (max-width: 599px) {
  :root {
    --fs-body: 1.0625rem;
    --lh-body: 1.6;
  }

  body {
    line-height: 1.6;
  }
}

/* Compact list tables.
 *
 * .table--stack turns each row into a labelled card, which is right for a key
 * and value table and wrong for a list of records. On the verdicts index and
 * the price list, stacking gave every one of 22 rows a card of about 400px:
 * eleven screens for what is a list.
 *
 * .table--list keeps the row compact instead: the labels are visually hidden
 * rather than removed, so a screen reader still announces what each field is,
 * and the fields sit on one wrapping line. */
@media (max-width: 767px) {
  .table--list caption {
    display: block;
    width: 100%;
  }

  .table--list thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .table--list,
  .table--list tbody,
  .table--list tr {
    display: block;
    width: 100%;
  }

  .table--list tr {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-4);
    align-items: baseline;
    padding-block: var(--space-3);
    border-bottom: var(--elevation-raised);
  }

  .table--list td {
    display: inline-flex;
    align-items: baseline;
    gap: 0.35em;
    padding: 0;
    border: 0;
    background: transparent;
    width: auto;
    flex: 0 1 auto;
    min-width: 0;
  }

  /* The label stays in the accessibility tree and out of the layout: a screen
   * reader still announces what each field is while the row stays one line. */
  .table--list .td-k {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* The model is the row's name and gets the emphasis the card layout used to
   * give it. */
  .table--list .table__key {
    flex: 1 0 100%;
    font-weight: 600;
  }

  .table--list tbody tr:nth-child(even) td {
    background: transparent;
    border-radius: 0;
  }
}
