/* BlueWorkz design system
 * ============================================================================
 * Built from the existing brand pack, not invented: Blue #0E52C9, dark-UI blue
 * #7B92FF, Ink #0F1626, Paper #FFFFFF. The mark is "the Hub" and its usage
 * rules are enforced here where CSS can enforce them (clear space, minimum
 * size, the light/dark variant swap) and stated on /styleguide/ where it
 * cannot.
 *
 * Conventions
 * -----------
 *   - Every class is prefixed `bwz-`. Block, `__element`, `--modifier`.
 *   - Light and dark are both first class. Nothing is "the dark override".
 *   - Brand hexes appear exactly once, in §1, as --bwz-brand-*. Everything
 *     else refers to a *role* token, so a component never names a colour.
 *   - Every foreground/background pair in §2 is checked against WCAG AA by
 *     core/design.py, and core/tests.py fails the build if one drops below.
 *
 * Targets: 320px minimum width, desktop and mobile parity, current and
 * previous major of Chrome, Safari, Firefox and Edge. No CSS nesting, no
 * :has(), no container queries — all four browsers support them at current,
 * not all at previous-major.
 * ============================================================================ */

/* ---------------------------------------------------------------------------
 * 1. Brand constants — the same in every theme, because they are the brand
 * ------------------------------------------------------------------------- */

:root {
  --bwz-brand-blue: #0E52C9;
  --bwz-brand-blue-dark-ui: #7B92FF;
  --bwz-brand-ink: #0F1626;
  --bwz-brand-paper: #FFFFFF;
}

/* ---------------------------------------------------------------------------
 * 2. Role tokens — light is the default, and is defined on bare :root so that
 *    no colour has its only definition inside a media query.
 * ------------------------------------------------------------------------- */

:root {
  color-scheme: light;

  /* Surfaces, back to front */
  --bwz-bg: #FFFFFF;
  --bwz-surface: #FFFFFF;
  --bwz-surface-2: #F4F6FB;
  --bwz-surface-3: #E9EEF7;

  /* Text */
  --bwz-fg: #0F1626;
  --bwz-fg-muted: #4A5568;
  --bwz-fg-subtle: #5C6880;

  /* Lines */
  --bwz-rule: #DDE3ED;
  --bwz-rule-strong: #B9C3D4;
  --bwz-field-border: #767F94;   /* 4.0:1 on paper — SC 1.4.11 wants 3:1 */

  /* Accent */
  --bwz-accent: #0E52C9;
  --bwz-accent-hover: #0B41A1;
  --bwz-accent-active: #083079;
  --bwz-accent-fg: #FFFFFF;
  --bwz-accent-surface: #EAF0FD;

  /* Status — the dashboard is a traffic light, so these are load-bearing */
  --bwz-ok: #0F7040;
  --bwz-ok-surface: #E6F4EC;
  --bwz-warn: #8A5300;
  --bwz-warn-surface: #FCF1DE;
  --bwz-danger: #B3251C;
  --bwz-danger-surface: #FCEBE9;

  /* A tile for somebody else's logo. Paper in BOTH themes, on purpose: a
   * partner mark is supplied in one colourway and may not be recoloured,
   * inverted or filtered, so the ground moves to it rather than the other way
   * round. The precedent is the brand pack's own instruction for putting a
   * lockup on a dark ground — it sits on its own Paper tile. */
  --bwz-logo-tile: #FFFFFF;
  --bwz-logo-tile-rule: #DDE3ED;

  /* Elevation. Deliberately restrained: the brand is flat. */
  --bwz-shadow-sm: 0 1px 2px rgba(15, 22, 38, 0.06);
  --bwz-shadow-md: 0 2px 8px rgba(15, 22, 38, 0.08);
  --bwz-shadow-lg: 0 12px 32px rgba(15, 22, 38, 0.12);
  --bwz-overlay: rgba(15, 22, 38, 0.55);
}

/* Dark, by system preference — unless the reader has explicitly chosen light. */
@media (prefers-color-scheme: dark) {
  :root:not([data-bwz-theme="light"]) {
    color-scheme: dark;

    --bwz-bg: #0F1626;
    --bwz-surface: #161F33;
    --bwz-surface-2: #1C2740;
    --bwz-surface-3: #24314E;

    --bwz-fg: #EEF1F7;
    --bwz-fg-muted: #A9B4C8;
    --bwz-fg-subtle: #8F9BB1;

    --bwz-rule: #2A3853;
    --bwz-rule-strong: #3D4E70;
    --bwz-field-border: #68799F;

    --bwz-accent: #7B92FF;
    --bwz-accent-hover: #9EAFFF;
    --bwz-accent-active: #B9C5FF;
    --bwz-accent-fg: #0B1020;
    --bwz-accent-surface: #1A2444;

    --bwz-ok: #4FC98C;
    --bwz-ok-surface: #12301F;
    --bwz-warn: #E9B159;
    --bwz-warn-surface: #33260F;
    --bwz-danger: #FF8B82;
    --bwz-danger-surface: #3A1B18;

    /* Unchanged in the dark theme. See the note beside the light value. */
    --bwz-logo-tile: #FFFFFF;
    --bwz-logo-tile-rule: #DDE3ED;

    --bwz-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --bwz-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.45);
    --bwz-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.55);
    --bwz-overlay: rgba(4, 8, 16, 0.7);
  }
}

/* Dark, chosen explicitly. Repeated rather than shared so the toggle wins in
 * both directions: a reader on a light system can still pick dark. */
:root[data-bwz-theme="dark"] {
  color-scheme: dark;

  --bwz-bg: #0F1626;
  --bwz-surface: #161F33;
  --bwz-surface-2: #1C2740;
  --bwz-surface-3: #24314E;

  --bwz-fg: #EEF1F7;
  --bwz-fg-muted: #A9B4C8;
  --bwz-fg-subtle: #8F9BB1;

  --bwz-rule: #2A3853;
  --bwz-rule-strong: #3D4E70;
  --bwz-field-border: #68799F;

  --bwz-accent: #7B92FF;
  --bwz-accent-hover: #9EAFFF;
  --bwz-accent-active: #B9C5FF;
  --bwz-accent-fg: #0B1020;
  --bwz-accent-surface: #1A2444;

  --bwz-ok: #4FC98C;
  --bwz-ok-surface: #12301F;
  --bwz-warn: #E9B159;
  --bwz-warn-surface: #33260F;
  --bwz-danger: #FF8B82;
  --bwz-danger-surface: #3A1B18;

  /* Unchanged in the dark theme. See the note beside the light value. */
  --bwz-logo-tile: #FFFFFF;
  --bwz-logo-tile-rule: #DDE3ED;

  --bwz-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --bwz-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.45);
  --bwz-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.55);
  --bwz-overlay: rgba(4, 8, 16, 0.7);
}

/* ---------------------------------------------------------------------------
 * 3. Type, space and shape — theme-independent
 * ------------------------------------------------------------------------- */

