/* ═══════════════════════════════════════════════════════════════════════════
   Page Sections
   Reusable landing-page sections for Kirby CMS 5+
   ═══════════════════════════════════════════════════════════════════════════

   Ported from the "Landing page design concepts" board (layouts A–P). The board
   pinned every color as a literal; here everything resolves through the site's
   canonical --ds-* tokens (style-lean.css §"CANONICAL DESIGN TOKENS").

   ── What this file deliberately does NOT contain ──────────────────────────

   style-lean.css is the site's design system and already ships the primitives.
   Redefining them here would fork them, so the sections consume them instead:

     Buttons            .btn + .btn-primary / .btn-secondary / .btn-white /
                        .btn--ghost                        (style-lean §07)
     Heading scale      h1–h6 sizes, weights, line-heights (style-lean §03)
     Chips              [data-chip="true"]                 (style-lean §22)
     Form controls      input / label base styling         (style-lean §06)
     Focus rings        a, button, input, select, textarea (style-lean §02)
     Screen-reader text .visually-hidden                   (style-lean §canon)
     External-link mark a[href^="http"]::after             (style-lean §21)
     Dark mode          [data-theme="dark"] --ds-* overrides (style-lean §34)

   What IS here: the section shell (background / container / spacing), the
   section layouts themselves, and the handful of deltas the shared components
   need when they sit on a filled brand panel.

   Because color comes from the tokens, dark mode needs no rules of its own.
   The two exceptions are the surfaces that paint themselves — brand and
   inverted panels — which stay dark in both themes by design.

   Namespace: .ps  ·  Sections: .ps-hero, .ps-cards, .ps-pricing, …
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. Local tokens ──────────────────────────────────────────────────────── */