:root {
  --bwz-font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  --bwz-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
    "Liberation Mono", monospace;

  /* Type scale. Body is fixed; headings are fluid so that a 320px phone and a
   * 1440px desktop both get a sensible measure without a breakpoint each. */
  --bwz-text-xs: 0.75rem;      /* 12px — meta, table captions            */
  --bwz-text-sm: 0.875rem;     /* 14px — helper text, badges             */
  --bwz-text-base: 1rem;       /* 16px — body. Never smaller on mobile.  */
  --bwz-text-md: 1.125rem;     /* 18px — lede                            */
  --bwz-text-lg: clamp(1.25rem, 0.5vw + 1.15rem, 1.375rem);
  --bwz-text-xl: clamp(1.5rem, 1vw + 1.3rem, 1.75rem);
  --bwz-text-2xl: clamp(1.75rem, 2vw + 1.4rem, 2.25rem);
  --bwz-text-3xl: clamp(2rem, 4vw + 1.25rem, 3rem);

  --bwz-leading-tight: 1.15;
  --bwz-leading-snug: 1.35;
  --bwz-leading-normal: 1.6;

  --bwz-weight-normal: 400;
  --bwz-weight-medium: 500;
  --bwz-weight-semibold: 600;
  --bwz-weight-bold: 700;

  --bwz-tracking-tight: -0.02em;
  --bwz-tracking-normal: 0;
  --bwz-tracking-wide: 0.08em;

  /* Spacing — a 4px base, named by step, not by intent. */
  --bwz-space-1: 0.25rem;
  --bwz-space-2: 0.5rem;
  --bwz-space-3: 0.75rem;
  --bwz-space-4: 1rem;
  --bwz-space-5: 1.5rem;
  --bwz-space-6: 2rem;
  --bwz-space-7: 3rem;
  --bwz-space-8: 4rem;
  --bwz-space-9: 6rem;

  --bwz-radius-sm: 4px;
  --bwz-radius-md: 8px;
  --bwz-radius-lg: 14px;
  --bwz-radius-full: 999px;

  --bwz-border: 1px;
  --bwz-border-thick: 2px;

  /* Layout.
   *
   * Widened on Dan's instruction, ticket 869evwwzn, 2026-09-07: "All the
   * content is constrained to a width which is too narrow — on wider screens,
   * make it flow wider if the window is wider."
   *
   * The container went 68rem -> 96rem, so a card grid, a picture and the
   * header now use a 1600px screen instead of leaving a third of it empty.
   * The reading measure did NOT double with it, and that is deliberate: line
   * length is the one width where more is worse. 34rem is about 68 characters
   * and 40rem is about 80, which is the top of the readable band; twice 34rem
   * would be roughly 135 characters a line and a reader loses their place
   * returning to the left edge. So the page got wider and the paragraph got a
   * little wider — the empty space a wide window used to show is now filled by
   * the things that can use it. */
  --bwz-container: 96rem;
  --bwz-container-narrow: 52rem;
  --bwz-container-wide: 112rem;
  --bwz-measure: 40rem;      /* ~80 characters — the top of the readable band */
  /* [DAN'S DECISION, and it is his second time asking] 2026-09-09, 869evwx03:
   * "make the content area twice as wide, if the browser window is wide enough
   * to support it". The last session widened the container and deliberately did
   * NOT widen the reading measure, on the argument recorded above; he has now
   * repeated the instruction having seen that result, so the measure doubles.
   *
   * It doubles only where the clause in his sentence is satisfied — at 90em and
   * up, which is a window of about 1440px. Below that nothing moves at all, so
   * every phone, tablet and laptop keeps the 40rem measure. And it applies to
   * the marketing pages only (section 10c), never to a form, the dashboard or
   * the questionnaire, where a 1280px-wide text field is a defect. */
  --bwz-measure-wide: 80rem;
  --bwz-gutter: 1rem;

  /* The Hub mark: the centre circle is r=8 in a 48 viewBox, so its width is
   * exactly one third of the mark. That is the brand pack's clear space. */
  --bwz-mark-size: 2rem;
  --bwz-mark-clearspace: calc(var(--bwz-mark-size) / 3);
  --bwz-mark-min: 20px;      /* below this, use the favicon variant */

  --bwz-duration: 140ms;
  --bwz-ease: cubic-bezier(0.2, 0, 0.2, 1);

  --bwz-z-header: 100;
  --bwz-z-overlay: 200;
}

@media (min-width: 40em) {
  :root { --bwz-gutter: 1.5rem; }
}

/* A 96rem container on a 1600px screen has almost no margin left. The gutter
 * grows once there is room for it, which is the one place a breakpoint earns
 * its keep: it changes a spacing value, not a layout. */
@media (min-width: 90em) {
  :root { --bwz-gutter: 2.5rem; }
}

/* ---------------------------------------------------------------------------
 * 4. Reset and element defaults
 * ------------------------------------------------------------------------- */

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

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

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

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

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

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

.bwz-body {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bwz-bg);
  color: var(--bwz-fg);
  font-family: var(--bwz-font-sans);
  font-size: var(--bwz-text-base);
  line-height: var(--bwz-leading-normal);
  -webkit-font-smoothing: antialiased;
  /* An overflowing table or code block must scroll inside its own box, never
   * push the page sideways. At 320px that is the difference between usable
   * and not. */
  overflow-x: hidden;
}

:focus-visible {
  outline: var(--bwz-border-thick) solid var(--bwz-accent);
  outline-offset: 2px;
  border-radius: var(--bwz-radius-sm);
}

::selection {
  background: var(--bwz-accent);
  color: var(--bwz-accent-fg);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---------------------------------------------------------------------------
 * 5. Layout primitives
 * ------------------------------------------------------------------------- */

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

.bwz-main { flex: 1 0 auto; }

.bwz-section { padding-block: var(--bwz-space-7); }
.bwz-section--tight { padding-block: var(--bwz-space-5); }
.bwz-section--loose { padding-block: clamp(2.5rem, 8vw, 5.5rem); }
.bwz-section--tinted { background: var(--bwz-surface-2); }

/* Vertical rhythm without margin arithmetic in every component. */
.bwz-stack > * + * { margin-top: var(--bwz-space-4); }
.bwz-stack--tight > * + * { margin-top: var(--bwz-space-2); }
.bwz-stack--loose > * + * { margin-top: var(--bwz-space-6); }

.bwz-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--bwz-space-3);
}
.bwz-cluster--between { justify-content: space-between; }

/* auto-fit, so it collapses to one column at 320px with no breakpoint. */
.bwz-grid {
  display: grid;
  gap: var(--bwz-space-5);
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
}
.bwz-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); }

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

/* ---------------------------------------------------------------------------
 * 6. Typography
 * ------------------------------------------------------------------------- */

.bwz-h1, .bwz-h2, .bwz-h3, .bwz-h4 {
  font-weight: var(--bwz-weight-bold);
  letter-spacing: var(--bwz-tracking-tight);
  line-height: var(--bwz-leading-tight);
  text-wrap: balance;
}
.bwz-h1 { font-size: var(--bwz-text-3xl); max-width: 22ch; }
.bwz-h2 { font-size: var(--bwz-text-2xl); }
.bwz-h3 { font-size: var(--bwz-text-xl); line-height: var(--bwz-leading-snug); }
.bwz-h4 {
  font-size: var(--bwz-text-lg);
  font-weight: var(--bwz-weight-semibold);
  line-height: var(--bwz-leading-snug);
}

.bwz-eyebrow {
  font-size: var(--bwz-text-sm);
  font-weight: var(--bwz-weight-semibold);
  letter-spacing: var(--bwz-tracking-wide);
  text-transform: uppercase;
  color: var(--bwz-accent);
}

.bwz-lede {
  font-size: var(--bwz-text-md);
  max-width: var(--bwz-measure);
}
.bwz-prose { max-width: var(--bwz-measure); }
.bwz-prose > * + * { margin-top: var(--bwz-space-4); }
.bwz-muted { color: var(--bwz-fg-muted); }
.bwz-subtle { color: var(--bwz-fg-subtle); font-size: var(--bwz-text-sm); }
.bwz-meta {
  font-size: var(--bwz-text-xs);
  color: var(--bwz-fg-subtle);
  font-variant-numeric: tabular-nums;
}

.bwz-code {
  font-family: var(--bwz-font-mono);
  font-size: 0.9375em;
  background: var(--bwz-surface-3);
  border-radius: var(--bwz-radius-sm);
  padding: 0.1em 0.35em;
}

/* [CRITICAL] The type selector is load-bearing, and it is a fix rather than a
 * flourish. The reset in section 4 says `ul[class], ol[class] { padding: 0;
 * list-style: none; }` -- which is the right default, because most lists on
 * this site are navigation. But `ol[class]` is (0,1,1) and a bare `.bwz-list`
 * is (0,1,0), so the reset **won**, and every bullet and every step number on
 * this site had silently rendered as an unmarked line since the stylesheet was
 * written. Nobody saw it because nothing had used a bulleted list in anger
 * until Dan asked for one on 2026-09-09 (869evwx03) -- at which point three
 * cards on /what-we-do/ came out as run-on lines with no markers.
 *
 * `ul.bwz-list` ties the reset on specificity and wins on source order.
 *
 * ⚠️ `--plain` has to be raised WITH it, and the first attempt got this wrong
 * on the reasoning that `--plain` is used on its own. It is not: every one of
 * its four uses is `class="bwz-list bwz-list--plain"`, so raising only the base
 * put bullets on the site-wide footer navigation. Caught by looking at a
 * screenshot of the footer, one deploy later. Both are (0,1,1) and `--plain`
 * comes second, which is what makes the modifier win.
 * `core/tests.py::test_a_bulleted_list_actually_gets_its_bullets` pins both. */
ul.bwz-list,
ol.bwz-list {
  padding-left: 1.25em;
  list-style: disc;
}
.bwz-list > li + li { margin-top: var(--bwz-space-2); }
ol.bwz-list--ordered { list-style: decimal; }
ul.bwz-list--plain,
ol.bwz-list--plain { padding-left: 0; list-style: none; }

/* ---------------------------------------------------------------------------
 * 7. Links
 * ------------------------------------------------------------------------- */

a { color: var(--bwz-accent); }

.bwz-link {
  color: var(--bwz-accent);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
  border-radius: var(--bwz-radius-sm);
}
.bwz-link:hover { color: var(--bwz-accent-hover); text-decoration-thickness: 2px; }
.bwz-link:active { color: var(--bwz-accent-active); }

/* For links inside a nav or a card, where the underline is noise. It still
 * underlines on hover and focus, so it is never colour-alone. */
.bwz-link--quiet { text-decoration: none; }
.bwz-link--quiet:hover,
.bwz-link--quiet:focus-visible { text-decoration: underline; }

.bwz-link--plain { color: inherit; text-decoration: none; }
.bwz-link--plain:hover { color: var(--bwz-accent); text-decoration: underline; }

/* Keyboard users reach the content without tabbing the whole header. */
.bwz-skip {
  position: absolute;
  left: -9999px;
  top: var(--bwz-space-2);
  z-index: var(--bwz-z-overlay);
  background: var(--bwz-accent);
  color: var(--bwz-accent-fg);
  padding: var(--bwz-space-2) var(--bwz-space-4);
  border-radius: var(--bwz-radius-md);
  text-decoration: none;
}
.bwz-skip:focus { left: var(--bwz-space-2); }

/* ---------------------------------------------------------------------------
 * 8. The mark and the lockups
 *
 * The brand pack forbids recolouring, gradients, stretching, rotation, an
 * added outline and a drop shadow. There is therefore no modifier here that
 * does any of those, and nothing sets `filter` or `transform` on a mark.
 * ------------------------------------------------------------------------- */

.bwz-mark {
  display: block;
  width: var(--bwz-mark-size);
  height: var(--bwz-mark-size);
  min-width: var(--bwz-mark-min);
  min-height: var(--bwz-mark-min);
  flex: none;
}
.bwz-mark--sm { --bwz-mark-size: 1.5rem; }
.bwz-mark--lg { --bwz-mark-size: 3rem; }
.bwz-mark--xl { --bwz-mark-size: 5rem; }

/* Clear space: at least the width of the centre circle, all the way round. */
.bwz-mark--clearspace {
  box-sizing: content-box;
  padding: var(--bwz-mark-clearspace);
}

.bwz-lockup { display: block; height: auto; }
.bwz-lockup--h { width: min(16.25rem, 100%); }
.bwz-lockup--stacked { width: min(12.5rem, 100%); }

/* The colour mark is solid #0E52C9 and goes muddy on the dark ground, so the
 * white variant is swapped in by CSS rather than by script. All three theme
 * states are handled: system-light, system-dark, and an explicit choice. */
.bwz-mark--on-dark { display: none; }

@media (prefers-color-scheme: dark) {
  :root:not([data-bwz-theme="light"]) .bwz-mark--on-light { display: none; }
  :root:not([data-bwz-theme="light"]) .bwz-mark--on-dark { display: block; }
}
:root[data-bwz-theme="dark"] .bwz-mark--on-light { display: none; }
:root[data-bwz-theme="dark"] .bwz-mark--on-dark { display: block; }

.bwz-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--bwz-space-3);
  text-decoration: none;
  color: inherit;
  border-radius: var(--bwz-radius-md);
}
.bwz-logo__word {
  font-weight: var(--bwz-weight-bold);
  font-size: var(--bwz-text-md);
  letter-spacing: var(--bwz-tracking-tight);
  white-space: nowrap;
}
.bwz-logo__word b { color: var(--bwz-accent); font-weight: inherit; }

/* ---------------------------------------------------------------------------
 * 9. Buttons
 * ------------------------------------------------------------------------- */

.bwz-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--bwz-space-2);
  min-height: 44px;                 /* a real touch target at 320px */
  padding: var(--bwz-space-2) var(--bwz-space-5);
  border: var(--bwz-border-thick) solid transparent;
  border-radius: var(--bwz-radius-md);
  background: transparent;
  color: var(--bwz-fg);
  font-size: var(--bwz-text-base);
  font-weight: var(--bwz-weight-semibold);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--bwz-duration) var(--bwz-ease),
              border-color var(--bwz-duration) var(--bwz-ease),
              color var(--bwz-duration) var(--bwz-ease);
}

.bwz-btn--primary {
  background: var(--bwz-accent);
  border-color: var(--bwz-accent);
  color: var(--bwz-accent-fg);
}
.bwz-btn--primary:hover { background: var(--bwz-accent-hover); border-color: var(--bwz-accent-hover); }
.bwz-btn--primary:active { background: var(--bwz-accent-active); border-color: var(--bwz-accent-active); }

.bwz-btn--secondary {
  border-color: var(--bwz-accent);
  color: var(--bwz-accent);
}
.bwz-btn--secondary:hover { background: var(--bwz-accent-surface); color: var(--bwz-accent-hover); border-color: var(--bwz-accent-hover); }

.bwz-btn--ghost { color: var(--bwz-fg-muted); }
.bwz-btn--ghost:hover { background: var(--bwz-surface-2); color: var(--bwz-fg); }

.bwz-btn--danger {
  background: var(--bwz-danger);
  border-color: var(--bwz-danger);
  color: var(--bwz-brand-paper);
}
:root[data-bwz-theme="dark"] .bwz-btn--danger { color: var(--bwz-brand-ink); }
@media (prefers-color-scheme: dark) {
  :root:not([data-bwz-theme="light"]) .bwz-btn--danger { color: var(--bwz-brand-ink); }
}

.bwz-btn--sm { min-height: 36px; padding: var(--bwz-space-1) var(--bwz-space-3); font-size: var(--bwz-text-sm); }
.bwz-btn--lg { min-height: 52px; padding: var(--bwz-space-3) var(--bwz-space-6); font-size: var(--bwz-text-md); }
.bwz-btn--block { display: flex; width: 100%; }

.bwz-btn[disabled],
.bwz-btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}

.bwz-btn-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bwz-space-3);
}
/* At 320px a row of buttons must stack rather than shrink below the target. */
@media (max-width: 22.5em) {
  .bwz-btn-group > .bwz-btn { flex: 1 1 100%; }
}

/* ---------------------------------------------------------------------------
 * 10. Cards
 * ------------------------------------------------------------------------- */

.bwz-card {
  display: flex;
  flex-direction: column;
  background: var(--bwz-surface);
  border: var(--bwz-border) solid var(--bwz-rule);
  border-radius: var(--bwz-radius-lg);
  box-shadow: var(--bwz-shadow-sm);
  overflow: hidden;
}
.bwz-card__header,
.bwz-card__body,
.bwz-card__footer { padding: var(--bwz-space-5); }
.bwz-card__header { border-bottom: var(--bwz-border) solid var(--bwz-rule); }
.bwz-card__footer {
  border-top: var(--bwz-border) solid var(--bwz-rule);
  background: var(--bwz-surface-2);
  margin-top: auto;
}
.bwz-card__title {
  font-size: var(--bwz-text-lg);
  font-weight: var(--bwz-weight-semibold);
  line-height: var(--bwz-leading-snug);
}
.bwz-card--flush { box-shadow: none; }
.bwz-card--tinted { background: var(--bwz-surface-2); }

.bwz-card--interactive { transition: border-color var(--bwz-duration) var(--bwz-ease), box-shadow var(--bwz-duration) var(--bwz-ease); }
.bwz-card--interactive:hover { border-color: var(--bwz-accent); box-shadow: var(--bwz-shadow-md); }
.bwz-card--interactive:focus-within { border-color: var(--bwz-accent); }

/* A stat tile for the dashboard. */
.bwz-stat__label {
  font-size: var(--bwz-text-sm);
  color: var(--bwz-fg-muted);
  font-weight: var(--bwz-weight-medium);
}
.bwz-stat__value {
  font-size: var(--bwz-text-2xl);
  font-weight: var(--bwz-weight-bold);
  line-height: var(--bwz-leading-tight);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--bwz-tracking-tight);
}