.ps {
  --ps-brand:        var(--ds-brand, #294557);
  --ps-brand-light:  var(--ds-brand-light, #dce5ec);
  --ps-on-brand:     var(--ds-text-on-brand, #ffffff);
  /* The softened foreground for secondary copy on a filled panel.
     The board mixes ~78% toward the panel color, which reads well but lands
     at 6.8:1 in light mode and 6.0:1 in dark (where the brand token flips to a
     light blue and the mix runs the other way). 90% clears 7:1 in both
     directions — 8.6:1 light, 7.1:1 dark — for a barely visible softening. */
  --ps-on-brand-dim: color-mix(in srgb, var(--ps-on-brand) 90%, var(--ps-brand));

  --ps-text:   var(--ds-text-primary, #232323);
  --ps-text-2: var(--ds-text-secondary, #475569);
  --ps-muted:  var(--ds-text-muted, #525252);

  --ps-surface: var(--ds-surface, #ffffff);
  --ps-raised:  var(--ds-surface-raised, #f8fafc);
  --ps-sunken:  var(--ds-surface-sunken, #f1f5f9);

  --ps-border:        var(--ds-border, #e5e7eb);
  --ps-border-strong: var(--ds-border-strong, #d1d5db);
  --ps-focus:         var(--ds-border-focus, #294557);
  --ps-link:          var(--ds-link, #294557);

  /* Text-grade status colors. The --ds-success / --ds-warning / --ds-error
     tokens are the *fill* grades — #059669 is only 3.8:1 on white, so a 13px
     delta set in it would fail. The --*-text grades are the readable pair. */
  --ps-positive: var(--ds-success-text, #065f46);
  --ps-warning:  var(--ds-warning-text, #92400e);
  --ps-negative: var(--ds-error-text, #991b1b);

  /* Solid dots and bars are non-text, so they keep the fill grades. */
  --ps-positive-fill: var(--ds-success, #059669);
  --ps-warning-fill:  var(--ds-warning, #d97706);

  --ps-radius:    var(--ds-radius, 8px);
  --ps-radius-lg: var(--ds-radius-lg, 12px);
  --ps-radius-xl: 16px;

  --ps-shadow:    var(--ds-shadow-sm, 0 1px 2px rgba(15, 23, 42, .05));
  --ps-shadow-lg: var(--ds-shadow-lg, 0 10px 15px -3px rgba(15, 23, 42, .12));

  --ps-mono: var(--ds-font-mono, 'JetBrains Mono', ui-monospace, monospace);

  /* Container widths, matching the board's frames. The site's own .container
     is a single fixed 1200px measure; sections need three. */
  --ps-w-narrow:  720px;
  /* Border-box widths that INCLUDE the 30px gutter, so the content edge lands
     on the same x as style-lean's .container (which puts its 15px gutters
     outside a content-box max-width). 1140 content + 30 gutter = 1170. */
  --ps-w-default: 1170px;
  --ps-w-wide:    1240px;
  --ps-gutter:    clamp(1.25rem, 4vw, 1.75rem);

  /* Grid column count, set per section by the snippets */
  --ps-cols: 3;

  box-sizing: border-box;
  color: var(--ps-text);
}

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

/* Pages that opt out of dark mode for their sections (blueprint: theme=light) */
.ps-page--light .ps {
  --ps-text: #232323;
  --ps-text-2: #475569;
  --ps-muted: #525252;
  --ps-surface: #ffffff;
  --ps-raised: #f8fafc;
  --ps-sunken: #f1f5f9;
  --ps-border: #e5e7eb;
  --ps-border-strong: #d1d5db;
  color-scheme: light;
}

/* ── 2. Section shell: tone, container, spacing ───────────────────────────── */

/* style-lean sets `section { overflow: hidden }`, which would clip a sticky
   rail; sections opt back out and re-clip only where they paint media. */
.ps {
  position: relative;
  width: 100%;
  overflow: visible;
}

.ps--tone-surface { background: var(--ps-surface); }
.ps--tone-raised  { background: var(--ps-raised); }
.ps--tone-sunken  { background: var(--ps-sunken); }
.ps--tone-none    { background: transparent; }

/* Filled panels paint their own surface, so they carry their own foreground
   pair rather than the page's.
   The brand panel follows the token: in dark mode --ds-brand flips to a LIGHT
   blue and --ds-text-on-brand to near-black, so the panel inverts with it.
   The inverted panel does not — its background is a fixed near-black — so it
   re-points --ps-brand / --ps-on-brand at its own pair. Everything downstream
   (buttons, ticks, score bars) then resolves correctly in both themes without
   a single [data-theme] rule in this file. */
.ps--tone-brand,
.ps--tone-dark {
  --ps-text: var(--ps-on-brand);
  --ps-text-2: var(--ps-on-brand-dim);
  --ps-muted: var(--ps-on-brand-dim);
  --ps-surface: transparent;
  --ps-raised: color-mix(in srgb, var(--ps-on-brand) 8%, transparent);
  --ps-border: color-mix(in srgb, var(--ps-on-brand) 24%, transparent);
  --ps-border-strong: color-mix(in srgb, var(--ps-on-brand) 40%, transparent);
  --ps-link: var(--ps-on-brand);
  --ps-focus: var(--ps-on-brand);
  color: var(--ps-on-brand);
}

.ps--tone-brand { background: var(--ps-brand); }

.ps--tone-dark {
  --ps-brand: #0f172a;
  --ps-brand-light: rgba(255, 255, 255, .12);
  --ps-on-brand: #f1f5f9;
  background: #0f172a;
}

/* Headings inherit the tone: style-lean recolors h1–h6 in dark mode, which
   would otherwise fight a brand panel sitting on a light page.
   NOT :where() — that has zero specificity, so style-lean's own
   [data-theme="dark"] heading rules beat it and the panel ends up with light
   text on the light-blue that --ds-brand becomes in dark mode (1.91:1). */
.ps--tone-brand h1, .ps--tone-brand h2, .ps--tone-brand h3,
.ps--tone-brand h4, .ps--tone-brand h5, .ps--tone-brand h6,
.ps--tone-dark h1, .ps--tone-dark h2, .ps--tone-dark h3,
.ps--tone-dark h4, .ps--tone-dark h5, .ps--tone-dark h6 { color: var(--ps-on-brand); }

/* Adjacent same-tone sections read as one band, so only the seam gets a rule */
.ps--tone-raised + .ps--tone-surface,
.ps--tone-surface + .ps--tone-raised { border-top: 1px solid var(--ps-border); }

.ps__inner {
  width: 100%;
  max-width: var(--ps-w-default);
  margin-inline: auto;
  padding-inline: var(--ps-gutter);
}

.ps--container-narrow .ps__inner { max-width: var(--ps-w-narrow); }
.ps--container-wide   .ps__inner { max-width: var(--ps-w-wide); }
.ps--container-full   .ps__inner { max-width: none; padding-inline: 0; }

/* style-lean's .container does not scale fluidly — it steps at Bootstrap's
   breakpoints (540/720/960/1140 content). The default container mirrors those
   steps so a section's text edge lands on the same x as the rest of the site
   at every width, not just above 1200px. narrow/wide are deliberately outside
   this system: they are prose and full-width treatments the site has no
   equivalent for. */
.ps--container-default .ps__inner {
  /* No cap below 576px — the block just fills, exactly like .container. */
  max-width: none;
  /* .container's own gutter, so content+gutter always clears the breakpoint
     that activates it (960+30 < 992). The 28px gutter used elsewhere here
     would overflow a 1000px viewport. */
  padding-inline: 15px;
}
@media (min-width: 576px)  { .ps--container-default .ps__inner { max-width: 570px; } }
@media (min-width: 768px)  { .ps--container-default .ps__inner { max-width: 750px; } }
@media (min-width: 992px)  { .ps--container-default .ps__inner { max-width: 990px; } }
@media (min-width: 1200px) { .ps--container-default .ps__inner { max-width: var(--ps-w-default); } }

.ps--space-none { padding-block: 0; }
.ps--space-sm   { padding-block: clamp(1.5rem, 3vw, 1.875rem); }
.ps--space-md   { padding-block: clamp(2.5rem, 5vw, 3.5rem); }
.ps--space-lg   { padding-block: clamp(3rem, 7vw, 4.5rem); }

/* ── 3. Typography ────────────────────────────────────────────────────────── */
/* Sizes come from style-lean §03. Only the section-specific bits live here:
   the eyebrow, the lead measure, the mono figures, and margin resets. */

.ps-head {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  margin-block-end: 2.25rem;
}

.ps-head:last-child { margin-block-end: 0; }

.ps-head--center {
  align-items: center;
  text-align: center;
  max-width: 46rem;
  margin-inline: auto;
}

.ps-eyebrow {
  margin: 0;
  font-size: var(--ds-eyebrow-size, .6875rem);
  font-weight: var(--ds-eyebrow-weight, 700);
  line-height: 1.2;
  letter-spacing: var(--ds-eyebrow-spacing, .1em);
  text-transform: uppercase;
  color: var(--ps-muted);
}

/* Heading tags keep the site scale; sections only drop the default margin and
   ask for balanced wrapping. */
.ps-title,
.ps-subtitle,
.ps-card__title { margin: 0; text-wrap: balance; }

/* Hero headings match the brand H1 exactly — style-lean §03 permits tuning
   hero H1 sizing, but the design board sized its heroes clamp(28px, 3.4vw,
   36px), which is that same range. No reason to exceed it. */
.ps-head--lg .ps-title {
  font-size: clamp(1.75rem, 4vw, 2.25rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.02em;
}

.ps-lead {
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--ps-text-2);
  max-width: 58ch;
  text-wrap: pretty;
}

.ps-head--lg .ps-lead { font-size: 1.1875rem; }
.ps-head--center .ps-lead { margin-inline: auto; }
.ps-lead > :first-child { margin-block-start: 0; }
.ps-lead > :last-child { margin-block-end: 0; }

.ps-prose {
  line-height: 1.65;
  color: var(--ps-text-2);
}

.ps-prose > :first-child { margin-block-start: 0; }
.ps-prose > :last-child { margin-block-end: 0; }
.ps-prose p { margin-block: 0 .875rem; }

.ps-prose--long { font-size: 1.0625rem; max-width: 68ch; color: var(--ps-text); }
.ps-prose--long > * + * { margin-block-start: 1.25rem; }

.ps-footnote {
  margin: 1.5rem 0 0;
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--ps-muted);
}

/* Mono numerals — the board sets every figure in JetBrains Mono */
.ps-figure-num {
  margin: 0;
  font-family: var(--ps-mono);
  font-weight: 700;
  font-size: 1.875rem;
  line-height: 1;
  letter-spacing: -.01em;
  color: var(--ps-link);
  font-variant-numeric: tabular-nums;
}

.ps-figure-num--xl { font-size: clamp(1.875rem, 3.5vw, 2.25rem); }

/* ── 4. Shared components: the deltas only ────────────────────────────────── */

/* Buttons are style-lean's .btn family. All that is needed here is the row. */
.ps-actions {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin-block-start: 1.5rem;
}

.ps-actions--center { justify-content: center; }
.ps-head + .ps-actions { margin-block-start: 0; }

/* Buttons on a filled panel.
   style-lean's dark-mode button rules assume the button sits on the *page*
   ground, and some of them are !important. A filled panel is the exception:
   in dark mode --ds-brand is a light blue, so the panel is lighter than the
   page and those rules would put a light-blue label on a light-blue panel.
   Restating the pair in the panel's own terms fixes both themes at once —
   .btn-white becomes "the panel's foreground color, filled". */
.ps .ps-actions--invert .btn.btn-white,
.ps .ps-tier--featured .btn.btn-white {
  background: var(--ps-on-brand);
  border-color: var(--ps-on-brand);
  color: var(--ps-brand) !important;
}

.ps .ps-actions--invert .btn.btn-white:hover,
.ps .ps-tier--featured .btn.btn-white:hover {
  background: color-mix(in srgb, var(--ps-on-brand) 88%, var(--ps-brand));
  border-color: color-mix(in srgb, var(--ps-on-brand) 88%, var(--ps-brand));
  color: var(--ps-brand) !important;
}

/* .btn-secondary is transparent by design; on a filled panel it takes the
   panel's foreground for both label and outline. */
.ps .ps-actions--invert .btn.btn-secondary,
.ps .ps-actions--invert .btn.btn--ghost {
  color: var(--ps-on-brand) !important;
  border-color: color-mix(in srgb, var(--ps-on-brand) 45%, transparent);
}

.ps .ps-actions--invert .btn.btn-secondary:hover,
.ps .ps-actions--invert .btn.btn--ghost:hover {
  background: color-mix(in srgb, var(--ps-on-brand) 14%, transparent);
  color: var(--ps-on-brand) !important;
  border-color: var(--ps-on-brand);
}

.ps-arrow { transition: transform .15s ease; }
.btn:hover .ps-arrow,
.ps-link:hover .ps-arrow { transform: translateX(2px); }

.ps-link {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  min-height: 44px;              /* WCAG 2.2 AA target size */
  font-size: .875rem;
  font-weight: 600;
  color: var(--ps-link);
  text-decoration: none;
}

.ps-link:hover { color: var(--ps-link); text-decoration: underline; text-underline-offset: 3px; }

.ps-dot {
  width: .5rem; height: .5rem;
  border-radius: 50%;
  background: currentColor;
}

.ps-badge--dot-positive .ps-dot { background: var(--ps-positive-fill); }
.ps-badge--dot-warning  .ps-dot { background: var(--ps-warning-fill); }
.ps-badge--dot-brand    .ps-dot { background: var(--ps-brand); }

/* Chips are style-lean's [data-chip] component; this is only the list. */
.ps-chips {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-meta {
  display: flex;
  flex-wrap: wrap;
  gap: .625rem;
  margin: 1rem 0 0;
  padding: 0;
  list-style: none;
  font-size: .8125rem;
  color: var(--ps-muted);
}

.ps-meta li + li::before {
  content: "·";
  margin-inline-end: .625rem;
  color: var(--ps-border-strong);
}

.ps-hero--centered .ps-meta,
.ps-hero--compact .ps-meta { justify-content: center; }

/* Icons */
.ps-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  font-size: 1.5rem;
  line-height: 1;
  color: var(--ps-link);
}

.ps-icon--tile {
  width: 2.875rem; height: 2.875rem;
  border-radius: var(--ps-radius-lg);
  background: var(--ps-brand-light);
}

.ps--tone-brand .ps-icon--tile,
.ps--tone-dark .ps-icon--tile { background: rgba(255, 255, 255, .12); }

.ps-icon--bare { font-size: 2.125rem; }

/* Ticked lists */
.ps-ticks {
  display: grid;
  gap: .625rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: .9375rem;
  line-height: 1.45;
  color: var(--ps-text-2);
}

.ps-ticks li {
  display: grid;
  grid-template-columns: 1.125rem 1fr;
  gap: .5625rem;
  align-items: start;
}

.ps-ticks li::before {
  content: "\2713";
  color: var(--ps-link);
  font-weight: 700;
  line-height: 1.45;
}

.ps-ticks li.is-excluded { color: var(--ps-muted); text-decoration: line-through; }
.ps-ticks li.is-excluded::before { content: "\2013"; color: var(--ps-muted); text-decoration: none; }

/* ── 5. Figures ───────────────────────────────────────────────────────────── */

.ps-figure {
  position: relative;
  overflow: hidden;
  border-radius: var(--ps-radius-lg);
  background: var(--ps-sunken);
}

.ps-figure img {
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
}

.ps-figure--fill { border-radius: 0; height: 100%; }

.ps-figure__placeholder {
  display: block;
  width: 100%; height: 100%;
  min-height: 12rem;
  background:
    repeating-linear-gradient(
      135deg,
      transparent 0 10px,
      color-mix(in srgb, var(--ps-border) 60%, transparent) 10px 11px
    );
}

/* ── 6. Hero ──────────────────────────────────────────────────────────────── */

.ps-hero__inner { display: grid; gap: clamp(2rem, 4vw, 3rem); }

.ps-hero__copy { display: flex; flex-direction: column; align-items: flex-start; gap: 1.125rem; }

.ps-hero--centered .ps-hero__copy,
.ps-hero--compact .ps-hero__copy { align-items: center; text-align: center; max-width: 45rem; margin-inline: auto; }

.ps-hero--centered .ps-head,
.ps-hero--compact .ps-head { margin-block-end: 0; }

.ps-hero--split .ps-hero__inner,
.ps-hero--split-reverse .ps-hero__inner { align-items: center; }

.ps-hero--split-reverse .ps-hero__copy { order: 2; }

.ps-hero--compact { --ps-w-default: 900px; }

/* Full-bleed: media under a scrim, copy on top */
.ps-hero--fullbleed {
  --ps-text: var(--ps-on-brand);
  --ps-text-2: var(--ps-on-brand-dim);
  --ps-muted: var(--ps-on-brand-dim);
  --ps-border: rgba(255, 255, 255, .22);
  --ps-border-strong: rgba(255, 255, 255, .4);
  --ps-link: var(--ps-on-brand);
  --ps-focus: #ffffff;
  background: var(--ps-brand);
  color: var(--ps-on-brand);
  overflow: hidden;
}

.ps-hero--fullbleed h1, .ps-hero--fullbleed h2, .ps-hero--fullbleed h3,
.ps-hero--fullbleed h4, .ps-hero--fullbleed h5, .ps-hero--fullbleed h6 { color: var(--ps-on-brand); }

.ps-hero__media { position: absolute; inset: 0; }
.ps-hero__media img { width: 100%; height: 100%; object-fit: cover; }

.ps-hero__scrim { position: absolute; inset: 0; }

.ps-hero--overlay-strong .ps-hero__scrim { background: color-mix(in srgb, var(--ps-brand) 88%, transparent); }
.ps-hero--overlay-medium .ps-hero__scrim {
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--ps-brand) 92%, transparent) 0%,
    color-mix(in srgb, var(--ps-brand) 72%, transparent) 52%,
    color-mix(in srgb, var(--ps-brand) 35%, transparent) 100%
  );
}
.ps-hero--overlay-soft .ps-hero__scrim { background: rgba(15, 23, 42, .55); }

.ps-hero--fullbleed .ps-hero__inner { position: relative; }
.ps-hero--fullbleed .ps-hero__copy { max-width: 38rem; }

@media (min-width: 62rem) {
  .ps-hero--split .ps-hero__inner,
  .ps-hero--split-reverse .ps-hero__inner { grid-template-columns: 1fr 1fr; }
  .ps-hero--split-reverse .ps-hero__aside { order: 1; }
}

/* ── 7. Stats ─────────────────────────────────────────────────────────────── */

.ps-stats__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 1.25rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-stats--strip .ps-stats__grid { text-align: center; max-width: 56rem; margin-inline: auto; }

.ps-stats--cards .ps-stats__item {
  padding: 1.5rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-surface);
  box-shadow: var(--ps-shadow);
}

.ps-stats__label {
  margin: .5rem 0 0;
  font-size: .8125rem;
  line-height: 1.45;
  color: var(--ps-text-2);
}

.ps-stats__note { display: block; margin-block-start: .25rem; color: var(--ps-muted); font-size: .75rem; }

.ps-stats__rows { margin: 0; }

.ps-stats__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: 1rem;
  border-block-end: 1px solid var(--ps-border);
}

.ps-stats__row:first-child { border-block-start: 1px solid var(--ps-border); }

.ps-stats__row-label { margin: 0; font-weight: 500; color: var(--ps-text); }
.ps-stats__row-value { display: flex; align-items: baseline; gap: .75rem; margin: 0; }

.ps-delta { font-family: var(--ps-mono); font-size: .8125rem; font-weight: 600; }
.ps-delta--positive { color: var(--ps-positive); }
.ps-delta--negative { color: var(--ps-negative); }
.ps-delta--neutral  { color: var(--ps-muted); }

/* ── 8. Feature rows ──────────────────────────────────────────────────────── */

.ps-feature__rows { display: grid; gap: clamp(2.5rem, 6vw, 4rem); }

.ps-feature__row { display: grid; gap: clamp(1.5rem, 4vw, 3rem); align-items: center; }

.ps-feature__copy { display: flex; flex-direction: column; align-items: flex-start; gap: .875rem; }

@media (min-width: 56rem) {
  .ps-feature__row { grid-template-columns: 1fr 1fr; }
  .ps-feature--ratio-copy  .ps-feature__row { grid-template-columns: 1.15fr .85fr; }
  .ps-feature--ratio-media .ps-feature__row { grid-template-columns: .85fr 1.15fr; }

  .ps-feature__row--media-left .ps-feature__copy  { order: 2; }
  .ps-feature__row--media-left .ps-feature__media { order: 1; }
}

/* ── 9. Cards ─────────────────────────────────────────────────────────────── */

.ps-cards__grid,
.ps-pricing__grid,
.ps-steps__list,
.ps-quote__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
  gap: 1.375rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 56rem) {
  .ps-cards__grid,
  .ps-pricing__grid,
  .ps-steps--cards .ps-steps__list,
  .ps-quote--grid .ps-quote__grid { grid-template-columns: repeat(var(--ps-cols), minmax(0, 1fr)); }
}

.ps-card { display: flex; flex-direction: column; gap: .75rem; }

.ps-cards--card .ps-card {
  padding: 1.625rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-surface);
  box-shadow: var(--ps-shadow);
}

.ps-cards--row .ps-cards__grid { grid-template-columns: 1fr; }

.ps-cards--row .ps-card {
  flex-direction: row;
  align-items: flex-start;
  gap: 1rem;
  padding: 1.125rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  box-shadow: var(--ps-shadow);
}

.ps-cards--row .ps-card__body { flex: 1; }
.ps-cards--plain .ps-card { gap: .625rem; }

.ps-card__link { margin-block-start: auto; }

/* ── 10. Steps ────────────────────────────────────────────────────────────── */

.ps-steps__item { display: flex; flex-direction: column; gap: .625rem; }

.ps-steps--cards .ps-steps__item {
  padding: 1.625rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-raised);
}

.ps-steps--list .ps-steps__list,
.ps-steps--timeline .ps-steps__list { grid-template-columns: 1fr; gap: 0; }

.ps-steps--list .ps-steps__item,
.ps-steps--timeline .ps-steps__item {
  flex-direction: row;
  gap: 1.25rem;
  padding-block: 1.5rem;
  border-block-end: 1px solid var(--ps-border);
}

.ps-steps--timeline .ps-steps__item { position: relative; padding-inline-start: .25rem; border-block-end: 0; }

.ps-steps--timeline .ps-steps__item:not(:last-child)::before {
  content: "";
  position: absolute;
  inset-block: 3rem 0;
  inset-inline-start: 1.0625rem;
  width: 1px;
  background: var(--ps-border);
}

.ps-steps__num { font-size: 1.375rem; flex: none; }

.ps-steps--timeline .ps-steps__num {
  display: grid;
  place-items: center;
  width: 2.125rem; height: 2.125rem;
  border-radius: 50%;
  background: var(--ps-brand-light);
  font-size: .8125rem;
}

.ps-steps__body { display: flex; flex-direction: column; gap: .5rem; }

/* ── 11. Bento ────────────────────────────────────────────────────────────── */

.ps-bento__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  gap: 1.125rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-bento__tile {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 1rem;
  min-height: 11.5rem;
  padding: 1.5rem;
  border: 1px solid var(--ps-border);
  border-radius: 14px;
  overflow: hidden;
}

.ps-bento__tile--tone-surface { background: var(--ps-surface); box-shadow: var(--ps-shadow); }
.ps-bento__tile--tone-raised  { background: var(--ps-raised); }

/* Same pairing rule as the section tones above — see §2. */
.ps-bento__tile--tone-brand,
.ps-bento__tile--tone-dark {
  /* Re-declared, not inherited: --ps-on-brand-dim resolves on the element
     that declares it, so a tile re-pointing --ps-on-brand needs its own. */
  --ps-on-brand-dim: color-mix(in srgb, var(--ps-on-brand) 90%, var(--ps-brand));
  --ps-text: var(--ps-on-brand);
  --ps-text-2: var(--ps-on-brand-dim);
  --ps-muted: var(--ps-on-brand-dim);
  --ps-border: color-mix(in srgb, var(--ps-on-brand) 24%, transparent);
  --ps-link: var(--ps-on-brand);
  color: var(--ps-on-brand);
  border-color: transparent;
}

/* Cards that paint their own brand surface need the whole foreground pair,
   otherwise --ps-muted still resolves to the page's gray and lands at 2.07:1
   on the panel. Same remap as .ps--tone-brand, scoped to the card. */
.ps-tier--featured,
.ps-bento__tile--tone-brand,
.ps-bento__tile--tone-dark {
  --ps-text: var(--ps-on-brand);
  --ps-text-2: var(--ps-on-brand-dim);
  --ps-muted: var(--ps-on-brand-dim);
  --ps-border: color-mix(in srgb, var(--ps-on-brand) 24%, transparent);
  --ps-link: var(--ps-on-brand);
}

.ps-bento__tile--tone-brand { background: var(--ps-brand); }

.ps-bento__tile--tone-dark {
  --ps-brand: #0f172a;
  --ps-brand-light: rgba(255, 255, 255, .12);
  --ps-on-brand: #f1f5f9;
  background: #0f172a;
}

.ps-bento__tile--tone-brand h1, .ps-bento__tile--tone-brand h2, .ps-bento__tile--tone-brand h3,
.ps-bento__tile--tone-brand h4, .ps-bento__tile--tone-brand h5, .ps-bento__tile--tone-brand h6,
.ps-bento__tile--tone-dark h1, .ps-bento__tile--tone-dark h2, .ps-bento__tile--tone-dark h3,
.ps-bento__tile--tone-dark h4, .ps-bento__tile--tone-dark h5, .ps-bento__tile--tone-dark h6 { color: var(--ps-on-brand); }

.ps-bento__tile--image { padding: 0; }
.ps-bento__tile--stat  { justify-content: center; gap: .375rem; }

.ps-bento__body { display: flex; flex-direction: column; gap: .5rem; }

/* style-lean gives every blockquote a 45px margin and a left rule; inside a
   tile that reads as a stray divider. */
.ps-bento__quote {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 1.0625rem;
  font-weight: 500;
  line-height: 1.5;
}

.ps-bento__quote p { margin: 0 !important; font-size: inherit; font-weight: inherit; line-height: inherit; }
.ps-bento__cite { margin: .5rem 0 0; font-size: .8125rem; color: var(--ps-muted); }

@media (min-width: 56rem) {
  .ps-bento__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: minmax(11.5rem, auto); }
  .ps-bento__tile--span-2-1 { grid-column: span 2; }
  .ps-bento__tile--span-1-2 { grid-row: span 2; }
  .ps-bento__tile--span-2-2 { grid-column: span 2; grid-row: span 2; }
}

/* ── 12. Pricing ──────────────────────────────────────────────────────────── */

.ps-pricing__grid { align-items: start; }

.ps-tier {
  display: flex;
  flex-direction: column;
  gap: 1.125rem;
  height: 100%;
  padding: 1.75rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-surface);
}

.ps-tier--featured {
  /* Re-declared, not inherited: --ps-on-brand-dim resolves on the element
     that declares it, so a tile re-pointing --ps-on-brand needs its own. */
  --ps-on-brand-dim: color-mix(in srgb, var(--ps-on-brand) 90%, var(--ps-brand));
  --ps-text: var(--ps-on-brand);
  --ps-text-2: var(--ps-on-brand-dim);
  --ps-muted: var(--ps-on-brand-dim);
  --ps-link: var(--ps-on-brand);
  background: var(--ps-brand);
  border-color: var(--ps-brand);
  color: var(--ps-on-brand);
  box-shadow: var(--ps-shadow-lg);
}

.ps-tier--featured .ps-figure-num,
.ps-tier--featured .ps-eyebrow,
.ps-tier--featured h1, .ps-tier--featured h2, .ps-tier--featured h3,
.ps-tier--featured h4, .ps-tier--featured h5, .ps-tier--featured h6 { color: var(--ps-on-brand); }

.ps-tier__badge {
  align-self: flex-start;
  margin: 0;
  padding: .25rem .625rem;
  border-radius: 999px;
  background: var(--ps-on-brand);
  color: var(--ps-brand);
  font-size: .6875rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.ps-tier:not(.ps-tier--featured) .ps-tier__badge { background: var(--ps-brand-light); color: var(--ps-brand); }

.ps-tier__price { display: flex; align-items: baseline; gap: .375rem; margin: 0; }
.ps-tier__price .ps-figure-num { font-size: 2.125rem; color: var(--ps-text); }
.ps-tier__price-note { font-size: .875rem; color: var(--ps-muted); }
.ps-tier__summary { font-size: .875rem; }
.ps-tier__features { font-size: .875rem; }
.ps-tier__cta { margin-block-start: auto; justify-content: center; }

/* ── 13. Comparison table ─────────────────────────────────────────────────── */

.ps-compare__scroll { overflow-x: auto; }

.ps-compare__table {
  width: 100%;
  border-collapse: collapse;
  font-size: .875rem;
  text-align: start;
}

.ps-compare__table th,
.ps-compare__table td {
  padding: .875rem 1rem;
  border-block-end: 1px solid var(--ps-border);
  text-align: start;
  vertical-align: top;
}

.ps-compare__table thead th {
  border-block-end: 2px solid var(--ps-border-strong);
  color: var(--ps-text);
  font-weight: 700;
}

.ps-compare__col-label { display: block; }
.ps-compare__col-note {
  display: block;
  margin-block-start: .25rem;
  font-family: var(--ps-mono);
  font-size: .75rem;
  font-weight: 400;
  line-height: 1.3;
  color: var(--ps-muted);
}

.ps-compare__table tbody th { font-weight: 500; color: var(--ps-text); }
.ps-compare__table td { color: var(--ps-text-2); }

.ps-compare__group th {
  padding-block: 1.25rem .5rem;
  border-block-end: 0;
  font-size: .6875rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ps-muted);
}

/* The tint lifts the ground, so the highlighted column takes the primary text
   color — secondary and muted both drop under 7:1 on #dce5ec. */
.ps-compare__table .is-highlighted { background: var(--ps-brand-light); color: var(--ps-text); }
.ps-compare__table .is-highlighted .ps-compare__col-note { color: var(--ps-text); }
/* Brand, not green: the tick must clear 3:1 as a non-text indicator on the
   highlighted column too, where a green tick lands at 2.9:1. */
.ps-tick  { color: var(--ps-link); font-weight: 700; }
.ps-cross { color: var(--ps-muted); }

/* ── 14. Checklist & scorecard ────────────────────────────────────────────── */

.ps-checklist__list {
  display: grid;
  gap: .875rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 48rem) {
  .ps-checklist--columns .ps-checklist__list { grid-template-columns: repeat(var(--ps-cols), minmax(0, 1fr)); }
}

.ps-checklist__item {
  display: grid;
  grid-template-columns: 1.25rem 1fr;
  gap: .625rem;
  align-items: start;
  font-size: .9375rem;
  line-height: 1.5;
  color: var(--ps-text-2);
}

.ps-checklist__item::before {
  content: "\2713";
  color: var(--ps-link);
  font-weight: 700;
}

.ps-checklist--marker-dot .ps-checklist__item::before { content: "\2022"; }
.ps-checklist--marker-number .ps-checklist__list { counter-reset: ps-step; }
.ps-checklist--marker-number .ps-checklist__item { counter-increment: ps-step; }
.ps-checklist--marker-number .ps-checklist__item::before {
  content: counter(ps-step);
  font-family: var(--ps-mono);
  font-size: .8125rem;
}

.ps-checklist__label { color: var(--ps-text); font-weight: 500; }
.ps-checklist__detail { grid-column: 2; margin-block-start: .25rem; font-size: .875rem; }

.ps-checklist--scorecard .ps-checklist__item {
  padding-block: .875rem;
  border-block-end: 1px solid var(--ps-border);
}

.ps-checklist--scorecard .is-pending::before { content: "\2013"; color: var(--ps-warning); }
.ps-checklist--scorecard .is-na::before { content: "\00B7"; color: var(--ps-muted); }
.ps-checklist--scorecard .is-na .ps-checklist__label { color: var(--ps-muted); }

.ps-score { display: flex; align-items: center; gap: 1rem; margin: 0 0 1.5rem; }

.ps-score__bar {
  flex: 1;
  height: .5rem;
  max-width: 20rem;
  border-radius: 999px;
  background: var(--ps-sunken);
  overflow: hidden;
}

.ps-score__bar > span { display: block; height: 100%; border-radius: inherit; background: var(--ps-link); }

/* ── 15. FAQ ──────────────────────────────────────────────────────────────── */

.ps-faq__inner { display: grid; gap: 2rem; }
.ps-faq__list { display: grid; gap: .75rem; }

@media (min-width: 56rem) {
  .ps-faq--split .ps-faq__inner { grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); gap: 3rem; align-items: start; }
  .ps-faq--split .ps-faq__intro { position: sticky; top: 2rem; }
  .ps-faq--open .ps-faq__list { grid-template-columns: repeat(var(--ps-cols), minmax(0, 1fr)); gap: 2rem; }
}

.ps-faq__group {
  margin: 1.5rem 0 .25rem;
  font-size: .6875rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ps-muted);
}

.ps-faq__group:first-child { margin-block-start: 0; }

.ps-faq__details {
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-surface);
}

.ps-faq__details .ps-faq__question {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 44px;
  padding: 1rem 1.25rem;
  margin: 0;
  cursor: pointer;
  list-style: none;
}

.ps-faq__details .ps-faq__question::-webkit-details-marker { display: none; }
.ps-faq__details .ps-faq__answer { padding: 0 1.25rem 1.25rem; }

/* style-lean's focus ring covers a, button and form controls — not summary. */
.ps-faq__question:focus-visible { outline: 3px solid var(--ps-focus); outline-offset: 3px; border-radius: var(--ds-radius-xs, 4px); }

.ps-faq__chevron {
  flex: none;
  width: .5rem; height: .5rem;
  border-inline-end: 2px solid currentColor;
  border-block-end: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform .15s ease;
}

.ps-faq__details[open] .ps-faq__chevron { transform: rotate(-135deg); }

.ps-faq--open .ps-faq__question { margin: 0 0 .5rem; }
.ps-faq--open .ps-faq__item + .ps-faq__item { margin-block-start: 1.5rem; }

/* ── 16. Quote ────────────────────────────────────────────────────────────── */

.ps-quote__item { margin: 0; display: flex; flex-direction: column; gap: 1rem; }

/* Overrides style-lean's global blockquote rule (45px margins, left border),
   which is tuned for quotes inside article prose, not for a full-width band. */
.ps-quote__text {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 1.25rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--ps-text);
  text-wrap: pretty;
}

.ps-quote__text p {
  margin: 0 !important;
  font-size: inherit;
  font-weight: inherit;
  line-height: inherit;
}

.ps-quote__text::before { content: "\201C"; }
.ps-quote__text::after  { content: "\201D"; }

.ps-quote__cite { display: flex; flex-direction: column; gap: .125rem; font-size: .875rem; }
.ps-quote__author { font-weight: 600; color: var(--ps-text); }
.ps-quote__role { color: var(--ps-muted); }
.ps-quote__portrait { width: 3.5rem; height: 3.5rem; border-radius: 50%; object-fit: cover; }

.ps-quote--band .ps-quote__item { align-items: center; text-align: center; max-width: 52rem; margin-inline: auto; }
.ps-quote--band .ps-quote__text { font-size: clamp(1.25rem, 2.4vw, 1.5rem); }
.ps-quote--band .ps-quote__cite { align-items: center; }

.ps-quote--plain .ps-quote__item { border-block-start: 2px solid var(--ps-border-strong); padding-block-start: 1.5rem; }

.ps-quote--card .ps-quote__item {
  flex-direction: row;
  align-items: center;
  gap: 1.5rem;
  padding: 1.75rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-surface);
  box-shadow: var(--ps-shadow);
}

.ps-quote--grid .ps-quote__text { font-size: 1rem; font-weight: 500; }

/* ── 17. Logos ────────────────────────────────────────────────────────────── */

.ps-logos__inner { display: flex; flex-direction: column; align-items: center; gap: 1.125rem; text-align: center; }

.ps-logos__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 1.5rem 2.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ps-logos__item img {
  display: block;
  width: auto;
  max-width: 8rem;
  max-height: 2.25rem;
  object-fit: contain;
}

.ps-logos__wordmark { font-size: 1rem; font-weight: 600; color: var(--ps-muted); }

.ps-logos--muted .ps-logos__item { filter: grayscale(1); opacity: .75; transition: filter .15s ease, opacity .15s ease; }
.ps-logos--muted .ps-logos__item:hover,
.ps-logos--muted .ps-logos__item:focus-within { filter: none; opacity: 1; }

.ps-logos--grid .ps-logos__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px;
  background: var(--ps-border);
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  overflow: hidden;
}

.ps-logos--grid .ps-logos__item {
  display: grid;
  place-items: center;
  min-height: 5.5rem;
  padding: 1rem;
  background: var(--ps-surface);
}

/* ── 18. CTA ──────────────────────────────────────────────────────────────── */

.ps-cta__panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding: clamp(2rem, 5vw, 3.25rem) clamp(1.5rem, 4vw, 2.5rem);
  border-radius: var(--ps-radius-xl);
  text-align: center;
}