/* ---------------------------------------------------------------------------
 * 10a. Logos and pictures
 *
 * Added for ticket 869evwwzn, 2026-09-07, on two instructions: "Use logos for
 * Asset Giant and Just Granted", and "use the mockups as graphics ... plus a
 * screenshot".
 *
 * Two rules govern everything here.
 *
 * A supplied mark is not recoloured. Asset Giant's logo carries a gradient and
 * a red; Just Granted's is a fixed teal. Neither survives an invert or a CSS
 * filter, and both would fail against the dark ground. So they sit on a Paper
 * tile in both themes -- the brand pack's own answer for a lockup on dark.
 *
 * Every picture reserves its space before it loads. width and height attributes
 * are on the markup and aspect-ratio is here, so nothing below an image jumps
 * down the page when it arrives.
 * ------------------------------------------------------------------------- */

.bwz-logo-tile {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  background: var(--bwz-logo-tile);
  border: var(--bwz-border) solid var(--bwz-logo-tile-rule);
  border-radius: var(--bwz-radius-md);
  padding: var(--bwz-space-4);
  min-height: 4.5rem;
}
.bwz-logo-tile img {
  width: auto;
  max-height: 2.5rem;
  max-width: 100%;
  object-fit: contain;
}
.bwz-logo-tile--centred { justify-content: center; }

/* A row of logos that wraps at 320px with no breakpoint. */
.bwz-logo-strip {
  display: grid;
  gap: var(--bwz-space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(12rem, 100%), 1fr));
}

/* A picture with an optional caption. <figure> is the element; this is only
 * the frame round it. */
.bwz-figure { display: flex; flex-direction: column; gap: var(--bwz-space-3); }
.bwz-figure img {
  width: 100%;
  border-radius: var(--bwz-radius-lg);
  border: var(--bwz-border) solid var(--bwz-rule);
  background: var(--bwz-surface-2);
}
.bwz-figure figcaption {
  font-size: var(--bwz-text-sm);
  color: var(--bwz-fg-subtle);
}

/* The gallery on a case study. auto-fit again, so one picture fills the width
 * and three share it. */
.bwz-gallery {
  display: grid;
  gap: var(--bwz-space-5);
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
}

/* A picture at the top of a card, above the title. It is cropped to a fixed
 * shape so a row of cards keeps its titles on one line. */
.bwz-card__media {
  aspect-ratio: 16 / 9;
  background: var(--bwz-surface-2);
  border-bottom: var(--bwz-border) solid var(--bwz-rule);
}
.bwz-card__media img { width: 100%; height: 100%; object-fit: cover; }
.bwz-card__media--logo {
  aspect-ratio: auto;
  background: var(--bwz-logo-tile);
  padding: var(--bwz-space-5);
  display: flex;
  align-items: center;
}
.bwz-card__media--logo img {
  height: 2.25rem;
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

/* ---------------------------------------------------------------------------
 * 10b. Design concepts — /design-concepts/ only, staff only
 *
 * Dan, ticket 869evwwzn, 2026-09-07: "I'd like the site to be a lot more
 * visually arresting - include graphics and more colours etc ... professional,
 * modern, slight hints at AI capabilities but really very subtle on that part,
 * simple (just not quite this simple as we currently have). Draft various
 * designs / graphics etc for my approval."
 *
 * So these are DRAFTS. Nothing here is applied to a page a visitor can reach:
 * every rule is scoped under .bwz-dc, the page it renders on is signed-in-staff
 * only, and picking one is a separate piece of work.
 *
 * Three constraints held throughout, because they are not negotiable:
 *   - no component names a hex; everything is built from the role tokens in
 *     section 2, so all three directions follow the light and dark themes;
 *   - the mark is never recoloured, gradient-filled, rotated or outlined;
 *   - nothing here relies on CSS nesting, :has() or container queries, so the
 *     previous major of all four target browsers still renders it.
 *
 * The "AI hint" is a field of faint dots behind a heading and nothing else. No
 * circuitry, no glowing orb, no robot.
 * ------------------------------------------------------------------------- */

.bwz-dc { border-radius: var(--bwz-radius-lg); overflow: hidden; }
.bwz-dc__frame {
  border: var(--bwz-border) solid var(--bwz-rule);
  border-radius: var(--bwz-radius-lg);
  overflow: hidden;
}
.bwz-dc__pad { padding: clamp(1.5rem, 4vw, 3.5rem); }
.bwz-dc__cards {
  display: grid;
  gap: var(--bwz-space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
}
.bwz-dc__card {
  background: var(--bwz-surface);
  border: var(--bwz-border) solid var(--bwz-rule);
  border-radius: var(--bwz-radius-md);
  padding: var(--bwz-space-5);
}
.bwz-dc__card p { color: var(--bwz-fg-muted); font-size: var(--bwz-text-sm); }
.bwz-dc__title {
  font-size: var(--bwz-text-2xl);
  font-weight: var(--bwz-weight-bold);
  letter-spacing: var(--bwz-tracking-tight);
  line-height: var(--bwz-leading-tight);
  /* 26ch, not the 22ch .bwz-h1 uses: at 20ch this wrapped to five lines on a
   * 1280px screen and left the right two-thirds of the hero empty, which read
   * as a layout fault rather than as a design. Measured in a screenshot. */
  max-width: 26ch;
}
.bwz-dc__lede {
  font-size: var(--bwz-text-md);
  color: var(--bwz-fg-muted);
  max-width: var(--bwz-measure);
  margin-top: var(--bwz-space-4);
}

/* -- A. Quiet ---------------------------------------------------------------
 * What the site is now, given room to breathe: one accent, a lot of white
 * space, and the pictures doing the work instead of the colour. The safe
 * choice, and the one that ages best. */
.bwz-dc--quiet { background: var(--bwz-bg); }
.bwz-dc--quiet .bwz-dc__title { color: var(--bwz-fg); }
.bwz-dc--quiet .bwz-dc__rule {
  width: 3rem;
  height: var(--bwz-border-thick);
  background: var(--bwz-accent);
  margin-bottom: var(--bwz-space-5);
}

/* -- B. Structured ----------------------------------------------------------
 * Colour arrives through surfaces rather than through hue: a tinted ground,
 * white cards floating on it, an accent rule and a numbered spine down the
 * left. Reads as an operations document, which is close to what is being
 * sold. */
.bwz-dc--structured { background: var(--bwz-surface-2); }
.bwz-dc--structured .bwz-dc__card {
  box-shadow: var(--bwz-shadow-md);
  border-color: transparent;
  position: relative;
  padding-left: var(--bwz-space-7);
}
.bwz-dc--structured .bwz-dc__num {
  position: absolute;
  left: var(--bwz-space-5);
  top: var(--bwz-space-5);
  font-variant-numeric: tabular-nums;
  font-weight: var(--bwz-weight-bold);
  color: var(--bwz-accent);
}
.bwz-dc--structured .bwz-dc__title {
  border-left: 4px solid var(--bwz-accent);
  padding-left: var(--bwz-space-5);
}

/* -- C. Signal --------------------------------------------------------------
 * The loud one. A gradient hero built from the two ends of the palette, a
 * field of faint dots behind it, and the section below it on the accent tint.
 * Both gradient stops are role tokens, so it inverts correctly in the dark
 * theme instead of turning to mud.
 *
 * The dot field is a repeating radial-gradient rather than an image: it is
 * about 90 bytes, it scales to any viewport, and there is no file to keep. */
.bwz-dc--signal .bwz-dc__hero {
  position: relative;
  background-image: linear-gradient(140deg, var(--bwz-accent) 0%, var(--bwz-fg) 100%);
  color: var(--bwz-accent-fg);
  isolation: isolate;
}
.bwz-dc--signal .bwz-dc__hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: radial-gradient(currentColor 1px, transparent 1px);
  background-size: 18px 18px;
  opacity: 0.12;
}
.bwz-dc--signal .bwz-dc__title,
.bwz-dc--signal .bwz-dc__lede { color: var(--bwz-accent-fg); }
.bwz-dc--signal .bwz-dc__band { background: var(--bwz-accent-surface); }
.bwz-dc--signal .bwz-dc__card { border-color: var(--bwz-accent); }

/* ---------------------------------------------------------------------------
 * 10c. Signal — the chosen direction, on the real site
 *
 * Dan picked C, "Signal", on 2026-09-08 (ticket 869evwwzn, read back off the
 * tick boxes on 869eyf9jx). ⚠️ He did NOT pick the recommended option — the
 * sweep starred B, Structured. Anybody revisiting this works from the tick.
 *
 * This is 10b's third draft made real. The draft stays where it is, so the
 * three directions can still be compared, and this section is what a visitor
 * actually gets. Three devices and no more:
 *
 *   1. a gradient hero, built from the two ends of the palette;
 *   2. a field of faint dots behind it — the only nod to AI anywhere on the
 *      site, and deliberately not a circuit board, an orb or a robot;
 *   3. the accent tint on a banded section, and an accent hairline on cards.
 *
 * [CRITICAL] Scoped to the marketing site, not to the stylesheet. The
 * dashboard, the client portal and the discovery questionnaire all extend the
 * same base.html and share this one stylesheet, so every rule below is behind
 * `.bwz-body--signal`, a body class that only content/page.html and
 * content/case_study.html set. Restyling `.bwz-card` or `.bwz-section--tinted`
 * outright would have repainted the operations dashboard, where colour means
 * "this check is failing" and nothing else.
 *
 * No hex appears here. Both gradient stops are role tokens, so the hero
 * inverts with the theme instead of turning to mud: light runs Blue -> Ink
 * under white text, dark runs dark-UI-blue -> Paper-ish under near-black text.
 * ------------------------------------------------------------------------- */

/* The hero. `isolation: isolate` gives the dot field a stacking context of its
 * own, so `z-index: -1` puts it behind the text and NOT behind the page. */
.bwz-hero {
  position: relative;
  isolation: isolate;
  background-image: linear-gradient(140deg, var(--bwz-accent) 0%, var(--bwz-fg) 100%);
  color: var(--bwz-accent-fg);
}

/* The AI hint: a repeating radial-gradient rather than an image. About ninety
 * bytes, scales to any viewport, and there is no file to keep in step with a
 * release. `currentColor` means it follows the hero's own text colour, so it
 * needs no token of its own in either theme. */
.bwz-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: radial-gradient(currentColor 1px, transparent 1px);
  background-size: 18px 18px;
  opacity: 0.12;
}

/* Everything inside the hero is on the gradient, so it takes the hero's
 * foreground rather than the page's. The eyebrow and the meta line are named
 * explicitly because both carry a colour of their own in section 6. */
.bwz-hero .bwz-h1,
.bwz-hero .bwz-lede,
.bwz-hero .bwz-prose,
.bwz-hero .bwz-eyebrow,
.bwz-hero .bwz-meta,
.bwz-hero .bwz-muted,
.bwz-hero .bwz-subtle { color: var(--bwz-accent-fg); }

/* A link on the gradient. The accent is the darkest thing in the light theme's
 * gradient and would vanish into it, so the link takes the hero's foreground
 * and keeps its underline — which is what carries the affordance once colour
 * is no longer doing it. */
.bwz-hero .bwz-link,
.bwz-hero a { color: var(--bwz-accent-fg); }
.bwz-hero .bwz-link:hover,
.bwz-hero a:hover { color: var(--bwz-accent-fg); text-decoration-thickness: 2px; }

/* [CRITICAL] The focus ring is `--bwz-accent` everywhere else, and the accent
 * is one END of this gradient: a keyboard user tabbing across the hero would
 * get an outline the same colour as the thing behind it. On the gradient the
 * ring is the hero's foreground instead, which is the highest-contrast colour
 * available against every point of it. */
.bwz-hero :focus-visible { outline-color: var(--bwz-accent-fg); }

/* The band under the hero: the accent tint, where `--tinted` is the neutral
 * one. A separate modifier rather than a redefinition of `--tinted`, because
 * `--tinted` is also the dashboard's table header and the case study's body. */
.bwz-section--band { background: var(--bwz-accent-surface); }

/* An accent hairline on the cards, so the colour carries past the hero rather
 * than stopping at it. Border only: the card keeps its own surface, because a
 * tinted card on a tinted band is two surfaces and no edge. */
.bwz-body--signal .bwz-card { border-color: var(--bwz-accent); }
.bwz-body--signal .bwz-card__header,
.bwz-body--signal .bwz-card__footer { border-color: var(--bwz-rule); }

/* The wide measure. Dan's instruction of 2026-09-09; the reasoning and the
 * limits are on --bwz-measure-wide in section 3. Scoped to the marketing body
 * because .bwz-prose is also the dashboard's and the questionnaire's, and
 * neither of those asked for a longer line.
 *
 * To put it back: delete this block. To go halfway, change the token to 60rem.
 * Nothing else reads --bwz-measure-wide. */
@media (min-width: 90em) {
  .bwz-body--signal .bwz-prose,
  .bwz-body--signal .bwz-lede,
  .bwz-body--signal .bwz-measure { max-width: var(--bwz-measure-wide); }
  /* The hero is the exception, and it is not a compromise: a lede set across
   * 1280px directly under a heading capped at 22ch reads as two unrelated
   * blocks. The hero keeps the readable measure. */
  .bwz-body--signal .bwz-hero .bwz-lede,
  .bwz-body--signal .bwz-hero .bwz-prose,
  .bwz-body--signal .bwz-hero .bwz-measure { max-width: var(--bwz-measure); }
}

/* The step drawings on /how-we-work/ (869evwx03, 2026-09-09). The icon is
 * `currentColor` throughout, so it takes the accent here and inverts with the
 * theme like everything else — there is no second colour to keep in step. */
.bwz-body--signal .bwz-step__mark {
  display: block;
  color: var(--bwz-accent);
  margin-bottom: var(--bwz-space-2);
}
.bwz-body--signal .bwz-step__icon {
  width: 2rem;
  height: 2rem;
}

/* ---------------------------------------------------------------------------
 * 11. Header, nav and footer
 * ------------------------------------------------------------------------- */

.bwz-header {
  border-bottom: var(--bwz-border) solid var(--bwz-rule);
  background: var(--bwz-bg);
  padding-block: var(--bwz-space-3);
}
.bwz-header__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--bwz-space-3);
}
/* The logo takes the free space so the nav and the controls stay together on
 * the right, whether or not there is a nav to show. An auto margin does that
 * for any number of children; `justify-content` did not, once there were
 * three of them. */
.bwz-header__inner > .bwz-logo { margin-right: auto; }

/* The nav wraps at every width the reader has JavaScript turned off at, and
 * collapses behind a disclosure below 48em when they have it. Ticket
 * 869evwwz8, on Dan's instruction: "Create a hamburger nav."
 *
 * [CRITICAL] The collapsed state is scoped to `:root[data-bwz-nav="js"]`, an
 * attribute set by bwz-nav.js and by nothing else. With no JavaScript there is
 * no attribute, so the nav is exactly the wrapping row it has always been and
 * the button that would hide it never appears. A menu whose only way open is a
 * script that did not load is a site with no navigation at all. */
.bwz-nav__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--bwz-space-1) var(--bwz-space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}
.bwz-nav__link {
  display: inline-block;
  padding: var(--bwz-space-2) 0;
  color: var(--bwz-fg-muted);
  font-weight: var(--bwz-weight-medium);
  text-decoration: none;
  border-bottom: var(--bwz-border-thick) solid transparent;
}
.bwz-nav__link:hover { color: var(--bwz-fg); border-bottom-color: var(--bwz-rule-strong); }
/* Current page is marked by weight and a rule, not by colour alone. */
.bwz-nav__link[aria-current="page"] {
  color: var(--bwz-fg);
  font-weight: var(--bwz-weight-semibold);
  border-bottom-color: var(--bwz-accent);
}

/* The disclosure itself. It ships `hidden` in the markup and bwz-nav.js is
 * what reveals it, for the same reason the theme toggle does: a control that
 * cannot do anything must not be on the page. */
.bwz-nav-toggle {
  display: none;
  align-items: center;
  gap: var(--bwz-space-2);
  min-height: 2.75rem;
  padding: var(--bwz-space-2) var(--bwz-space-3);
  border: var(--bwz-border) solid var(--bwz-rule-strong);
  border-radius: var(--bwz-radius-md);
  background: var(--bwz-surface);
  color: var(--bwz-fg);
  font: inherit;
  font-size: var(--bwz-text-sm);
  font-weight: var(--bwz-weight-medium);
  cursor: pointer;
}
.bwz-nav-toggle:hover { border-color: var(--bwz-accent); }

/* Three bars, drawn in `currentColor` so they follow the button's text in both
 * themes and there is no colour to keep in step. */