/* The panel inherits the section tone; an unfilled section gets a bordered
   card so the CTA still reads as a distinct band. */
.ps--tone-surface.ps-cta .ps-cta__panel,
.ps--tone-none.ps-cta .ps-cta__panel { background: var(--ps-raised); border: 1px solid var(--ps-border); }

.ps-cta--inline .ps-cta__panel {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  text-align: start;
}

/* The panel's own gap already separates copy from actions, so the defaults
   that space a heading from the buttons below it are canceled here. */
.ps-cta__copy { min-width: 0; }
.ps-cta__panel .ps-head { margin-block-end: 0; }
.ps-cta__panel .ps-actions { margin-block-start: 0; }

.ps-cta__actions { display: flex; flex-direction: column; align-items: center; }
.ps-cta--inline .ps-cta__actions { align-items: flex-start; }

.ps-cta--bar .ps__inner { max-width: none; padding-inline: 0; }
.ps-cta--bar .ps-cta__panel { border-radius: 0; }

.ps-cta__note { margin: .75rem 0 0; font-size: .8125rem; color: var(--ps-muted); }

@media (max-width: 47.99rem) {
  .ps-cta--inline .ps-cta__panel { flex-direction: column; align-items: flex-start; }
}

/* ── 19. Signup ───────────────────────────────────────────────────────────── */

.ps-signup__inner {
  display: grid;
  gap: 2rem;
  padding-block: clamp(1.75rem, 4vw, 2.5rem);
  padding-inline: clamp(1.5rem, 4vw, 2.5rem);
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-xl);
  background: var(--ps-raised);
}

.ps-signup__copy { display: flex; flex-direction: column; gap: 1rem; }

.ps-signup__form form {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1.5rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-surface);
  box-shadow: var(--ps-shadow);
}

.ps-field { display: flex; flex-direction: column; gap: .375rem; }

/* style-lean §06 styles the control itself; these are the deltas a stacked
   field needs — its 20px bottom margin, the target floor and the radius. */
.ps-field__label { margin: 0; font-size: .8125rem; font-weight: 600; color: var(--ps-text); }

.ps-field__input {
  margin: 0;
  min-height: 44px;
  border-radius: var(--ps-radius);
  border-color: var(--ps-border-strong);
  background: var(--ps-surface);
  color: var(--ps-text);
}

.ps-field__help { margin: 0; font-size: .75rem; line-height: 1.45; color: var(--ps-muted); }

.ps-signup--centered .ps-signup__inner { justify-items: center; text-align: center; max-width: 40rem; margin-inline: auto; }
.ps-signup--centered .ps-signup__form { width: 100%; }