.bwz-nav-toggle__bars {
  display: block;
  position: relative;
  width: 1.125rem;
  height: 0.75rem;
  flex: none;
}
.bwz-nav-toggle__bars span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
  transition: transform var(--bwz-duration) var(--bwz-ease),
    opacity var(--bwz-duration) var(--bwz-ease);
}
.bwz-nav-toggle__bars span:nth-child(1) { top: 0; }
.bwz-nav-toggle__bars span:nth-child(2) { top: calc(50% - 1px); }
.bwz-nav-toggle__bars span:nth-child(3) { bottom: 0; }

/* Open: the bars become a cross. The middle one fades rather than moving, so
 * nothing has to travel behind anything else. */
.bwz-header--nav-open .bwz-nav-toggle__bars span:nth-child(1) {
  transform: translateY(calc(0.375rem - 1px)) rotate(45deg);
}
.bwz-header--nav-open .bwz-nav-toggle__bars span:nth-child(2) { opacity: 0; }
.bwz-header--nav-open .bwz-nav-toggle__bars span:nth-child(3) {
  transform: translateY(calc(1px - 0.375rem)) rotate(-45deg);
}

/* Collapsed navigation: below 48em, and only where the script ran.
 *
 * The panel is in normal flow on its own row rather than floating over the
 * page, so opening it pushes the page down instead of covering it. That is
 * what makes it safe with no trap, no overlay and no scroll lock -- three
 * things that go wrong on real phones and cannot be tested from here. */
@media (max-width: 47.99em) {
  :root[data-bwz-nav="js"] .bwz-nav-toggle { display: inline-flex; }

  :root[data-bwz-nav="js"] .bwz-nav {
    order: 3;
    flex-basis: 100%;
    display: none;
  }
  :root[data-bwz-nav="js"] .bwz-header--nav-open .bwz-nav { display: block; }

  :root[data-bwz-nav="js"] .bwz-nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-top: var(--bwz-space-2);
  }
  /* Each link is its own row, at least 44px tall, with the rule under it
   * rather than under the text -- a whole-row target is what a thumb hits. */
  :root[data-bwz-nav="js"] .bwz-nav__link {
    display: block;
    padding: var(--bwz-space-3) 0;
    border-bottom: var(--bwz-border) solid var(--bwz-rule);
  }
  :root[data-bwz-nav="js"] .bwz-nav__link[aria-current="page"] {
    border-bottom-color: var(--bwz-accent);
  }
}

.bwz-footer {
  flex-shrink: 0;
  margin-top: var(--bwz-space-7);
  border-top: var(--bwz-border) solid var(--bwz-rule);
  background: var(--bwz-surface-2);
  padding-block: var(--bwz-space-6);
  font-size: var(--bwz-text-sm);
  color: var(--bwz-fg-muted);
}
.bwz-footer__grid {
  display: grid;
  gap: var(--bwz-space-5);
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
}
.bwz-footer__heading {
  font-size: var(--bwz-text-xs);
  font-weight: var(--bwz-weight-semibold);
  letter-spacing: var(--bwz-tracking-wide);
  text-transform: uppercase;
  color: var(--bwz-fg-subtle);
  margin-bottom: var(--bwz-space-2);
}
.bwz-footer__legal {
  font-size: var(--bwz-text-xs);
  color: var(--bwz-fg-subtle);
}
/* The rule above the legal line separates it from the rest of the footer, so
 * it must not appear when the legal line IS the rest of the footer -- which is
 * the case on every page until there is something to link to. */
.bwz-footer__legal:not(:first-child) {
  margin-top: var(--bwz-space-5);
  padding-top: var(--bwz-space-4);
  border-top: var(--bwz-border) solid var(--bwz-rule);
}
.bwz-footer__version { font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
 * 12. Forms
 * ------------------------------------------------------------------------- */

.bwz-form { max-width: var(--bwz-measure); }
.bwz-form > * + * { margin-top: var(--bwz-space-5); }

.bwz-fieldset { border: 0; padding: 0; margin: 0; }
.bwz-fieldset__legend {
  padding: 0;
  font-size: var(--bwz-text-lg);
  font-weight: var(--bwz-weight-semibold);
  margin-bottom: var(--bwz-space-3);
}

.bwz-field { display: block; }
.bwz-field > * + * { margin-top: var(--bwz-space-2); }

.bwz-label {
  display: block;
  font-weight: var(--bwz-weight-medium);
  font-size: var(--bwz-text-sm);
}
.bwz-label__optional { color: var(--bwz-fg-subtle); font-weight: var(--bwz-weight-normal); }
.bwz-label__required { color: var(--bwz-danger); }

.bwz-input,
.bwz-textarea,
.bwz-select {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: var(--bwz-space-2) var(--bwz-space-3);
  background: var(--bwz-surface);
  color: var(--bwz-fg);
  border: var(--bwz-border) solid var(--bwz-field-border);
  border-radius: var(--bwz-radius-md);
  /* 16px minimum, or iOS Safari zooms the whole page on focus. */
  font-size: var(--bwz-text-base);
  transition: border-color var(--bwz-duration) var(--bwz-ease);
}
.bwz-textarea { min-height: 7rem; resize: vertical; line-height: var(--bwz-leading-normal); }

.bwz-select {
  appearance: none;
  padding-right: var(--bwz-space-7);
  /* Chevron drawn in the border colour so it flips with the theme. */
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 1.15rem) 55%, calc(100% - 0.8rem) 55%;
  background-size: 0.36rem 0.36rem, 0.36rem 0.36rem;
  background-repeat: no-repeat;
}

.bwz-input:hover,
.bwz-textarea:hover,
.bwz-select:hover { border-color: var(--bwz-rule-strong); }

.bwz-input::placeholder,
.bwz-textarea::placeholder { color: var(--bwz-fg-subtle); opacity: 1; }

.bwz-input[disabled],
.bwz-textarea[disabled],
.bwz-select[disabled] {
  background: var(--bwz-surface-2);
  color: var(--bwz-fg-subtle);
  cursor: not-allowed;
}

/* Error state is driven by aria-invalid, so the styling and the accessibility
 * information cannot get out of step. */
.bwz-input[aria-invalid="true"],
.bwz-textarea[aria-invalid="true"],
.bwz-select[aria-invalid="true"] {
  border-color: var(--bwz-danger);
  border-width: var(--bwz-border-thick);
}

.bwz-help { font-size: var(--bwz-text-sm); color: var(--bwz-fg-muted); }
.bwz-error {
  display: flex;
  gap: var(--bwz-space-2);
  font-size: var(--bwz-text-sm);
  font-weight: var(--bwz-weight-medium);
  color: var(--bwz-danger);
}
/* A glyph as well as the colour: never colour alone. */
.bwz-error::before { content: "\26A0"; }

.bwz-check {
  display: flex;
  align-items: flex-start;
  gap: var(--bwz-space-3);
  cursor: pointer;
}
.bwz-check + .bwz-check { margin-top: var(--bwz-space-3); }
.bwz-check__input {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  margin: 0.2rem 0 0;
  accent-color: var(--bwz-accent);
}
.bwz-check__label { font-size: var(--bwz-text-base); }

/* The honeypot wrapper. Off-canvas rather than display:none, because a bot that
 * skips hidden fields is exactly the bot this is meant to catch. It is also
 * aria-hidden and tabindex=-1 in the markup: three separate ways to keep a
 * person out of a field whose only correct value is empty. */
.bwz-hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
 * 13. Tables
 * ------------------------------------------------------------------------- */

/* A table wider than 320px scrolls inside this, not the page. tabindex="0" on
 * the wrapper in the markup makes that scroll reachable from the keyboard. */
.bwz-table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: var(--bwz-border) solid var(--bwz-rule);
  border-radius: var(--bwz-radius-lg);
}
.bwz-table-wrap:focus-visible { outline-offset: 0; }

.bwz-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--bwz-text-sm);
  text-align: left;
}
.bwz-table caption {
  padding: var(--bwz-space-3) var(--bwz-space-4);
  text-align: left;
  font-size: var(--bwz-text-sm);
  color: var(--bwz-fg-muted);
}
.bwz-table th,
.bwz-table td {
  padding: var(--bwz-space-3) var(--bwz-space-4);
  border-bottom: var(--bwz-border) solid var(--bwz-rule);
  vertical-align: top;
}
.bwz-table thead th {
  background: var(--bwz-surface-2);
  font-weight: var(--bwz-weight-semibold);
  font-size: var(--bwz-text-xs);
  letter-spacing: var(--bwz-tracking-wide);
  text-transform: uppercase;
  color: var(--bwz-fg-muted);
  white-space: nowrap;
}
.bwz-table tbody tr:last-child td { border-bottom: 0; }
.bwz-table--striped tbody tr:nth-child(even) { background: var(--bwz-surface-2); }
.bwz-table--hover tbody tr:hover { background: var(--bwz-accent-surface); }
.bwz-table--compact th,
.bwz-table--compact td { padding: var(--bwz-space-2) var(--bwz-space-3); }
.bwz-table__num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------------------------------------------------------------------------
 * 14. Badges, status dots and callouts
 * ------------------------------------------------------------------------- */

.bwz-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--bwz-space-2);
  padding: 0.15rem var(--bwz-space-3);
  border-radius: var(--bwz-radius-full);
  background: var(--bwz-surface-3);
  color: var(--bwz-fg-muted);
  font-size: var(--bwz-text-xs);
  font-weight: var(--bwz-weight-semibold);
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.bwz-badge--accent { background: var(--bwz-accent-surface); color: var(--bwz-accent); }
.bwz-badge--ok { background: var(--bwz-ok-surface); color: var(--bwz-ok); }
.bwz-badge--warn { background: var(--bwz-warn-surface); color: var(--bwz-warn); }
.bwz-badge--danger { background: var(--bwz-danger-surface); color: var(--bwz-danger); }

/* The traffic light. The dot is decorative; the word next to it carries the
 * meaning, because colour alone is not an accessible signal. */
.bwz-dot {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--bwz-radius-full);
  background: currentColor;
  flex: none;
}

.bwz-callout {
  display: flex;
  gap: var(--bwz-space-3);
  padding: var(--bwz-space-4) var(--bwz-space-5);
  border-radius: var(--bwz-radius-md);
  border-left: var(--bwz-space-1) solid var(--bwz-rule-strong);
  background: var(--bwz-surface-2);
  color: var(--bwz-fg);
}
.bwz-callout__body > * + * { margin-top: var(--bwz-space-2); }
.bwz-callout__title { font-weight: var(--bwz-weight-semibold); }
.bwz-callout--accent { border-left-color: var(--bwz-accent); background: var(--bwz-accent-surface); }
.bwz-callout--ok { border-left-color: var(--bwz-ok); background: var(--bwz-ok-surface); }
.bwz-callout--warn { border-left-color: var(--bwz-warn); background: var(--bwz-warn-surface); }
.bwz-callout--danger { border-left-color: var(--bwz-danger); background: var(--bwz-danger-surface); }

.bwz-divider {
  height: var(--bwz-border);
  border: 0;
  background: var(--bwz-rule);
  margin-block: var(--bwz-space-6);
}

/* ---------------------------------------------------------------------------
 * 15. Theme toggle
 * ------------------------------------------------------------------------- */

.bwz-theme-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--bwz-space-2);
  min-height: 36px;
  padding: var(--bwz-space-1) var(--bwz-space-3);
  border: var(--bwz-border) solid var(--bwz-rule-strong);
  border-radius: var(--bwz-radius-full);
  background: var(--bwz-surface);
  color: var(--bwz-fg-muted);
  font-size: var(--bwz-text-sm);
  font-weight: var(--bwz-weight-medium);
  cursor: pointer;
}
.bwz-theme-toggle:hover { color: var(--bwz-fg); border-color: var(--bwz-accent); }
/* Hidden until the script that drives it has run — a toggle that does nothing
 * is worse than no toggle. */
.bwz-theme-toggle[hidden] { display: none; }

/* ---------------------------------------------------------------------------
 * 16. Styleguide-only furniture. Prefixed bwz-sg- so it is obvious that none
 *     of this is part of the design system the site and dashboard consume.
 * ------------------------------------------------------------------------- */

.bwz-sg-banner {
  background: var(--bwz-warn-surface);
  color: var(--bwz-warn);
  border-bottom: var(--bwz-border) solid var(--bwz-warn);
  padding-block: var(--bwz-space-2);
  font-size: var(--bwz-text-sm);
  font-weight: var(--bwz-weight-semibold);
}

.bwz-sg-toc {
  display: flex;
  flex-wrap: wrap;
  gap: var(--bwz-space-2) var(--bwz-space-4);
  padding: 0;
  margin: 0;
  list-style: none;
  font-size: var(--bwz-text-sm);
}

.bwz-sg-section { scroll-margin-top: var(--bwz-space-5); }
.bwz-sg-section + .bwz-sg-section { margin-top: var(--bwz-space-8); }
.bwz-sg-section__head {
  border-bottom: var(--bwz-border-thick) solid var(--bwz-rule);
  padding-bottom: var(--bwz-space-2);
  margin-bottom: var(--bwz-space-5);
}

.bwz-sg-demo {
  padding: var(--bwz-space-5);
  border: var(--bwz-border) dashed var(--bwz-rule-strong);
  border-radius: var(--bwz-radius-lg);
  background: var(--bwz-surface);
}
.bwz-sg-demo + .bwz-sg-demo { margin-top: var(--bwz-space-4); }
.bwz-sg-demo__label {
  font-size: var(--bwz-text-xs);
  letter-spacing: var(--bwz-tracking-wide);
  text-transform: uppercase;
  color: var(--bwz-fg-subtle);
  margin-bottom: var(--bwz-space-3);
}

.bwz-sg-swatch {
  display: flex;
  align-items: center;
  gap: var(--bwz-space-3);
  padding: var(--bwz-space-2);
  border: var(--bwz-border) solid var(--bwz-rule);
  border-radius: var(--bwz-radius-md);
  background: var(--bwz-surface);
}
.bwz-sg-swatch__chip {
  width: 2.75rem;
  height: 2.75rem;
  flex: none;
  border-radius: var(--bwz-radius-md);
  border: var(--bwz-border) solid var(--bwz-rule-strong);
}
.bwz-sg-swatch__name { font-weight: var(--bwz-weight-semibold); font-size: var(--bwz-text-sm); }
.bwz-sg-swatch__hex {
  font-family: var(--bwz-font-mono);
  font-size: var(--bwz-text-xs);
  color: var(--bwz-fg-muted);
  text-transform: uppercase;
}

.bwz-sg-scale { display: flex; align-items: baseline; gap: var(--bwz-space-4); flex-wrap: wrap; }
.bwz-sg-scale__token {
  font-family: var(--bwz-font-mono);
  font-size: var(--bwz-text-xs);
  color: var(--bwz-fg-subtle);
  min-width: 9rem;
}
.bwz-sg-space__bar {
  height: 1rem;
  background: var(--bwz-accent);
  border-radius: var(--bwz-radius-sm);
}
.bwz-sg-dont { color: var(--bwz-danger); font-weight: var(--bwz-weight-semibold); }
.bwz-sg-do { color: var(--bwz-ok); font-weight: var(--bwz-weight-semibold); }

/* A darkened photograph strip, to show the one place the white mark is used
 * over an image. No real photograph is shipped for this. */