.ps-signup--inline .ps-signup__form form { flex-direction: row; align-items: flex-end; flex-wrap: wrap; }
.ps-signup--inline .ps-field { flex: 1 1 14rem; }

@media (min-width: 56rem) {
  .ps-signup--split .ps-signup__inner { grid-template-columns: 1fr .9fr; align-items: center; gap: 2.5rem; }
}

/* ── 20. Media band ───────────────────────────────────────────────────────── */

.ps-media__figure { margin: 0; }
.ps-media__frame { display: grid; gap: 1rem; }
.ps-media--duo .ps-media__frame { grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); }
.ps-media--bleed .ps__inner { max-width: none; padding-inline: 0; }
.ps-media--bleed .ps-figure { border-radius: 0; }

.ps-media__caption { margin-block-start: .875rem; color: var(--ps-muted); }

.ps-media__caption--mono {
  font-family: var(--ps-mono);
  font-size: .75rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: .04em;
  text-transform: uppercase;
}

.ps-media__caption--prose { font-size: .875rem; line-height: 1.6; }

/* ── 21. Prose column & rail ──────────────────────────────────────────────── */

.ps-prose-section__inner { display: grid; gap: 2.5rem; }

.ps-rail__inner { display: flex; flex-direction: column; gap: 1rem; }
.ps-rail__nav ul { margin: 0; padding: 0; list-style: none; display: grid; gap: .125rem; }

.ps-rail__nav a,
.ps-rail__nav span {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding-inline-start: .875rem;
  border-inline-start: 2px solid var(--ps-border);
  font-size: .875rem;
  line-height: 1.4;
  color: var(--ps-text-2);
  text-decoration: none;
}

.ps-rail__nav a:hover { border-inline-start-color: var(--ps-brand); color: var(--ps-text); }

.ps-rail__meta {
  margin: 0;
  padding: 1.25rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius-lg);
  background: var(--ps-raised);
  font-size: .875rem;
}

.ps-rail__meta dt { font-weight: 600; color: var(--ps-text); }
.ps-rail__meta dd { margin: 0 0 .875rem; color: var(--ps-text-2); }
.ps-rail__meta dd:last-child { margin-block-end: 0; }

@media (min-width: 62rem) {
  .ps-prose-section--rail-left.has-rail .ps-prose-section__inner  { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); }
  .ps-prose-section--rail-right.has-rail .ps-prose-section__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 18rem); }
  .ps-prose-section--rail-left .ps-prose-section__main { order: 2; }
  .ps-prose-section--rail-left .ps-rail { order: 1; }
  .ps-rail__inner { position: sticky; top: 2rem; }
}

/* The prose column hosts the site's extended blocks (metrics, timeline, charts,
   …). They bring their own styling; all that is needed here is the rhythm. */
.ps-prose--long > .blocks > * + * { margin-block-start: 1.5rem; }

/* ── 22. Focus, motion, print ─────────────────────────────────────────────── */

/* style-lean §02 already covers a, button, input, select and textarea.
   Only the elements it does not reach are handled here. */
.ps :where(summary, [tabindex]):focus-visible {
  outline: 3px solid var(--ps-focus);
  outline-offset: 3px;
  border-radius: var(--ds-radius-xs, 4px);
}

/* Links and buttons inside a section.
   ────────────────────────────────────────────────────────────────────────────
   The same fault that was fixed for form controls, left in place everywhere
   else. style-lean sets `outline: 3px solid #294557` for a:focus-visible and
   .btn:focus-visible, and that value IS --ps-brand — so every call-to-action in
   a brand-toned section drew a navy ring on a navy background. Measured at
   1.00:1: completely invisible, on the most-clicked element on a landing page.

   --ps-focus already flips per tone and was already wired to the FAQ, summary,
   [tabindex], the sessions links and the dataflow scroller. Plain links and
   buttons were simply never included.

   Specificity is deliberate rather than incidental. `.btn:focus-visible` is
   0-2-0, and `.ps :where(a, button):focus-visible` is also 0-2-0 — a tie decided
   by which stylesheet loads last, which is not something to rely on. The
   explicit `.ps a.btn` / `.ps button.btn` selectors are 0-3-1 and win outright. */
.ps :where(a, button):focus-visible,
.ps a.btn:focus-visible,
.ps button.btn:focus-visible {
  outline: 3px solid var(--ps-focus);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  .ps *,
  .ps *::before,
  .ps *::after {
    transition-duration: .01ms !important;
    animation-duration: .01ms !important;
  }
}

@media print {
  .ps { background: none !important; color: #000 !important; padding-block: 1rem; }
  .ps-hero__media,
  .ps-figure__placeholder { display: none; }
  .ps-faq__details { border: 0; }
  .ps-faq__details > .ps-faq__answer { display: block !important; }
}

/* ─────────────────────────────────────────────────────────────
   Section — Form
   Editor-defined fields. Sizing follows the site's 44px minimum
   tap target; focus uses the same 3px brand outline as the rest
   of the site rather than a bespoke ring.
   ───────────────────────────────────────────────────────────── */

.ps-form__inner { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }
.ps-form--split .ps-form__inner { grid-template-columns: 1fr; }

@media (min-width: 56rem) {
  .ps-form--split .ps-form__inner { grid-template-columns: 1fr 1fr; align-items: start; }
}

.ps-form--centered .ps-form__inner,
.ps-form--plain .ps-form__inner { max-width: 42rem; margin-inline: auto; }

.ps-form--split .ps-form__panel,
.ps-form--centered .ps-form__panel {
  background: var(--ds-surface, #fff);
  border: 1px solid var(--ds-border, #e5e7eb);
  border-radius: var(--ds-radius-lg, 12px);
  padding: clamp(1.25rem, 3vw, 2rem);

  /* This panel paints its own light surface, so it is a light island inside
     whatever tone the section is wearing. Without putting the tokens back, a
     form in a brand-toned section inherited the on-brand set and drew white on
     white: the focus ring measured 1.00:1, links were invisible, and borders
     sat at 24% white. Restores the same values .ps establishes, so the panel
     always matches the surface it actually paints. */
  --ps-text:   var(--ds-text-primary, #232323);
  --ps-text-2: var(--ds-text-secondary, #475569);
  --ps-muted:  var(--ds-text-muted, #525252);

  --ps-border:        var(--ds-border, #e5e7eb);
  --ps-border-strong: var(--ds-border-strong, #d1d5db);
  --ps-focus:         var(--ds-border-focus, #294557);
  --ps-link:          var(--ds-link, #294557);

  color: var(--ps-text);
}

.ps-form__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }

/* The base rule comes FIRST, before the width modifiers.
   It used to sit after them, and because `.ps-form__field` and
   `.ps-form__field--half` have the same specificity, the later declaration won:
   every half-width field computed `grid-column: 1 / -1` and spanned both columns.
   A field set to 1/2 in the Panel rendered full width, at every viewport, and had
   done since the option existed. */
.ps-form__field { grid-column: 1 / -1; display: flex; flex-direction: column; gap: .375rem; }

.ps-form__field--full { grid-column: 1 / -1; }
.ps-form__field--half { grid-column: 1 / -1; }

@media (min-width: 34rem) {
  .ps-form__field--half { grid-column: span 1; }
}

/* Group heading in a long form. The rule above it does the separating, so the
   heading itself keeps the h3-h6 size it inherits from the site scale rather
   than being restyled here. First one has no rule — nothing to separate yet. */
.ps-form__group { gap: .25rem; margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--ds-border, #e5e7eb); }
.ps-form__group:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.ps-form__grouphead { margin: 0; }

/* ── repeatable groups ─────────────────────────────────────────────────────
   A distinct prefix from .ps-form__group, which is the radio/checkbox
   fieldset — the two are unrelated, and sharing a name made the repeatable
   container inherit a border it should not have.

   Every colour and radius here is one of the plugin's own --ps-* tokens. The
   first draft reached for --ds-* names that do not exist in this stylesheet,
   so every one silently fell back to a hardcoded grey: the button borders
   measured 1.24:1 against the page, which fails 1.4.11 for the one visual
   boundary that identifies them as buttons. */
.ps-form__repeat { grid-column: 1 / -1; display: flex; flex-direction: column; gap: .75rem; }
.ps-form__repeatrows { display: flex; flex-direction: column; gap: .75rem; }

/* Each row is a real fieldset, so the reset that normally strips fieldset
   chrome has to be undone here: the border is what makes one person's block of
   answers read as one block. The grouping is carried by the legend as well, so
   this border is reinforcement rather than the only signal. */
.ps-form__repeatrow {
  margin: 0;
  padding: 1rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ps-radius);
}
.ps-form__repeatrowlegend {
  padding: 0 .375rem;
  font-weight: 600;
  font-size: .9375rem;
  color: var(--ps-text);
}

.ps-form__grid--repeat { margin-bottom: .75rem; }

/* Both buttons are secondary to the form's submit: they change the form, they
   do not send it, and looking like the submit button is how a visitor ends up
   clicking the wrong one.

   The border is --ps-brand, not --ps-border-strong. Measured in the browser,
   --ps-border-strong resolves to 1.47:1 against the form's surface and
   --ps-border to 1.24:1 — both well under the 3:1 that 1.4.11 asks of the
   visual boundary identifying a control, and here the boundary is the only
   thing that makes these read as buttons. --ps-brand measures 10.08:1 and is
   already the text colour, so the control is an outline button rather than an
   invention. (That --ps-border-strong does not reach 3:1 is worth looking at
   across the design system; changing a shared token is not this change's
   business.) */
.ps-form__repeatadd,
.ps-form__repeatremove {
  align-self: flex-start;
  padding: .5rem .875rem;
  font: inherit;
  font-size: .875rem;
  color: var(--ps-brand);
  background: var(--ps-surface);
  border: 1px solid var(--ps-brand);
  border-radius: var(--ps-radius);
  cursor: pointer;
}
.ps-form__repeatadd:hover,
.ps-form__repeatremove:hover { color: var(--ps-on-brand); background: var(--ps-brand); }

/* Focus is inherited from the form's own visible-focus rule rather than
   restated here: a second definition is how the focus ring ended up at 1.00:1
   in this plugin once already. */

/* Announcements only — never a layout box. Kept in the flow with no fixed size
   so it is not a hidden region, which some screen readers stop watching. */
.ps-form__repeatlive {
  margin: 0;
  font-size: .875rem;
  color: var(--ps-muted);
}

@media (prefers-reduced-motion: no-preference) {
  .ps-form__repeatrow { transition: border-color .15s ease; }
}

.ps-form__groupnote { margin: 0; font-size: .875rem; color: var(--ds-text-secondary, #475569); }

.ps-form__label {
  font-size: .9375rem;
  font-weight: 600;
  color: var(--ds-text-primary, #232323);
}

.ps-form__req { color: var(--ds-error, #dc2626); }

/* Visible only to screen readers — carries "(required)" so the
   asterisk isn't the sole indicator. */
.ps-form__sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.ps-form__help { font-size: .875rem; color: var(--ds-text-secondary, #475569); margin: 0; }

.ps-form__error {
  font-size: .875rem;
  font-weight: 500;
  color: var(--ds-error-text, #991b1b);
  margin: 0;
}

/* Controls do not inherit typography by default; without this checkboxes and
   radios fall back to the UA font (Arial) rather than Inter. */
.ps-form__form input,
.ps-form__form select,
.ps-form__form textarea,
.ps-form__form button,
.ps-onboarding__check { font-family: inherit; }

.ps-form__form input[type="text"],
.ps-form__form input[type="email"],
.ps-form__form input[type="tel"],
.ps-form__form input[type="url"],
.ps-form__form input[type="number"],
.ps-form__form input[type="date"],
.ps-form__form textarea,
.ps-form__form select {
  width: 100%;
  min-height: 2.75rem;               /* 44px tap target */
  padding: .625rem .75rem;
  font: inherit;
  font-size: 1rem;                   /* 16px — stops iOS zoom on focus */
  color: var(--ds-text-primary, #232323);
  background: var(--ds-surface, #fff);
  border: 1px solid var(--ds-border-strong, #d1d5db);
  border-radius: var(--ds-radius, 8px);
}

.ps-form__form textarea { min-height: 7rem; resize: vertical; }

.ps-form__field--invalid input,
.ps-form__field--invalid textarea,
.ps-form__field--invalid select { border-color: var(--ds-error, #dc2626); }

.ps-form__fieldset { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .375rem; }
.ps-form__choices { display: flex; flex-direction: column; gap: .5rem; margin-top: .25rem; }

.ps-form__choice { display: flex; align-items: flex-start; gap: .625rem; min-height: 2.75rem; }
/* 1.5rem = 24px: WCAG 2.5.8 Target Size (Minimum), AA. Both the UA default
   and the 1.25rem this used to carry sit under that floor. */
.ps-form__choice input { width: 1.5rem; height: 1.5rem; margin-top: .0625rem; flex: none; }
.ps-form__choice label { font-size: .9375rem; line-height: 1.5; }

/* Focus indicators for form controls.

   style-lean.css sets a hardcoded `outline: 3px solid #294557` for every
   focused input. That value is also what --ps-brand resolves to, so a form
   sitting in a brand-toned section drew its focus ring at 1.00:1 against its
   own background — invisible, SC 2.4.7 and 1.4.11. Dark mode was 1.44:1.

   The plugin already flips --ps-focus per tone (white on brand, light in dark
   mode) and applies it to the FAQ and [tabindex] elements; the form controls
   were simply never wired to it.

   The :not() chain mirrors style-lean's own selector so these rules win on
   specificity rather than on which stylesheet happens to load last. */
.ps-form :where(input[type="radio"], input[type="checkbox"], select, textarea, button):focus-visible {
  outline: 3px solid var(--ps-focus);
  outline-offset: 3px;
}

.ps-form input:not([type="radio"]):not([type="checkbox"]):not([type="range"]):not([type="file"]):focus-visible {
  outline: 3px solid var(--ps-focus);
  outline-offset: 3px;
  /* style-lean pairs its ring with a border tint; keep that, in a colour that
     tracks the tone instead of the hardcoded navy. */
  border-color: var(--ps-focus);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ps-focus) 25%, transparent);
}

/* ── Wizard ─────────────────────────────────────────────────────────────────
   Only ever present once the script has run; the server renders the form as
   one page, so none of this applies to a no-JS visitor. */

/* `hidden` means hidden — everywhere in the plugin, whatever else is set.

   The attribute only carries display:none from the user-agent sheet, so any
   author rule that sets display beats it. That has now caught three separate
   features: wizard steps (.ps-form__field is flex), conditional fields, and
   agenda rows (a grid inside a media query, which tied on specificity and won
   on source order). Each time the symptom was the same and quiet — the element
   stayed on screen AND in the tab order, which is the one thing `hidden` is
   relied on to guarantee.

   !important rather than a specificity arms race, because this is a
   correctness invariant rather than a style preference: nothing added later
   should be able to un-hide something the markup says is hidden. */
.ps [hidden] { display: none !important; }

.ps-form__progress {
  font-size: .875rem;
  font-weight: 600;
  color: var(--ps-muted);
  margin: 0 0 1rem;
}

.ps-form__wizard-nav {
  display: flex;
  flex-wrap: wrap;
  gap: .75rem;
  margin-top: 1.25rem;
}

/* A disabled Back on step one still has to be legible — a greyed-out control
   that drops under 4.5:1 is a contrast failure whether or not it is clickable. */
.ps-form__back[disabled] {
  opacity: .55;
  cursor: not-allowed;
}

/* Visually hidden, still announced. Not `display: none`, which would take it
   out of the accessibility tree and silence the live region. */
.ps-form__sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.ps-form__errors {
  border: 2px solid var(--ds-error, #dc2626);
  background: var(--ds-error-bg, #fef2f2);
  border-radius: var(--ds-radius, 8px);
  padding: 1rem;
  margin-bottom: 1.25rem;
}

.ps-form__errors-title { font-weight: 700; margin: 0 0 .5rem; color: var(--ds-error-text, #991b1b); }
.ps-form__errors ul { margin: 0; padding-left: 1.25rem; }
.ps-form__errors a { color: var(--ds-error-text, #991b1b); }

.ps-form__success {
  border: 2px solid var(--ds-success, #059669);
  background: var(--ds-success-bg, #ecfdf5);
  color: var(--ds-success-text, #065f46);
  border-radius: var(--ds-radius, 8px);
  padding: 1.25rem;
}

.ps-form__success p { margin: 0; }
.ps-form__actions { margin-top: 1.25rem; }
.ps-form__note { font-size: .8125rem; color: var(--ds-text-muted, #525252); margin: .75rem 0 0; }

/* Honeypot — hidden from sighted users and from assistive tech.
   display:none is deliberate: the field must not be reachable at all. */
.ps-form__hp { display: none; }

/* ─────────────────────────────────────────────────────────────
   Section — Onboarding checklist
   Progress column beside hairline rows (ui.beste.co onboarding33,
   board 15a). Bar and figure move together as rows are ticked.
   ───────────────────────────────────────────────────────────── */

.ps-onboarding__inner { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }

@media (min-width: 56rem) {
  .ps-onboarding__inner { grid-template-columns: minmax(0, 20rem) 1fr; align-items: start; }
  .ps-onboarding__aside { position: sticky; top: 2rem; }
}

.ps-onboarding__figure { display: flex; align-items: baseline; gap: .5rem; margin: 1rem 0 .5rem; }

.ps-onboarding__figure .ps-figure-num {
  font-size: clamp(2.75rem, 8vw, 4rem);
  font-weight: 300;
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--ds-brand, #294557);
}

.ps-onboarding__figure-label { font-size: .9375rem; color: var(--ds-text-secondary, #475569); }

.ps-onboarding__bar {
  display: block;
  height: .375rem;
  border-radius: 999px;
  background: var(--ds-border, #e5e7eb);
  overflow: hidden;
}

.ps-onboarding__bar-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--ds-brand, #294557);
  transition: width .3s ease;
}

@media (prefers-reduced-motion: reduce) {
  .ps-onboarding__bar-fill { transition: none; }
}

.ps-onboarding__note { font-size: .8125rem; color: var(--ds-text-muted, #525252); margin: .625rem 0 0; }

.ps-onboarding__rows { list-style: none; margin: 0; padding: 0; border-top: 1px solid var(--ds-border, #e5e7eb); }

.ps-onboarding__row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .25rem .875rem;
  align-items: start;
  padding: 1rem 0;
  border-bottom: 1px solid var(--ds-border, #e5e7eb);
}

@media (min-width: 40rem) {
  .ps-onboarding__row { grid-template-columns: auto 1fr auto; align-items: center; }
}

.ps-onboarding__check {
  width: 1.5rem;
  height: 1.5rem;
  margin: .125rem 0 0;
  flex: none;
  accent-color: var(--ds-brand, #294557);
}

.ps-onboarding__body { min-width: 0; }

.ps-onboarding__label {
  display: inline-block;
  font-weight: 600;
  color: var(--ds-text-primary, #232323);
  /* 44px target without inflating the row: padding sits inside the grid cell */
  padding-block: .625rem;
  margin-block: -.625rem;
  cursor: pointer;
}

/* Strike-through is presentational only — the checkbox carries the real state */
.ps-onboarding__row.is-done .ps-onboarding__label {
  text-decoration: line-through;
  color: var(--ds-text-muted, #525252);
}

.ps-onboarding__text { font-size: .9375rem; line-height: 1.55; color: var(--ds-text-secondary, #475569); margin: .125rem 0 0; }

.ps-onboarding__link {
  grid-column: 2;
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  min-height: 2.75rem;
  font-size: .9375rem;
  font-weight: 600;
  white-space: nowrap;
  color: var(--ds-link, #294557);
}

@media (min-width: 40rem) {
  .ps-onboarding__link { grid-column: 3; }
}

/* Hero — media-on-top band (hero90) and the editorial band under (hero143) */
/* hero90: the band IS the section's top edge, so the section's own top padding
   would render as a gap between the page chrome and the photo. Drop it, and
   put the spacing where it belongs — under the image, before the copy. The
   author's chosen spacing still governs the bottom of the section. */
.ps-hero--media-top { padding-block-start: 0; }

.ps-hero--media-top .ps-hero__band {
  margin-block-end: clamp(1.75rem, 4vw, 2.75rem);
}

.ps-hero__band { width: 100%; overflow: hidden; }
.ps-hero__band img { display: block; width: 100%; height: clamp(18rem, 45vh, 32rem); object-fit: cover; }
.ps-hero__band--under img { height: clamp(18rem, 40vw, 28rem); }

/* hero143: mirror of the media-top case. Here the band is the section's BOTTOM
   edge, so the section's bottom padding would show as a gap under the photo,
   and the copy would otherwise sit flush on top of it. */
.ps-hero--editorial { padding-block-end: 0; }

.ps-hero--editorial .ps-hero__band--under {
  margin-block-start: clamp(1.75rem, 4vw, 2.75rem);
}

/* hero143: display heading left, copy + CTA right, aligned on their baselines */
.ps-hero--editorial .ps-hero__inner { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }

@media (min-width: 48rem) {
  .ps-hero--editorial .ps-hero__inner { grid-template-columns: 1fr 1fr; align-items: end; }
}

.ps-hero--editorial .ps-title { font-weight: 700; letter-spacing: -.02em; }

/* hero120: image inside the measure with a monospace caption */
.ps-hero__figure { margin-top: clamp(1.5rem, 4vw, 2.5rem); }

.ps-figure__caption {
  margin: .625rem 0 0;
  font-family: var(--ds-font-mono, 'JetBrains Mono', monospace);
  font-size: .8125rem;
  color: var(--ds-text-muted, #525252);
}

.ps-title__accent { font-weight: inherit; color: var(--ds-text-muted, #525252); }

/* hero84: trust row with ticks rather than dot separators */
.ps-meta--checks { gap: .5rem 1.25rem; }
.ps-meta--checks li::before { content: none; }
.ps-meta__tick { color: var(--ds-success-text, #065f46); margin-right: .375rem; }

/* stats59: tall image beside the stat grid */
.ps-stats__split { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }

@media (min-width: 52rem) {
  .ps-stats__split { grid-template-columns: minmax(0, 22rem) 1fr; align-items: start; }
}

.ps-stats__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); gap: clamp(1.25rem, 3vw, 2rem); margin: 0; }
.ps-stats__cell { display: flex; flex-direction: column; gap: .25rem; }
.ps-stats__cell .ps-stats__value { margin: 0; }
.ps-stats__cell .ps-stats__label { font-size: .9375rem; color: var(--ds-text-secondary, #475569); }

/* ─────────────────────────────────────────────────────────────
   Section — About / figure strip (about39)
   Display line and paragraph share a bottom baseline; the image
   strip shares a bottom edge with a taller centre frame.
   ───────────────────────────────────────────────────────────── */

.ps-about__head { display: grid; gap: clamp(1rem, 3vw, 2rem); }

@media (min-width: 48rem) {
  /* items-end is the whole point: the paragraph meets the bottom of the
     display line rather than starting level with its top. */
  .ps-about__head { grid-template-columns: 1fr 1fr; align-items: end; }
}

.ps-about__display {
  /* about39 sets this as light 80px display type. style-lean §03 is the
     standard here, and it allows tuning a *hero H1* only — so the display
     treatment is scoped to h1 below and every other level keeps the brand
     scale. Nothing here overrides size or weight. */
  margin: .25rem 0 0;
  text-wrap: balance;
}

/* Hero-level display sizing, matching the brand H1 range exactly */
h1.ps-about__display {
  font-size: clamp(1.75rem, 4vw, 2.25rem);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.02em;
}

.ps-about__display .ps-title__accent { color: var(--ds-brand, #294557); font-weight: inherit; }

.ps-about__text { color: var(--ds-text-secondary, #475569); }
.ps-about__text > :last-child { margin-bottom: 0; }

.ps-about__strip {
  list-style: none;
  margin: clamp(1.75rem, 5vw, 3rem) 0 0;
  padding: 0;
  display: grid;
  gap: clamp(.75rem, 2vw, 1.25rem);
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .ps-about__strip { grid-template-columns: repeat(var(--ps-frames, 3), 1fr); align-items: end; }
  .ps-about__strip[data-count="1"] { --ps-frames: 1; }
  .ps-about__strip[data-count="2"] { --ps-frames: 2; }
  .ps-about__strip[data-count="3"] { --ps-frames: 3; }
}

.ps-about__frame { margin: 0; overflow: hidden; border-radius: var(--ds-radius-lg, 12px); }

.ps-about__frame img {
  display: block;
  width: 100%;
  height: 100%;
  aspect-ratio: 3 / 4;
  object-fit: cover;
  transition: transform .5s ease;
}

/* The centre frame runs taller, which is what staggers the strip */
.ps-about__frame.is-tall img { aspect-ratio: 3 / 5; }

.ps-about__frame:hover img { transform: scale(1.05); }

@media (prefers-reduced-motion: reduce) {
  .ps-about__frame img { transition: none; }
  .ps-about__frame:hover img { transform: none; }
}

.ps-about__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: clamp(1.25rem, 3vw, 2rem);
}

.ps-about__caption { margin: 0; font-size: .9375rem; color: var(--ds-text-muted, #525252); max-width: 46ch; }

/* ── Foreground on filled panels ──────────────────────────────────────────
   style-lean recolors h1–h6 under [data-theme="dark"] at specificity (0,1,1).
   A single class + element ties that and loses on source order, which left
   near-white headings on the light blue --ds-brand becomes in dark mode —
   1.91:1. Doubling the class takes these to (0,2,1) so they win outright.
   Every filled surface is listed, not just section tones: cards paint brand
   themselves and need the same pair. */
.ps.ps--tone-brand h1, .ps.ps--tone-brand h2, .ps.ps--tone-brand h3,
.ps.ps--tone-brand h4, .ps.ps--tone-brand h5, .ps.ps--tone-brand h6,
.ps.ps--tone-dark h1, .ps.ps--tone-dark h2, .ps.ps--tone-dark h3,
.ps.ps--tone-dark h4, .ps.ps--tone-dark h5, .ps.ps--tone-dark h6,
.ps .ps-cta__panel h1, .ps .ps-cta__panel h2, .ps .ps-cta__panel h3,
.ps .ps-tier--featured h1, .ps .ps-tier--featured h2, .ps .ps-tier--featured h3,
.ps .ps-tier--featured h4, .ps .ps-tier--featured h5, .ps .ps-tier--featured h6,
.ps .ps-bento__tile--tone-brand h1, .ps .ps-bento__tile--tone-brand h2,
.ps .ps-bento__tile--tone-brand h3, .ps .ps-bento__tile--tone-brand h4,
.ps .ps-bento__tile--tone-dark h1, .ps .ps-bento__tile--tone-dark h2,
.ps .ps-bento__tile--tone-dark h3, .ps .ps-bento__tile--tone-dark h4,
.ps .ps-hero--fullbleed h1, .ps .ps-hero--fullbleed h2, .ps .ps-hero--fullbleed h3 {
  color: var(--ps-on-brand);
}

/* Non-heading text on those same surfaces: eyebrows, notes and prose all
   resolve through the tone tokens, so remap the pair on the panel itself. */
.ps .ps-cta__panel,
.ps .ps-tier--featured,
.ps .ps-bento__tile--tone-brand,
.ps .ps-bento__tile--tone-dark {
  --ps-text: var(--ps-on-brand);
  --ps-text-2: var(--ps-on-brand-dim);
  --ps-muted: var(--ps-on-brand-dim);
  --ps-link: var(--ps-on-brand);
  color: var(--ps-on-brand);
}

.ps .ps-cta__panel .ps-eyebrow,
.ps .ps-tier--featured .ps-eyebrow,
.ps .ps-bento__tile--tone-brand .ps-eyebrow,
.ps.ps--tone-brand .ps-eyebrow,
.ps.ps--tone-dark .ps-eyebrow { color: var(--ps-on-brand-dim); }

/* The tier name is a real subheading, so it takes the brand H3 (18px/600)
   rather than the 11px eyebrow treatment it used to borrow. style-lean §03:
   H2–H6 stay consistent everywhere. */
.ps-tier__name {
  margin: 0 0 .25rem;
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.4;
  letter-spacing: -.01em;
  text-transform: none;
  color: inherit;
}

/* section-signup is retired from the picker but still renders for any content
   that already uses it — its controls need Inter too. */
.ps-signup__form input,
.ps-signup__form button,
.ps-field__input { font-family: inherit; }

/* style-lean's .badge has no brand-panel context, so invert it there. Additive
   only — the pill itself stays style-lean's component. */
.ps--tone-brand .badge--primary,
.ps--tone-dark .badge--primary,
.ps-hero--fullbleed .badge--primary {
  background: rgba(255, 255, 255, .14);
  border-color: rgba(255, 255, 255, .28);
  color: var(--ps-on-brand);
}

.ps-badge-row { gap: .5rem; align-self: flex-start; margin: 0; }

/* ── Classes the markup emitted with no rules behind them ────────────────────
   Found by diffing the classes the snippets output against the ones this file
   styles. Each of these was rendering as an unstyled default. */

/* about39: the paragraph sitting on the display line's baseline */
.ps-about__lead {
  margin: 0;
  color: var(--ps-text-secondary);
  text-wrap: pretty;
}

/* Comparison table's empty top-left header cell */
.ps-compare__corner {
  background: transparent;
  border: 0;
}

/* Consent rows put the box beside the label rather than above it */
.ps-form__choice--consent {
  display: flex;
  align-items: flex-start;
  gap: .625rem;
}

.ps-form__choice--consent input { margin-block-start: .0625rem; flex: none; }

/* Split-variant copy column */
.ps-form__copy {
  display: flex;
  flex-direction: column;
  gap: .75rem;
}

/* The anti-spam answer is a 1–2 digit sum, so it does not need a full-width
   input. Previously this borrowed .ps-form__field--narrow, a wrapper-grid
   modifier that never had rules and does not belong on an <input>. */
.ps-form__answer { max-width: 7rem; }

/* stats59: the tall image beside the figure grid */
.ps-stats__media {
  border-radius: var(--ds-radius-lg, 12px);
  overflow: hidden;
}

/* ── Events ─────────────────────────────────────────────────────────────────
   A date column beside the detail. Past events are dimmed, but only to a grade
   that still passes AA — status is carried by the "Upcoming"/"Past" headings,
   never by the tint alone. */
.ps-entries__group { margin: 2rem 0 .75rem; font-size: 1.125rem; font-weight: 600; }
.ps-entries__group:first-of-type { margin-top: 0; }
.ps-entries__empty { margin: 0 0 1rem; color: var(--ps-muted); }
.ps-entries__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.ps-entries__item {
  display: grid;
  grid-template-columns: 1fr;
  gap: .25rem 1.5rem;
  padding: 1rem 0;
  border-block-start: 1px solid var(--ps-border);
}
.ps-entries__item:last-child { border-block-end: 1px solid var(--ps-border); }
.ps-entries__when { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem; }
.ps-entries__date { font-family: var(--ps-mono); font-size: .8125rem; color: var(--ps-muted); white-space: nowrap; }
.ps-entries__date--none { font-style: italic; }
.ps-entries__name { margin: 0; font-size: 1.125rem; font-weight: 600; line-height: 1.4; }
.ps-entries__talk { margin: .15rem 0 0; color: var(--ps-text); }
.ps-entries__meta { margin: .35rem 0 0; font-size: .875rem; color: var(--ps-muted); display: flex; flex-wrap: wrap; gap: .35rem; }
.ps-entries__note { margin-block-start: .5rem; font-size: .9375rem; }
.ps-entries__links { margin: .5rem 0 0; display: flex; flex-wrap: wrap; gap: 1rem; font-size: .875rem; }
.ps-entries__role { font-weight: 600; color: var(--ps-text); }

@media (min-width: 40rem) {
  .ps-entries--timeline .ps-entries__item { grid-template-columns: minmax(0, 10rem) 1fr; }
}

/* Cards: same content, laid out as a grid rather than a list of rows */
@media (min-width: 48rem) {
  .ps-entries--cards .ps-entries__list { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
  .ps-entries--cards .ps-entries__item {
    border: 1px solid var(--ps-border);
    border-radius: var(--ps-radius);
    padding: 1.25rem;
  }
  .ps-entries--cards .ps-entries__item:last-child { border-block-end: 1px solid var(--ps-border); }
}

/* Recurring entries and times sit in the same column as the date. */
.ps-entries__repeat { font-family: var(--ps-mono); font-size: .8125rem; color: var(--ps-text); font-weight: 600; }
.ps-entries__time { font-family: var(--ps-mono); font-size: .8125rem; color: var(--ps-muted); white-space: nowrap; }

/* ── Events: icon rail ──────────────────────────────────────────────────────
   A fixed leading column so the markers line up regardless of what is in them,
   and so nothing event-specific is assumed — the same rail lists releases or
   milestones with a different icon. */
.ps-entries--rail .ps-entries__item { grid-template-columns: 2rem 1fr; }
.ps-entries__marker { display: flex; align-items: flex-start; justify-content: center; padding-block-start: .1rem; }
.ps-entries__marker-dot {
  width: .5rem; height: .5rem; border-radius: 50%;
  background: var(--ps-border-strong, var(--ps-border)); margin-block-start: .45rem;
}
.ps-icon--rail { font-size: 1.125rem; color: var(--ps-brand); }
.ps-entries__badge {
  display: inline-flex; align-items: center; justify-content: center;
  padding: .1rem .4rem; border-radius: var(--ps-radius-sm, .25rem);
  background: var(--ps-raised); border: 1px solid var(--ps-border);
  font-family: var(--ps-mono); font-size: .625rem; font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; white-space: nowrap;
}

@media (min-width: 40rem) {
  .ps-entries--rail .ps-entries__item { grid-template-columns: 2rem minmax(0, 8rem) 1fr; }
}

/* ── Events: grouped ────────────────────────────────────────────────────────
   The dates are what differ between otherwise identical entries, so they get
   their own row rather than repeating the whole entry per date. */
.ps-entries__dates { margin: .5rem 0 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .5rem; font-size: .875rem; }
.ps-entries__dates-label { color: var(--ps-muted); }
.ps-entries__chip {
  font-family: var(--ps-mono); font-size: .8125rem;
  padding: .1rem .45rem; border-radius: var(--ps-radius-sm, .25rem);
  background: var(--ps-raised); border: 1px solid var(--ps-border); white-space: nowrap;
}

/* ── Events: table ──────────────────────────────────────────────────────────
   Scrolls inside its own container so a long row never makes the page scroll
   sideways. */
.ps-entries__table { width: 100%; border-collapse: collapse; font-size: .9375rem; display: block; overflow-x: auto; }
.ps-entries__caption { text-align: start; font-weight: 600; padding-block-end: .5rem; }
.ps-entries__table th,
.ps-entries__table td { text-align: start; padding: .6rem .75rem; border-block-end: 1px solid var(--ps-border); vertical-align: top; }
.ps-entries__table thead th {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .05em;
  color: var(--ps-muted); font-weight: 700; white-space: nowrap;
}
.ps-entries__table tbody th { font-weight: 600; }
.ps-entries__talk-inline { display: block; font-weight: 400; color: var(--ps-muted); font-size: .875rem; }

/* The editorial hero's second column. On a narrow screen it follows the
   heading normally; from the breakpoint up it sits beside it, baselines
   aligned, which is what hero143 is. */
.ps-hero--editorial .ps-hero__offset { display: flex; flex-direction: column; gap: 1rem; }
.ps-hero--editorial .ps-hero__offset .ps-lead { margin: 0; }

/* Rail links carry a 24px hit area (WCAG 2.2 SC 2.5.8). They sit in a nav list
   or a definition list, not in a sentence, so the inline exception does not
   apply — they were 17px tall. The padding is vertical only, so the rail's
   width is unchanged. */
.ps-rail__nav a,
.ps-rail__nav span,
.ps-rail__meta dd a {
  display: block;
  min-height: 24px;
  padding-block: .3125rem;
  line-height: 1.4;
}
.ps-rail__nav li + li { margin-block-start: .125rem; }

/* ── 23. Sessions (entries) ───────────────────────────────────────────────── */
/* social52: linked hairline rows with a card that sticks beside them. */

.ps-sessions {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  margin-block-start: 2rem;
}

@media (min-width: 60rem) {
  .ps-sessions { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); }
  .ps-sessions--nocard { grid-template-columns: minmax(0, 1fr); }
}

.ps-sessions__list { list-style: none; margin: 0; padding: 0; }

/* The rule runs between rows and above the first, and stops — the list closes
   on whitespace rather than on a line, which is what keeps it from reading as a
   table. */
.ps-sessions__row { border-block-start: 1px solid var(--ps-border); }
.ps-sessions__row:last-child { border-block-end: 1px solid var(--ps-border); }

.ps-sessions__link,
.ps-sessions__row > .ps-sessions__body {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  padding-block: 1rem;
  text-decoration: none;
  color: inherit;
}

.ps-sessions__link { padding-inline: .25rem; }
.ps-sessions__link:hover { background: var(--ps-raised); }
.ps-sessions__link:focus-visible {
  outline: 3px solid var(--ps-focus);
  outline-offset: -3px;
}

/* Fixed tile with tabular numerals so a 1 and a 9 occupy the same width and the
   column of dates stays straight. */
.ps-sessions__date {
  flex: none;
  width: 3.5rem;
  display: grid;
  justify-items: center;
  gap: .125rem;
  padding-block: .375rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ds-radius, 8px);
  font-variant-numeric: tabular-nums;
}

.ps-sessions__month {
  font-size: .6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ps-muted);
}

.ps-sessions__day { font-size: 1.25rem; font-weight: 700; line-height: 1; }

.ps-sessions__body { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.ps-sessions__name { margin: 0; font-size: 1rem; font-weight: 600; }
.ps-sessions__note { color: var(--ps-text-2); font-size: .9375rem; }
.ps-sessions__meta { color: var(--ps-muted); font-size: .875rem; }

.ps-sessions__card {
  border: 1px solid var(--ps-border);
  border-radius: var(--ds-radius-lg, 12px);
  padding: clamp(1rem, 2.5vw, 1.5rem);
  background: var(--ps-raised);
  align-self: start;
}

@media (min-width: 60rem) {
  /* Sticky only where there is room for it to matter. */
  .ps-sessions__card { position: sticky; top: 6rem; }
}

.ps-sessions__card-title {
  margin: 0 0 .75rem;
  font-size: .75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ps-muted);
}

.ps-sessions__person { display: flex; align-items: center; gap: .75rem; }
.ps-sessions__avatar { width: 3rem; flex: none; border-radius: 50%; overflow: hidden; }
.ps-sessions__byline { display: flex; flex-direction: column; }
.ps-sessions__person-name { font-weight: 600; }
.ps-sessions__person-role { font-size: .875rem; color: var(--ps-muted); }

.ps-sessions__status { margin: .75rem 0 0; font-size: .875rem; color: var(--ps-text-2); }
.ps-sessions__card-text { margin: .75rem 0 0; font-size: .9375rem; }

.ps-sessions__rows { margin: 1rem 0 0; }
.ps-sessions__card-row {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding-block: .5rem;
  border-block-start: 1px solid var(--ps-border);
  font-size: .875rem;
}
.ps-sessions__card-row dt { color: var(--ps-muted); }
.ps-sessions__card-row dd { margin: 0; font-weight: 600; text-align: right; }

/* ── 24. Hero — indexed rows ──────────────────────────────────────────────── */

.ps-hero__indexed { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }

@media (min-width: 60rem) {
  .ps-hero__indexed { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
}

/* The author-typed index is the visible marker, so the list's own numbering is
   suppressed — two competing numbers would be worse than none. */
.ps-hero__rows { list-style: none; margin: 0; padding: 0; }

.ps-hero__row {
  display: flex;
  gap: 1rem;
  padding-block: 1rem;
  border-block-start: 1px solid var(--ps-border);
}
.ps-hero__row:last-child { border-block-end: 1px solid var(--ps-border); }

.ps-hero__index {
  flex: none;
  min-width: 2rem;
  font-variant-numeric: tabular-nums;
  font-size: .8125rem;
  font-weight: 700;
  color: var(--ps-muted);
  padding-block-start: .125rem;
}

.ps-hero__row-body { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.ps-hero__row-title { margin: 0; font-size: 1rem; font-weight: 600; }
.ps-hero__row-text { font-size: .9375rem; color: var(--ps-text-2); }

.ps-hero__band { margin-block-start: clamp(2rem, 5vw, 3.5rem); }
.ps-hero__band-caption {
  margin: .5rem 0 0;
  padding-inline: clamp(1rem, 4vw, 2rem);
  font-size: .8125rem;
  color: var(--ps-muted);
}

/* ── 25. FAQ ledger ───────────────────────────────────────────────────────── */

.ps-faq__ledger { display: grid; gap: 2rem; margin-block-start: 1.5rem; }
.ps-faq__dl { margin: 0; }

.ps-faq__pair {
  display: grid;
  gap: .25rem;
  padding-block: .875rem;
  border-block-start: 1px solid var(--ps-border);
}

/* The answer gets the wider track: it is the part people came to read. */
@media (min-width: 48rem) {
  .ps-faq__pair { grid-template-columns: 1fr 1.6fr; gap: 1.5rem; align-items: baseline; }
}

/* Each set closes with its own rule, so the groups read as separate ledgers
   rather than one unbroken run. */
.ps-faq__set .ps-faq__pair:last-child { border-block-end: 1px solid var(--ps-border); }

.ps-faq__term { font-weight: 600; }
.ps-faq__def { margin: 0; color: var(--ps-text-2); }
.ps-faq__footer { margin-block-start: 1.5rem; color: var(--ps-muted); font-size: .9375rem; }

/* ── 26. Letter ───────────────────────────────────────────────────────────── */

.ps-letter__inner { display: grid; gap: clamp(1.5rem, 4vw, 3rem); }

@media (min-width: 60rem) {
  .ps-letter__inner { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); }
  /* Offset so the photographs start level with the letter, not the eyebrow. */
  .ps-letter__aside { padding-block-start: 5rem; }
}

/* The track is wide; the measure is not. This cap is the layout. */
.ps-letter__body,
.ps-letter__quote,
.ps-letter__signatories { max-width: 40rem; }

.ps-letter__quote {
  margin: 1.5rem 0;
  padding-inline-start: 1.25rem;
  border-inline-start: 2px solid var(--ps-brand);
  font-size: 1.125rem;
  line-height: 1.5;
}
.ps-letter__quote p { margin: 0; }

.ps-letter__signatories {
  list-style: none;
  margin: 2rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  border-block-start: 1px solid var(--ps-border);
  padding-block-start: 1.5rem;
}
.ps-letter__signatory { display: flex; align-items: center; gap: .75rem; }
.ps-letter__avatar { width: 2.75rem; flex: none; border-radius: 50%; overflow: hidden; }
.ps-letter__byline { display: flex; flex-direction: column; }
.ps-letter__name { font-weight: 600; }
.ps-letter__role { font-size: .875rem; color: var(--ps-muted); }

.ps-letter__aside { display: grid; gap: 1.5rem; align-content: start; }
.ps-letter__portrait { margin: 0; }
.ps-letter__caption { margin: .5rem 0 0; font-size: .8125rem; color: var(--ps-muted); }

/* ── 27. Status notice ────────────────────────────────────────────────────── */

.ps-notice__inner { display: grid; gap: clamp(1.5rem, 4vw, 3rem); align-items: start; }

@media (min-width: 60rem) {
  .ps-notice__inner { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); }
}

.ps-notice__details { margin: 1.5rem 0; }

.ps-notice__row {
  display: grid;
  gap: .25rem;
  padding-block: .75rem;
  border-block-start: 1px solid var(--ps-border);
}
.ps-notice__row:last-child { border-block-end: 1px solid var(--ps-border); }

@media (min-width: 34rem) {
  .ps-notice__row { grid-template-columns: 12rem 1fr; gap: 1.5rem; }
}

.ps-notice__label { font-weight: 600; }
.ps-notice__value { margin: 0; color: var(--ps-text-2); }
.ps-notice__note { margin-block-start: 1rem; font-size: .875rem; color: var(--ps-muted); }

.ps-notice__media { position: relative; }

.ps-notice__stat {
  position: absolute;
  inset-block-end: 1rem;
  inset-inline-start: 1rem;
  margin: 0;
  display: flex;
  flex-direction: column;
  padding: .75rem 1rem;
  border-radius: var(--ds-radius, 8px);
  background: var(--ps-surface);
  border: 1px solid var(--ps-border);
  box-shadow: 0 2px 12px rgb(0 0 0 / .08);
}

/* With no image there is nothing to float over, so it becomes a plain tile. */
.ps-notice__media--bare .ps-notice__stat { position: static; display: inline-flex; }

.ps-notice__stat-value { font-size: 1.5rem; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; }
.ps-notice__stat-label { margin-block-start: .25rem; font-size: .75rem; color: var(--ps-muted); }

/* ── 28. Data flow map ────────────────────────────────────────────────────── */

.ps-dataflow__subhead { margin: 2rem 0 1rem; font-size: 1rem; }

.ps-dataflow__nodes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
}

.ps-dataflow__node {
  padding: 1rem;
  border-radius: var(--ds-radius, 8px);
  background: var(--ps-raised);
}

/* Surface tells the two apart at a glance; the wording inside carries it for
   everyone else, so this is never the only signal — SC 1.4.1. */
.ps-dataflow__node--external { background: var(--ps-sunken); }

.ps-dataflow__node-name { margin: 0; font-weight: 600; }
.ps-dataflow__node-detail { margin: .25rem 0 0; font-size: .875rem; color: var(--ps-text-2); }
.ps-dataflow__node-who {
  margin: .5rem 0 0;
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ps-muted);
}

.ps-dataflow__scroll { overflow-x: auto; }
.ps-dataflow__scroll:focus-visible { outline: 3px solid var(--ps-focus); outline-offset: 2px; }

.ps-dataflow__table { width: 100%; border-collapse: collapse; font-size: .9375rem; }
.ps-dataflow__table th,
.ps-dataflow__table td {
  text-align: start;
  padding: .75rem 1rem .75rem 0;
  border-block-end: 1px solid var(--ps-border);
  vertical-align: top;
}
.ps-dataflow__table thead th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ps-muted);
}
.ps-dataflow__table tbody th { font-weight: 600; }
.ps-dataflow__note { margin-block-start: 1.5rem; color: var(--ps-text-2); }

/* ── 29. Plain-words terms ────────────────────────────────────────────────── */

.ps-terms__scroll { overflow-x: auto; margin-block-start: 1.5rem; }
.ps-terms__scroll:focus-visible { outline: 3px solid var(--ps-focus); outline-offset: 2px; }

.ps-terms__table { width: 100%; border-collapse: collapse; }

/* The caption names the table for a screen reader; it is not a second heading,
   so it is not repeated visually. */
.ps-terms__caption {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.ps-terms__table th,
.ps-terms__table td {
  text-align: start;
  padding: 1rem 1.5rem 1rem 0;
  border-block-end: 1px solid var(--ps-border);
  vertical-align: top;
}

.ps-terms__table thead th {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ps-muted);
}

.ps-terms__ref {
  width: 4rem;
  font-variant-numeric: tabular-nums;
  font-size: .875rem;
  color: var(--ps-muted);
  font-weight: 600;
}

/* The translation is what people are here for, so it carries the emphasis and
   the legal wording is the muted column. Deliberately the opposite of how a
   contract is usually set. */
.ps-terms__clause { color: var(--ps-muted); font-size: .9375rem; }
.ps-terms__plain { color: var(--ps-text); }
.ps-terms__disclaimer { margin-block-start: 1.5rem; font-size: .875rem; color: var(--ps-muted); }

/* ── 30. Form cards (legal56) ─────────────────────────────────────────────── */
/* A matrix in the copy column beside the form. Separated by the gap showing a
   darker container through, rather than by borders — the reference's trick, and
   it keeps the cells from stacking double rules where they meet. */

.ps-form__cards {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 1px;
  display: grid;
  gap: 1px;
  background: var(--ps-border);
  border-radius: var(--ds-radius-lg, 12px);
  overflow: hidden;
}

@media (min-width: 30rem) {
  .ps-form__cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  /* An odd card count left an empty cell in the last row — and because the border
     here is the CONTAINER's background showing through a 1px gap, an empty cell is
     not blank space, it is a solid grey block the size of a card. With one card it
     filled half the panel and read as an image that had failed to load.

     :last-child:nth-child(odd) is the whole fix: it matches the final card only when
     the count is odd, which is precisely when a cell would be left over. One card
     spans, two do not, three span the last. */
  .ps-form__card:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

.ps-form__card {
  display: flex;
  flex-direction: column;
  gap: .375rem;
  padding: 1rem;
  background: var(--ps-surface);
}

/* align-self is the fix, not the font size. .ps-icon is an inline-flex box that
   centres its glyph, and .ps-form__card is a column flex with the default
   align-items: stretch — so the icon span stretched to the full card width and its
   glyph sat centred above left-aligned text. It looked deliberate and wrong. */
.ps-form__card-icon {
  align-self: start;
  font-size: 1.25rem;
  color: var(--ps-brand);
}
.ps-form__card-title { margin: 0; font-size: .9375rem; font-weight: 600; }

/* The description takes the slack, so the footnotes line up along the bottom of
   the row however uneven the descriptions are. */
.ps-form__card-text { margin: 0; flex: 1; font-size: .875rem; color: var(--ps-text-2); }

.ps-form__card-meta {
  margin: 0;
  font-size: .75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ps-muted);
}

/* ── 31. Agenda (entries) ─────────────────────────────────────────────────── */

.ps-agenda__filters { display: flex; flex-wrap: wrap; gap: .5rem; margin-block: 1.5rem; }

.ps-agenda__pill {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  /* 44px floor: these are the only controls in the section, and a row of
     small pills is exactly the case WCAG 2.5.8 exists for. */
  min-height: 2.75rem;
  padding: .5rem .875rem;
  border: 1px solid var(--ps-border);
  border-radius: 999px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: .875rem;
  cursor: pointer;
}

.ps-agenda__pill:hover { background: var(--ps-raised); }
.ps-agenda__pill:focus-visible { outline: 3px solid var(--ps-focus); outline-offset: 2px; }

/* The pressed one is filled AND has a heavier border — never colour alone. */
.ps-agenda__pill[aria-pressed="true"] {
  background: var(--ps-brand);
  border-color: var(--ps-brand);
  color: var(--ps-on-brand);
  font-weight: 600;
}

.ps-agenda__count { font-variant-numeric: tabular-nums; opacity: .75; font-size: .8125rem; }

.ps-agenda__list { list-style: none; margin: 0; padding: 0; }
.ps-agenda__row { border-block-start: 1px solid var(--ps-border); }
.ps-agenda__row:last-child { border-block-end: 1px solid var(--ps-border); }

.ps-agenda__link,
.ps-agenda__row > .ps-agenda__time {
  display: grid;
  gap: .25rem 1.5rem;
  padding-block: 1rem;
  text-decoration: none;
  color: inherit;
}

.ps-agenda__row > * { padding-block: 1rem; }
.ps-agenda__link { padding-inline: .25rem; padding-block: 1rem; }
.ps-agenda__link:hover { background: var(--ps-raised); }
.ps-agenda__link:focus-visible { outline: 3px solid var(--ps-focus); outline-offset: -3px; }

/* Stacked on a narrow screen, three tracks from md — time, detail, who. */
.ps-agenda__row { display: block; }

@media (min-width: 48rem) {
  .ps-agenda__link,
  .ps-agenda__row:not(:has(.ps-agenda__link)) {
    display: grid;
    grid-template-columns: 7rem minmax(0, 1fr) minmax(0, 14rem);
    gap: 1.5rem;
    align-items: start;
  }
  .ps-agenda__who { text-align: end; }
}

.ps-agenda__time {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  display: flex;
  flex-direction: column;
}
.ps-agenda__until { font-weight: 400; font-size: .8125rem; color: var(--ps-muted); }

.ps-agenda__body { display: flex; flex-direction: column; gap: .25rem; min-width: 0; }
.ps-agenda__title { margin: 0; font-size: 1rem; font-weight: 600; }
.ps-agenda__note { font-size: .9375rem; color: var(--ps-text-2); }
.ps-agenda__track { font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ps-muted); }

.ps-agenda__who { display: flex; flex-direction: column; gap: .125rem; font-size: .875rem; }
.ps-agenda__speaker { font-weight: 600; }
.ps-agenda__room { color: var(--ps-muted); }

/* ── 32. Notice — record layout (error33) ─────────────────────────────────── */

.ps-notice--record .ps-notice__inner { grid-template-columns: minmax(0, 1fr); max-width: 48rem; }

.ps-notice--record .ps-notice__details {
  display: grid;
  gap: 0;
  margin-block: 2rem;
}

@media (min-width: 34rem) {
  .ps-notice--record .ps-notice__details { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Each pair sits under its own rule rather than inside a boxed cell, and the
   value is drawn above its label. column-reverse rather than reordering the
   markup: the <dt> stays before its <dd> where it belongs. */
.ps-notice--record .ps-notice__row {
  display: flex;
  flex-direction: column-reverse;
  justify-content: flex-end;
  gap: .25rem;
  padding: 1rem 1rem 1rem 0;
  border-block-start: 1px solid var(--ps-border);
  border-block-end: 0;
}

.ps-notice--record .ps-notice__label {
  font-size: .75rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ps-muted);
}

.ps-notice--record .ps-notice__value {
  font-size: clamp(1.25rem, 3vw, 1.75rem);
  font-weight: 700;
  line-height: 1.2;
  color: var(--ps-text);
}

/* ── 33. Who does what (onboarding40) ─────────────────────────────────────── */

.ps-work__scroll { overflow-x: auto; margin-block-start: 1.5rem; }
.ps-work__scroll:focus-visible { outline: 3px solid var(--ps-focus); outline-offset: 2px; }

.ps-work__table { width: 100%; border-collapse: collapse; }

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

.ps-work__table th,
.ps-work__table td {
  text-align: start;
  /* Inset on BOTH sides, matching the phase band. The first column used to sit at 0
     — flush against the container edge, which reads as a rendering fault rather than
     a deliberate edge. The band and the rows share this value, so they line up; what
     matters is that they agree, not what the number is. */
  padding: .875rem 1rem;
  border-block-end: 1px solid var(--ps-border);
  vertical-align: top;
}

.ps-work__table thead th {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; color: var(--ps-muted);
}

/* The phase banner spans the row on a filled band, so the groups read as
   sections of the table rather than as one long run. */
.ps-work__band th {
  background: var(--ps-sunken);
  font-size: .8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;

  /* The same inline inset as the cells. Previously the band was inset 1rem and the
     cells were flush at 0, so the band text started a centimetre right of the tasks
     it introduces — aligned now because both use the same value, not because either
     was pulled to zero.

     Vertical rhythm is its own thing: a section break gets more room above than
     below, which visually attaches it to the rows it opens rather than the ones it
     closes. */
  padding-inline: 1rem;
  padding-block: 1.125rem .625rem;
}

/* The first band carries the header rule instead, so it does not need the extra
   space above. */
.ps-work__table tbody tr:first-child .ps-work__band-cell,
.ps-work__table tbody .ps-work__band:first-child th { padding-block-start: .75rem; }

.ps-work__task { font-weight: 600; }
.ps-work__task-name { display: block; line-height: 1.35; }

/* .125rem is 2px: the detail sat directly under the name with no separation, so a
   two-line cell read as one wrapped sentence. The name is 600 and the detail 400 at
   .875rem, and that weight change alone was carrying the distinction. */
.ps-work__task-detail {
  display: block;
  margin-block-start: .25rem;
  font-weight: 400;
  font-size: .875rem;
  line-height: 1.45;
  color: var(--ps-text-2);
}
.ps-work__owner { width: 5rem; font-size: 1.125rem; }
.ps-work__effort { width: 8rem; font-size: .875rem; color: var(--ps-muted); font-variant-numeric: tabular-nums; }

.ps-work__total {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 1rem; margin-block-start: 1.5rem;
}
.ps-work__total-text { margin: 0; }
.ps-work__total-value { font-size: 1.125rem; font-weight: 700; }
.ps-work__total-label { color: var(--ps-muted); }

/* ── 34. Roster (onboarding37) ────────────────────────────────────────────── */

.ps-roster__subhead { margin: 2rem 0 .75rem; font-size: 1rem; }

.ps-roster__roles { margin: 0; }
.ps-roster__role {
  display: grid; gap: .25rem; padding-block: .75rem;
  border-block-start: 1px solid var(--ps-border);
}
.ps-roster__role:last-child { border-block-end: 1px solid var(--ps-border); }

@media (min-width: 40rem) {
  .ps-roster__role { grid-template-columns: 10rem minmax(0, 1fr); gap: 1.5rem; }
}
.ps-roster__role dt { font-weight: 600; }
.ps-roster__role dd { margin: 0; color: var(--ps-text-2); }

.ps-roster__people { list-style: none; margin: 0; padding: 0; }
.ps-roster__person {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  padding-block: .75rem; border-block-start: 1px solid var(--ps-border);
  min-height: 3.5rem;
}
.ps-roster__person:last-child { border-block-end: 1px solid var(--ps-border); }

.ps-roster__avatar { width: 2.5rem; flex: none; border-radius: 50%; overflow: hidden; }

/* Stands in for a portrait. aria-hidden in the markup — an initial read aloud
   before the name it came from is noise. */
.ps-roster__initial {
  width: 2.5rem; height: 2.5rem; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--ps-sunken);
  font-weight: 700;
}

.ps-roster__who { display: flex; flex-direction: column; margin-inline-end: auto; }
.ps-roster__name { font-weight: 600; }
.ps-roster__detail { font-size: .875rem; color: var(--ps-muted); }

.ps-roster__meta { display: flex; align-items: center; gap: .75rem; font-size: .875rem; }
.ps-roster__role-name { color: var(--ps-text-2); }
.ps-roster__status {
  padding: .125rem .5rem;
  border: 1px solid var(--ps-border);
  border-radius: 999px;
  font-size: .75rem;
  color: var(--ps-muted);
}

.ps-roster__meter { margin-block-start: 2rem; max-width: 26rem; }
.ps-roster__meter-head {
  display: flex; justify-content: space-between; gap: 1rem; margin: 0 0 .375rem;
  font-size: .875rem; font-weight: 600;
}
.ps-roster__meter-value { font-variant-numeric: tabular-nums; color: var(--ps-muted); }
.ps-roster__meter-bar { width: 100%; height: .5rem; }
.ps-roster__note { margin-block-start: .75rem; font-size: .875rem; color: var(--ps-muted); }

/* The block currently being edited, marked briefly when the Panel scrolls the
   preview to it. The attribute is set by the PARENT, not by any script in the
   frame — the preview frame is sandboxed without allow-scripts — so this rule has
   to live in the frontend sheet the frame loads, even though nothing inside the
   frame ever sets it. Outline rather than a background, so it cannot be mistaken
   for the section's own styling. */
.ps[data-ps-focused] {
  outline: 3px solid var(--ps-focus);
  outline-offset: -3px;
}

@media (prefers-reduced-motion: no-preference) {
  .ps[data-ps-focused] { transition: outline-color .25s ease; }
}

/* Which step an error is on. Dimmed and smaller than the message itself: it is
   orientation, not the error. */
.ps-form__errstep {
  font-weight: 400;
  font-size: .875em;
  opacity: .8;
}

/* ── Onboarding: status board (feature22) ────────────────────────────────────
   The checklist is a summary column beside rows to tick. This inverts that: the
   steps are the content and get the wide column, and the progress is a panel
   beside them. Its own partial, so none of this has to undo the checklist. */

.ps-onboarding--board .ps-onboarding__inner {
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 60rem) {
  .ps-onboarding--board .ps-onboarding__inner {
    /* Steps first and wider. The panel is a fixed measure rather than a fraction
       so the figures stay on one line whatever the container does. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 19rem);
    align-items: start;
  }

  .ps-onboarding--board .ps-onboarding__panel {
    position: sticky;
    top: 2rem;
  }
}

/* ── the steps ── */

.ps-onboarding__steps {
  list-style: none;
  margin: 1.5rem 0 0;
  padding: 0;
  /* The gap IS the separator: a border on each row plus a gap reads as a table,
     which these are not. */
  display: flex;
  flex-direction: column;
  gap: .25rem;
}

.ps-onboarding__step {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ds-radius-lg, 12px);
  background: var(--ps-surface);
}

/* A done step recedes. The word in its pill is what states it; this is the second
   cue, not the only one. */
.ps-onboarding__step--done { background: var(--ps-raised); }

.ps-onboarding__step-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: var(--ds-radius, 8px);
  background: var(--ps-sunken);
  font-size: 1.25rem;
}

.ps-onboarding__step--done .ps-onboarding__step-icon {
  background: var(--ps-surface);
}

.ps-onboarding__step-body { min-width: 0; }

/* Title, state and ETA on one line, wrapping as a group rather than stretching
   the row. */
.ps-onboarding__step-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem;
  margin: 0;
}

.ps-onboarding__step-title {
  font-size: 1.0625rem;
  font-weight: 600;
  /* Not the whole line: the state pill sits beside it on wide rows. */
  margin-inline-end: .25rem;
}

.ps-onboarding__step-text {
  margin: .35rem 0 0;
  font-size: .9375rem;
  line-height: 1.55;
  color: var(--ps-text-2);
}

/* ── the panel ── */

.ps-onboarding__panel {
  padding: 1.25rem;
  border: 1px solid var(--ps-border);
  border-radius: var(--ds-radius-lg, 12px);
  background: var(--ps-raised);
}

.ps-onboarding__panel-label {
  margin: 0;
  font-size: .8125rem;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--ps-muted);
}

.ps-onboarding__count {
  margin: .5rem 0 0;
  font-size: .9375rem;
  color: var(--ps-text-2);
}

.ps-onboarding--board .ps-onboarding__figure { margin: .25rem 0 .5rem; }

/* ── figures ── */

.ps-onboarding__stats {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  margin: 1.25rem 0 0;
  padding-block-start: 1rem;
  border-block-start: 1px solid var(--ps-border);
}

.ps-onboarding__stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.ps-onboarding__stat dt {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  font-size: .875rem;
  font-weight: 600;
}

.ps-onboarding__stat-note {
  font-weight: 400;
  font-size: .8125rem;
  color: var(--ps-muted);
}

.ps-onboarding__stat dd { margin: 0; white-space: nowrap; }

/* ── the state, as a word ── */
/* Colour is layered on top of the text, never instead of it — WCAG 1.4.1. */

.ps-onboarding__meta,
.ps-onboarding__step-head .ps-onboarding__state,
.ps-onboarding__step-head .ps-onboarding__eta { font-size: .8125rem; }

.ps-onboarding__state {
  display: inline-block;
  padding: .1rem .45rem;
  border: 1px solid var(--ps-border-strong);
  border-radius: 999px;
  font-weight: 600;
  white-space: nowrap;
}

.ps-onboarding__state[data-state="done"] {
  border-color: var(--ps-success-text, #047857);
  color: var(--ps-success-text, #047857);
}

.ps-onboarding__state[data-state="doing"] {
  border-color: var(--ps-warning-text, #a16207);
  color: var(--ps-warning-text, #a16207);
}

.ps-onboarding__eta { color: var(--ps-muted); }

.ps-onboarding__actions { margin-block-start: 1.25rem; }

/* ── Client progress ────────────────────────────────────────────────────────
   The figure is text and the bar is decoration, so nothing here carries a role
   and there is no aria value that could drift from the sentence above it. */

.ps-progress__figure {
  font-size: clamp(1.25rem, 3vw, 1.75rem);
  font-weight: 700;
  margin: 0 0 .75rem;
  color: var(--ps-text);
}

.ps-progress__percent {
  color: var(--ps-muted);
  font-weight: 600;
  /* Smaller than the count it follows: the "12 of 30" is the fact, the percentage
     is a convenience. */
  font-size: .75em;
  margin-inline-start: .35rem;
}

.ps-progress__track {
  height: .75rem;
  border-radius: 999px;
  background: var(--ps-sunken);
  border: 1px solid var(--ps-border);
  overflow: hidden;
}

.ps-progress__fill {
  height: 100%;
  background: var(--ps-brand);
  /* No transition: the value arrives once per render, and animating it would
     imply live movement that a daily figure does not have. */
}

/* A filled track and an empty one must differ by more than colour — SC 1.4.1.
   The border does that at 0% and the fill's own edge does at anything above. */
.ps-progress__fill:empty { display: block; }

.ps-progress__counts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.ps-progress__counts li {
  display: flex;
  flex-direction: column;
  font-size: .875rem;
  color: var(--ps-muted);
}

.ps-progress__counts strong {
  font-size: clamp(1.5rem, 4vw, 2.25rem);
  font-weight: 700;
  color: var(--ps-text);
  font-variant-numeric: tabular-nums;
}

.ps-progress__boards {
  list-style: none;
  margin: 1.25rem 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.ps-progress__board {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: .5rem;
  padding: .625rem 0;
  border-block-start: 1px solid var(--ps-border);
  font-size: .9375rem;
}

.ps-progress__board:last-child { border-block-end: 1px solid var(--ps-border); }
.ps-progress__board-name { font-weight: 600; color: var(--ps-text); }
.ps-progress__board-count { color: var(--ps-muted); font-variant-numeric: tabular-nums; }

/* Caveats are the point of this section rather than an afterthought: an
   understated figure is the kind that prompts an awkward call. */
.ps-progress__caveat {
  margin: .75rem 0 0;
  padding: .625rem .75rem;
  border-inline-start: 3px solid var(--ds-warning, #d97706);
  background: var(--ps-raised);
  font-size: .875rem;
  color: var(--ps-text);
}

.ps-progress__empty {
  margin: 0;
  color: var(--ps-muted);
  font-size: .9375rem;
}

.ps-progress__note { margin-block-start: 1rem; }

.ps-progress__asat {
  margin: 1rem 0 0;
  font-size: .8125rem;
  color: var(--ps-muted);
}

/* Who the outstanding work is waiting on. The figure a client acts on, so it is
   given more weight than the percentage above it. */
.ps-progress__sides {
  display: flex;
  flex-wrap: wrap;
  gap: 1.25rem;
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
}

.ps-progress__side {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  font-size: .9375rem;
  color: var(--ps-muted);
}

.ps-progress__side strong {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--ps-text);
  font-variant-numeric: tabular-nums;
}

/* "waiting on you" carries a marker, because it is the one the reader has to act
   on. A left border rather than colour alone — SC 1.4.1 — since a colour-only
   distinction between the two sides would be exactly the wrong thing to ship in
   this plugin. */
.ps-progress__side--them {
  padding-inline-start: .625rem;
  border-inline-start: 3px solid var(--ds-warning, #d97706);
}

/* The outstanding items themselves. A heading per side rather than one merged
   list — "waiting on you" is a call to action, "with us" is reassurance, and
   merging them makes the reader work out which is which. */
.ps-progress__itemhead {
  margin: 1.25rem 0 .35rem;
  font-size: .8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ps-muted);
}

.ps-progress__items {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

.ps-progress__item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
  padding: .5rem 0;
  border-block-start: 1px solid var(--ps-border);
  font-size: .9375rem;
}

.ps-progress__item:last-child { border-block-end: 1px solid var(--ps-border); }
.ps-progress__item-title { color: var(--ps-text); }

/* Tabular figures so a column of dates lines up. */
.ps-progress__item-due {
  color: var(--ps-muted);
  font-size: .8125rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The phase note — timing or a sentence of context, beside the phase heading. Not
   uppercased with the band label: it is prose, and small caps make dates harder to
   read, not easier. */
.ps-work__band-note {
  margin-inline-start: .625rem;
  font-weight: 400;
  font-size: .8125rem;
  text-transform: none;
  letter-spacing: 0;
  color: var(--ps-muted);
}

/* A task that links to where it happens. Underlined rather than coloured alone —
   colour is not a distinguishing signal on its own, SC 1.4.1. */
.ps-work__task-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

.ps-work__task-link:hover { text-decoration-thickness: 2px; }

/* Lead versus supporting. The filled mark is the accountable party, the hollow one is
   help. Both cells also carry words for a screen reader, so this is emphasis rather
   than the only signal. */
.ps-work__owner--lead    { color: var(--ps-text); }
.ps-work__owner--support { color: var(--ps-muted); }

/* A board's description from Kitchen, under its name. Muted and smaller: it is
   context for the count beside it, not a heading of its own. */
.ps-progress__board-note {
  display: block;
  margin-block-start: .2rem;
  font-size: .8125rem;
  line-height: 1.45;
  color: var(--ps-text-2);
}

/* Choices in columns, for a long list of short options.
   ────────────────────────────────────────────────────────────────────────────
   Grid, not CSS multi-column. `columns: 2` flows down the first column and then
   down the second, so the visual order stops matching the DOM order — and the
   tab order follows the DOM, which would leave a keyboard user jumping from the
   bottom of one column to the top of the next. A grid reads left-to-right, the
   same order the markup is in.

   Collapses to one column below the container breakpoint: two ticks side by side
   in a narrow form card are harder to hit than a longer list, and 2.75rem rows
   are already at the target-size floor. */
@media (min-width: 30rem) {
  .ps-form__choices--cols2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ps-form__choices--cols3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