.bwz-sg-photo {
  display: grid;
  place-items: center;
  min-height: 9rem;
  border-radius: var(--bwz-radius-lg);
  background:
    linear-gradient(rgba(15, 22, 38, 0.62), rgba(15, 22, 38, 0.62)),
    repeating-linear-gradient(45deg, #5b6b86 0 14px, #74849e 14px 28px);
}

/* ---------------------------------------------------------------------------
 * 17. Dashboard
 *
 * Layout only. Every colour here is a role token that section 2 already
 * defines -- there is no new hex in this section and there must never be one,
 * because the traffic light on the dashboard has to be the same green as the
 * badge on the styleguide or the two stop meaning the same thing.
 *
 * The status itself is painted by .bwz-badge--ok / --warn / --danger and
 * .bwz-dot, which existed before this page did. What is added is the tile's
 * status edge and two small typographic helpers, and nothing else: a dashboard
 * that grows its own component set is a second design system.
 * ------------------------------------------------------------------------- */

/* Tighter than .bwz-grid: a status tile carries a label, a badge and a
 * sentence, so it wants to be narrower than a marketing card. auto-fit with a
 * min() floor, so 320px falls out of it rather than needing a breakpoint. */
.bwz-dash-grid {
  display: grid;
  gap: var(--bwz-space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}

/* The traffic light again, as an edge on the card. Redundant with the badge on
 * purpose: the badge carries the word for anyone who cannot rely on the
 * colour, and the edge is what makes a grid of twenty tiles scannable. */
.bwz-tile { border-left: var(--bwz-space-1) solid var(--bwz-rule-strong); }
.bwz-tile--ok { border-left-color: var(--bwz-ok); }
.bwz-tile--warn { border-left-color: var(--bwz-warn); }
.bwz-tile--danger { border-left-color: var(--bwz-danger); }
.bwz-tile--neutral { border-left-color: var(--bwz-rule-strong); }

/* Ages, intervals and counts. Tabular figures so a column of them lines up. */
.bwz-dash-meta {
  font-size: var(--bwz-text-xs);
  color: var(--bwz-fg-subtle);
  font-variant-numeric: tabular-nums;
}

/* Name/value pairs in a check's detail. The first column has a min() floor so
 * it collapses rather than pushing the page sideways at 320px, and the second
 * is minmax(0, 1fr) so a long URL wraps inside its cell instead of widening
 * the grid. No media query: the same rule as .bwz-grid. */
.bwz-dl {
  display: grid;
  grid-template-columns: minmax(min(9rem, 45%), auto) minmax(0, 1fr);
  gap: var(--bwz-space-1) var(--bwz-space-4);
  margin: 0;
}
.bwz-dl dt {
  color: var(--bwz-fg-muted);
  font-size: var(--bwz-text-sm);
}
.bwz-dl dd {
  margin: 0;
  font-size: var(--bwz-text-sm);
  overflow-wrap: anywhere;
}

/* ---------------------------------------------------------------------------
 * 20. The discovery questionnaire
 *
 * A private, link-only page (content/discovery_views.py), so none of this is
 * reachable from the marketing site and none of it is reused by it. It is here
 * rather than in a second stylesheet because there is one stylesheet, and
 * because every rule below is built out of the tokens in section 2 — a page
 * somebody answers at night has to work in both themes like everything else.
 *
 * Everything holds at 320px with no media query. The section tabs scroll
 * inside themselves rather than widening the page, which is the same rule
 * .bwz-table-wrap follows.
 * ------------------------------------------------------------------------- */

.bwz-quest { max-width: 52rem; }
.bwz-quest > * + * { margin-top: var(--bwz-space-4); }

/* The section tabs. Submit buttons, not links: clicking one saves the section
 * being left rather than discarding it, so they have to be part of the form. */
.bwz-quest__steps {
  display: flex;
  gap: var(--bwz-space-1);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border-bottom: var(--bwz-border) solid var(--bwz-rule);
  scrollbar-width: thin;
  /* [CRITICAL] `overflow-x: auto` alone is not enough here, and the reason is
   * worth writing down because it looks like a bug in the test rather than in
   * the page. `.bwz-body` sets `overflow-x: hidden`, and because <html> is
   * `visible` that value is *propagated to the viewport* -- which leaves the
   * body itself computing as `visible`. The fourteen tabs then contribute their
   * full 2.7 metres to the document's scrollable overflow, so
   * `documentElement.scrollWidth` reads 2570 in a 768px viewport even though
   * `window.scrollX` cannot move off zero. `test_the_page_does_not_scroll_
   * sideways` measures exactly that number, correctly, and would fail.
   * `contain: paint` ends the propagation at this box: nothing changes visually
   * and the tabs still scroll. Measured in Chromium on 2026-09-04; `max-width`
   * and `width: 100%` both make no difference, and clipping an ancestor does
   * not help either. */
  contain: paint;
}
.bwz-quest__step {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--bwz-space-2);
  min-height: 44px;
  padding: var(--bwz-space-2) var(--bwz-space-3);
  border: 0;
  border-bottom: var(--bwz-border-thick) solid transparent;
  background: none;
  color: var(--bwz-fg-muted);
  font: inherit;
  font-size: var(--bwz-text-sm);
  white-space: nowrap;
  cursor: pointer;
}
.bwz-quest__step:hover { color: var(--bwz-fg); }
/* aria-current, not a class: the state a screen reader is told and the state a
 * sighted reader sees are then the same fact. */
.bwz-quest__step[aria-current="step"] {
  color: var(--bwz-accent);
  border-bottom-color: var(--bwz-accent);
  font-weight: var(--bwz-weight-semibold);
}

/* The ring carries a shape as well as a colour: never colour alone. */
.bwz-quest__ring {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.1rem;
  height: 1.1rem;
  border: var(--bwz-border-thick) solid var(--bwz-rule-strong);
  border-radius: var(--bwz-radius-full);
  font-size: 0.6rem;
  line-height: 1;
  color: transparent;
}
.bwz-quest__ring[data-done="part"] {
  border-color: var(--bwz-warn);
  background: var(--bwz-warn-surface);
}
.bwz-quest__ring[data-done="all"] {
  border-color: var(--bwz-ok);
  background: var(--bwz-ok);
  color: var(--bwz-bg);
}

.bwz-quest__bar {
  height: 4px;
  border-radius: var(--bwz-radius-full);
  background: var(--bwz-surface-3);
  overflow: hidden;
}
.bwz-quest__bar > span {
  display: block;
  height: 100%;
  background: var(--bwz-accent);
  transition: width var(--bwz-duration) var(--bwz-ease);
}

.bwz-quest__meta {
  display: flex;
  align-items: center;
  gap: var(--bwz-space-3);
  margin: 0;
  font-size: var(--bwz-text-sm);
  color: var(--bwz-fg-muted);
  font-variant-numeric: tabular-nums;
}
.bwz-quest__saved {
  padding: 0.1rem var(--bwz-space-3);
  border-radius: var(--bwz-radius-full);
  background: var(--bwz-ok-surface);
  color: var(--bwz-ok);
  font-size: var(--bwz-text-xs);
  font-weight: var(--bwz-weight-semibold);
}

.bwz-quest__head { margin-bottom: var(--bwz-space-5); }
.bwz-quest__eyebrow {
  margin: 0;
  font-family: var(--bwz-font-mono);
  font-size: var(--bwz-text-xs);
  letter-spacing: var(--bwz-tracking-wide);
  text-transform: uppercase;
  color: var(--bwz-fg-subtle);
}
.bwz-quest__title {
  margin: var(--bwz-space-1) 0 0;
  font-size: var(--bwz-text-xl);
  letter-spacing: var(--bwz-tracking-tight);
}
.bwz-quest__blurb {
  margin: var(--bwz-space-2) 0 0;
  max-width: var(--bwz-measure);
  color: var(--bwz-fg-muted);
}

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

/* One question. A fieldset, because a choice question is a group of inputs and
 * its legend is the question — which is what a screen reader announces. */
.bwz-quest__q {
  margin: 0;
  padding: var(--bwz-space-4);
  border: var(--bwz-border) solid var(--bwz-rule);
  border-radius: var(--bwz-radius-lg);
  background: var(--bwz-surface);
}
.bwz-quest__q > * + * { margin-top: var(--bwz-space-3); }
.bwz-quest__label {
  padding: 0;
  font-weight: var(--bwz-weight-semibold);
  font-size: var(--bwz-text-md);
  line-height: var(--bwz-leading-snug);
}
.bwz-quest__opts > .bwz-check + .bwz-check { margin-top: var(--bwz-space-2); }

.bwz-quest__other > * + * { margin-top: var(--bwz-space-2); }

.bwz-quest__files {
  margin: 0;
  padding: 0;
  list-style: none;
}
.bwz-quest__files li {
  display: flex;
  justify-content: space-between;
  gap: var(--bwz-space-3);
  padding: var(--bwz-space-2) 0;
  border-bottom: var(--bwz-border) solid var(--bwz-rule);
  font-size: var(--bwz-text-sm);
  overflow-wrap: anywhere;
}
.bwz-quest__size {
  flex: none;
  color: var(--bwz-fg-subtle);
  font-size: var(--bwz-text-sm);
  font-variant-numeric: tabular-nums;
}
.bwz-quest__upload > * + * { margin-top: var(--bwz-space-2); }

.bwz-quest__nav {
  padding-top: var(--bwz-space-4);
  border-top: var(--bwz-border) solid var(--bwz-rule);
}
.bwz-quest__nav > * + * { margin-top: var(--bwz-space-3); }
.bwz-quest__count {
  margin: 0;
  font-size: var(--bwz-text-sm);
  color: var(--bwz-fg-muted);
  font-variant-numeric: tabular-nums;
}
.bwz-quest__foot { max-width: var(--bwz-measure); }

.bwz-quest__summary li {
  display: flex;
  justify-content: space-between;
  gap: var(--bwz-space-3);
  padding: var(--bwz-space-2) 0;
  border-bottom: var(--bwz-border) solid var(--bwz-rule);
}
