/* ==========================================================================
   Quant Solvings portal: the design system as classes.
   Source: design/DESIGN-SYSTEM.md and design/artboards/Components.dc.html.
   Owner: the UI builder. Feature pages add their own rules in
   css/features/<feature>.css, built from these tokens and classes. They never
   add colors, shadows, radii or motion values of their own.

   Grounds: paper and white carry every page. ink-900 is the one dark ground
   (top bars, hero, offer card, sign-in half, toast); navy-800 fills primary
   buttons and the Mastered tile. Mark a dark region
   with data-ground="dark": links, focus rings, micro labels, numerals and
   progress marks switch to their dark values inside it. Gold lives only on
   dark grounds.

   Sections: 1 fonts, 2 tokens, 3 base, 4 type, 5 layout, 6 actions,
   7 surfaces, 8 figures and chips, 9 progress, 10 forms, 11 booking,
   12 feedback, 13 shells, 14 auth and error pages, 15 responsive, 16 motion.
   ========================================================================== */

/* 1. Fonts: self-hosted (no Google Fonts request), as the site's
   typography.css declares them. */

@font-face {
  font-family: "Source Serif 4";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("/fonts/SourceSerif4-Variable.woff2") format("woff2-variations");
}

@font-face {
  font-family: "Source Serif 4";
  font-style: italic;
  font-weight: 200 900;
  font-display: swap;
  src: url("/fonts/SourceSerif4-Italic-Variable.woff2") format("woff2-variations");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/IBMPlexSans-Regular.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("/fonts/IBMPlexSans-Medium.woff2") format("woff2");
}

@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/fonts/IBMPlexSans-SemiBold.woff2") format("woff2");
}

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

/* 2. Tokens: brand values only (site tokens.css and motion.css). */

:root {
  /* Grounds */
  --paper: #FBFBFC;
  --white: #FFFFFF;
  --ink-50: #F7F8FA;
  --ink-100: #F1F3F6;

  /* Lines */
  --ink-200: #E2E5EB;
  --ink-300: #C8CDD7;
  --ink-400: #8A93A4;

  /* Text */
  --ink-500: #5B667A;
  --ink-700: #2A3447;
  --ink-900: #0F1A2E;

  /* Navy: action, headings, progress marks */
  --navy-700: #243554;
  --navy-800: #1B2A45;
  --navy-900: #2D4059;

  /* Gold: dark grounds only */
  --gold-400: #F0C56E;
  --gold-500: #E4A83C;
  --black: #000000;

  /* State: errors, failures and legal clocks inside 3 days */
  --danger: #A33A2F;

  /* Derived values on dark grounds, and the overlay scrim */
  --white-8: rgba(255, 255, 255, 0.08);
  --white-16: rgba(255, 255, 255, 0.16);
  --white-24: rgba(255, 255, 255, 0.24);
  --white-40: rgba(255, 255, 255, 0.4);
  --scrim: rgba(15, 26, 46, 0.32);

  /* Type */
  --font-serif: "Source Serif 4", Georgia, serif;
  --font-sans: "IBM Plex Sans", "Helvetica Neue", Arial, sans-serif;
  --font-mono: "IBM Plex Mono", Menlo, monospace;

  /* Space: the site scale */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;
  --space-9: 80px;

  /* Radius: controls, containers */
  --radius-control: 4px;
  --radius-card: 8px;
  /* A full pill: the research post's comments pill only (2026-10-23, the Substack format). */
  --radius-pill: 9999px;

  /* Sizes */
  --container: 1240px;
  --gutter: 24px;
  --bar-h: 64px;
  --tabbar-h: 64px;
  --control-h: 48px;
  --control-h-compact: 44px;
  --target: 44px;

  /* Motion */
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.22, 0.61, 0.36, 1);
  --t-press: 80ms;
  --t-xfade: 160ms;
  --t-hover: 200ms;
  --t-sheet: 280ms;
  --t-line: 1100ms;
  /* The end of a Research post (2026-10-29): the meter's new segment fills after the gold hairline, then the series
     step it opened pops in. */
  --t-fill: 700ms;
  --t-fill-delay: 900ms;
  --t-pop-delay: 1200ms;

  /* The angle of the mark: progress marks only */
  --slant: skewX(-14.67deg);
}

/* 3. Base */

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

html {
  background: var(--paper);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin: 0;
  background: var(--paper);
  color: var(--ink-700);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 24px;
  font-weight: 400;
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

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

:where(fieldset) {
  min-width: 0;
  padding: 0;
  border: 0;
}

:where(legend) {
  padding: 0;
}

:where(img, svg, video) {
  display: block;
  max-width: 100%;
}

:where(img) {
  height: auto;
}

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

:where(button, summary) {
  cursor: pointer;
}

:where(table) {
  border-collapse: collapse;
}

[hidden] {
  display: none !important;
}

:where(a) {
  color: var(--navy-800);
  text-decoration-line: underline;
  text-decoration-color: var(--ink-300);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

:where(a):hover {
  color: var(--navy-700);
  text-decoration-color: currentColor;
}

:where([data-ground="dark"]) :where(a) {
  color: var(--white);
  text-decoration-color: var(--white-40);
}

:where([data-ground="dark"]) :where(a):hover {
  color: var(--white);
  text-decoration-color: var(--white);
}

:where([data-ground="light"]) :where(a) {
  color: var(--navy-800);
  text-decoration-color: var(--ink-300);
}

:where([data-ground="light"]) :where(a):hover {
  color: var(--navy-700);
  text-decoration-color: currentColor;
}

/* Focus: navy on light grounds (14.3:1 on white), gold on dark (8.3:1 on ink-900). */
:focus-visible {
  outline: 2px solid var(--navy-800);
  outline-offset: 2px;
}

[data-ground="dark"]:focus-visible,
[data-ground="dark"] :focus-visible {
  outline-color: var(--gold-500);
}

[data-ground="light"] :focus-visible {
  outline-color: var(--navy-800);
}

::placeholder {
  color: var(--ink-500);
  opacity: 1;
}

:where(a, button, input, select, textarea, summary, label) {
  transition:
    color var(--t-hover) var(--ease-standard),
    background-color var(--t-hover) var(--ease-standard),
    border-color var(--t-hover) var(--ease-standard),
    text-decoration-color var(--t-hover) var(--ease-standard),
    transform var(--t-press) var(--ease-out);
}

/* 4. Type */

:where(h1),
.h1 {
  font-family: var(--font-serif);
  font-size: 34px;
  line-height: 39px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--navy-800);
}

:where(h2),
.h2 {
  font-family: var(--font-serif);
  font-size: 22px;
  line-height: 29px;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--navy-800);
}

:where(h3, h4, h5, h6),
.title {
  font-family: var(--font-sans);
  font-size: 17px;
  line-height: 24px;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ink-900);
}

/* Moment headlines only (sign in, welcome, level complete); they end with a period. */
.display {
  font-family: var(--font-serif);
  font-size: 64px;
  line-height: 66px;
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--navy-800);
}

.text-label {
  font-size: 15px;
  line-height: 22px;
  font-weight: 600;
  color: var(--ink-900);
}

.text-body {
  font-size: 15px;
  line-height: 24px;
  font-weight: 400;
  color: var(--ink-700);
}

.text-strong {
  color: var(--ink-900);
}

.text-small {
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-500);
}

.fine-print {
  font-size: 12px;
  line-height: 16px;
  color: var(--ink-500);
}

/* Micro label: write sentence case in the source; CSS sets the caps. */
.micro {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-500);
}

/* Carlos's own lines only. */
.voice {
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 24px;
  font-style: italic;
  font-weight: 400;
  color: var(--ink-700);
}

/* Fixed legal strings only, each on its own line. */
.legal {
  font-size: 13px;
  line-height: 20px;
  font-style: italic;
  color: var(--ink-500);
}

.nowrap {
  white-space: nowrap;
}

[data-ground="dark"] :where(h1, h2, .h1, .h2, .display) {
  color: var(--white);
}

[data-ground="dark"] :where(h3, h4, .title, .text-label, .text-strong) {
  color: var(--white);
}

[data-ground="dark"] .micro,
[data-ground="dark"] .text-small,
[data-ground="dark"] .fine-print,
[data-ground="dark"] .legal {
  color: var(--ink-300);
}

/* 5. Layout primitives */

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

.stack {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Children keep their own width instead of stretching (text links under a button). */
.stack-start {
  align-items: flex-start;
}

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
}

.cluster-between {
  justify-content: space-between;
}

.cluster-end {
  justify-content: flex-end;
}

.cluster-baseline {
  align-items: baseline;
}

.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: 24px;
  row-gap: 24px;
  align-items: start;
}

.grid-stretch {
  align-items: stretch;
}

.span-1 { grid-column: span 1; }
.span-2 { grid-column: span 2; }
.span-3 { grid-column: span 3; }
.span-4 { grid-column: span 4; }
.span-5 { grid-column: span 5; }
.span-6 { grid-column: span 6; }
.span-7 { grid-column: span 7; }
.span-8 { grid-column: span 8; }
.span-9 { grid-column: span 9; }
.span-10 { grid-column: span 10; }
.span-11 { grid-column: span 11; }
.span-12 { grid-column: span 12; }

.gap-4 { gap: 4px; }
.gap-8 { gap: 8px; }
.gap-12 { gap: 12px; }
.gap-16 { gap: 16px; }
.gap-24 { gap: 24px; }
.gap-32 { gap: 32px; }
.gap-48 { gap: 48px; }

.min-w-0 {
  min-width: 0;
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  top: -120px;
  left: 16px;
  z-index: 100;
  padding: 10px 16px;
  border-radius: var(--radius-control);
  background: var(--white);
  color: var(--navy-800);
  font-weight: 500;
}

.skip-link:focus {
  top: 10px;
}

/* 6. Actions: buttons, text links, icon buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: var(--control-h);
  padding: 0 24px;
  border: 1px solid var(--navy-800);
  border-radius: var(--radius-control);
  background: var(--white);
  color: var(--navy-800);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 20px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.btn:active:not(:disabled) {
  transform: scale(0.98);
}

.btn:disabled {
  cursor: not-allowed;
}

.btn-primary {
  background: var(--navy-800);
  color: var(--white);
  font-weight: 600;
}

.btn-primary:hover {
  border-color: var(--navy-700);
  background: var(--navy-700);
  color: var(--white);
}

.btn-primary:disabled {
  border-color: var(--ink-200);
  background: var(--ink-200);
  color: var(--ink-500);
}

.btn-secondary:hover {
  background: var(--ink-100);
  color: var(--navy-800);
}

.btn-secondary:disabled {
  border-color: var(--ink-300);
  background: var(--white);
  color: var(--ink-400);
}

/* One per dark card, black label. Never on white or paper. */
.btn-gold {
  border-color: var(--gold-500);
  background: var(--gold-500);
  color: var(--black);
  font-weight: 600;
}

.btn-gold:hover {
  border-color: var(--gold-400);
  background: var(--gold-400);
  color: var(--black);
}

[data-ground="dark"] .btn-secondary {
  border-color: var(--white-40);
  background: transparent;
  color: var(--white);
}

[data-ground="dark"] .btn-secondary:hover {
  border-color: var(--white);
  background: var(--white-8);
  color: var(--white);
}

/* Quiet: a text link with a 44 px target. Decline is always "Not now". */
.btn-quiet {
  gap: 6px;
  height: auto;
  min-height: var(--target);
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--navy-800);
  font-weight: 500;
  text-decoration-line: underline;
  text-decoration-color: var(--ink-300);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.btn-quiet:hover {
  color: var(--navy-700);
  text-decoration-color: currentColor;
}

.btn-quiet:disabled {
  color: var(--ink-400);
  text-decoration-color: var(--ink-200);
}

[data-ground="dark"] .btn-quiet {
  color: var(--white);
  text-decoration-color: var(--white-40);
}

[data-ground="dark"] .btn-quiet:hover {
  color: var(--white);
  text-decoration-color: var(--white);
}

.btn-sm {
  height: var(--control-h-compact);
  padding: 0 18px;
  font-size: 14px;
}

.btn-quiet.btn-sm {
  height: auto;
  padding: 0;
}

.btn-block {
  width: 100%;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--target);
  height: var(--target);
  padding: 0;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink-700);
  text-decoration: none;
  cursor: pointer;
}

.icon-btn:hover,
.icon-btn[aria-pressed="true"] {
  background: var(--ink-100);
  color: var(--ink-900);
}

.icon-btn:disabled {
  background: transparent;
  color: var(--ink-400);
  cursor: default;
}

.icon-btn:active:not(:disabled) {
  transform: scale(0.98);
}

[data-ground="dark"] .icon-btn {
  color: var(--ink-300);
}

[data-ground="dark"] .icon-btn:hover {
  background: var(--white-8);
  color: var(--white);
}

.icon {
  display: block;
  flex: none;
}

/* 7. Surfaces: cards, hero, headers, lists */

.card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
  padding: 24px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  background: var(--white);
}

/* Emphasis is a full navy line, never a side stripe. */
.card-emphasis {
  border-color: var(--navy-900);
}

.card-compact {
  padding: 20px;
}

.card-roomy {
  padding: 32px;
}

.card-flush {
  gap: 0;
  padding: 0;
  overflow: hidden;
}

.card-dashed {
  border-style: dashed;
  border-color: var(--ink-300);
  background: transparent;
}

/* Offer card on ink-900: at most one dark card per screen. */
.card-dark {
  gap: 20px;
  padding: 32px;
  border-color: var(--ink-900);
  background: var(--ink-900);
  color: var(--white);
}

/* Card parts: a micro label row (with a chip), a title group, actions at the foot. */
.card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  min-height: 24px;
}

.card-titles {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.card-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-top: auto;
}

/* Inset panel inside a card: "Last time", "Your topic". */
.inset {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px 16px;
  border-radius: var(--radius-control);
  background: var(--ink-50);
}

.divider {
  height: 1px;
  border: 0;
  margin: 0;
  background: var(--ink-200);
}

[data-ground="dark"] .divider {
  background: var(--white-8);
}

/* 48 x 1 gold rule: dark grounds only. */
.gold-rule {
  display: block;
  flex: none;
  width: 48px;
  height: 1px;
  background: var(--gold-500);
  transform-origin: left center;
}

/* Hero: ink-900, one per screen, one gold button. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 1px 272px;
  column-gap: 40px;
  min-height: 300px;
  padding: 40px;
  border-radius: var(--radius-card);
  background: var(--ink-900);
  color: var(--white);
}

.hero-start,
.hero-end {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 24px;
  min-width: 0;
}

.hero-divider {
  background: var(--white-8);
}

/* The same frame on white, for the one card that replaces the hero. */
.hero-light {
  border: 1px solid var(--navy-900);
  background: var(--white);
  color: var(--ink-700);
}

.hero-light .hero-divider {
  background: var(--ink-200);
}

.page-head {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.page-head-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 16px 24px;
}

.page-head-title {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 12px;
}

.page-head-count {
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 22px;
  color: var(--ink-500);
  white-space: nowrap;
}

.page-head-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

.back-link {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: 8px;
  min-height: var(--target);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
}

.section-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
}

.section-head-title {
  display: flex;
  align-items: baseline;
  gap: 12px;
}

.section-head-count {
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 22px;
  color: var(--ink-500);
}

/* A list whose rows are split by hairlines. */
.rows {
  display: flex;
  flex-direction: column;
}

.rows > * {
  padding: 12px 0;
  border-bottom: 1px solid var(--ink-200);
}

.rows-top {
  border-top: 1px solid var(--ink-200);
}

/* Labelled lines: Carlos's Covered, Decided, Next. */
.facts {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  column-gap: 16px;
  row-gap: 12px;
  align-items: baseline;
}

.facts dt {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-500);
}

.facts dd {
  margin: 0;
  font-size: 15px;
  line-height: 24px;
  color: var(--ink-700);
}

/* A session's transcript (2026-10-20): a paragraph per line at the body's size, the speaker's name strong, long
   words wrapped. */
.transcript-text {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
  font-size: 15px;
  line-height: 24px;
  color: var(--ink-700);
  overflow-wrap: anywhere;
}

.transcript-text > p {
  margin: 0;
}

.transcript-speaker {
  color: var(--ink-900);
  font-weight: 600;
}

/* Folding rows built on details and summary: they work without JavaScript. */
.folds {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  background: var(--white);
}

.fold + .fold {
  border-top: 1px solid var(--ink-200);
}

.fold-summary {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 76px;
  padding: 16px 24px;
  list-style: none;
}

.fold-summary::-webkit-details-marker {
  display: none;
}

.fold-summary:hover {
  background: var(--ink-50);
}

.fold-main {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.fold-chevron {
  flex: none;
  color: var(--ink-700);
}

.fold[open] > .fold-summary .fold-chevron {
  transform: rotate(180deg);
}

.fold-body {
  padding: 0 24px 24px;
}

/* Side sheet: the panel alone, or opened as a modal dialog by base.js. */
.sheet {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  background: var(--white);
}

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 12px 16px 24px;
  border-bottom: 1px solid var(--ink-200);
}

.sheet-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 16px;
  padding: 24px;
  overflow-y: auto;
}

.sheet-foot {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 16px;
  padding: 16px 24px;
  border-top: 1px solid var(--ink-200);
}

dialog.sheet {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(480px, 100vw);
  max-width: 100vw;
  height: 100%;
  max-height: none;
  margin: 0;
  padding: 0;
  border-width: 0 0 0 1px;
  border-radius: 0;
  color: var(--ink-700);
}

/* .sheet sets display, which would beat the browser's rule that hides a closed dialog. */
dialog.sheet:not([open]) {
  display: none;
}

dialog.sheet::backdrop {
  background: var(--scrim);
}

/* The certificate of completion (CertificateDocument, src/ui/certificate.tsx; 2026-10-22, owner decision:
   direction A). An A4 landscape sheet drawn on the canvas's 1123 x 794 grid: the frame is a size container
   and --cert-u one 1123th of its width, so every length below is N design units and the drawing is the same
   at any width (the level moment's preview, Close out's, and 297 x 210 mm on paper, where a unit is about
   one CSS pixel). Navy and ink only: a white ground never carries gold. */
.cert-doc-frame {
  --cert-u: calc(100cqw / 1123);
  container-type: inline-size;
  width: 100%;
  aspect-ratio: 1123 / 794;
}

/* On screen the white sheet sits on white cards: a hairline outline marks its edge without taking room. */
@media screen {
  .cert-doc-frame {
    outline: 1px solid var(--ink-200);
  }
}

.cert-doc {
  width: 100%;
  height: 100%;
  overflow: hidden;
  padding: calc(32 * var(--cert-u));
  background: var(--white);
  color: var(--ink-700);
  font-family: var(--font-sans);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

.cert-doc-outer {
  height: 100%;
  padding: calc(5 * var(--cert-u));
  border: calc(1 * var(--cert-u)) solid var(--navy-900);
}

.cert-doc-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  height: 100%;
  padding: calc(40 * var(--cert-u)) calc(72 * var(--cert-u)) calc(28 * var(--cert-u));
  border: calc(1 * var(--cert-u)) solid var(--ink-300);
}

.cert-doc-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
}

.cert-doc-logo {
  display: block;
  width: auto;
  height: calc(68 * var(--cert-u));
}

.cert-doc-title {
  margin-top: calc(28 * var(--cert-u));
  font-family: var(--font-mono);
  font-size: calc(12 * var(--cert-u));
  line-height: calc(16 * var(--cert-u));
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--ink-500);
}

.cert-doc-presented,
.cert-doc-for {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: calc(18 * var(--cert-u));
  line-height: calc(24 * var(--cert-u));
  color: var(--ink-500);
}

.cert-doc-presented {
  margin-top: calc(28 * var(--cert-u));
}

/* The holder's name: 64 up to 22 characters, 52 up to 30, 44 beyond (nameSize). */
.cert-doc-name {
  max-width: calc(900 * var(--cert-u));
  margin-top: calc(6 * var(--cert-u));
  font-family: var(--font-serif);
  line-height: 1.12;
  font-weight: 500;
  letter-spacing: -0.015em;
  color: var(--navy-800);
  text-wrap: balance;
  overflow-wrap: anywhere;
}

.cert-doc-name-l {
  font-size: calc(64 * var(--cert-u));
}

.cert-doc-name-m {
  font-size: calc(52 * var(--cert-u));
}

.cert-doc-name-s {
  font-size: calc(44 * var(--cert-u));
}

/* The 48 x 1 navy rule under the name, drawn once on the owner's first view (section 16). */
.cert-doc-rule {
  display: block;
  flex: none;
  width: calc(48 * var(--cert-u));
  height: calc(1 * var(--cert-u));
  margin-top: calc(14 * var(--cert-u));
  background: var(--navy-900);
  transform-origin: left center;
}

.cert-doc-for {
  margin-top: calc(22 * var(--cert-u));
}

.cert-doc-level {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(16 * var(--cert-u));
  margin-top: calc(8 * var(--cert-u));
}

/* The tier bars: three parallelograms at the logo's angle, the level's rungs filled, the others outlined. */
.cert-doc-bars {
  display: flex;
  align-items: center;
  gap: calc(6 * var(--cert-u));
}

.cert-doc-bar {
  display: block;
  width: calc(12 * var(--cert-u));
  height: calc(32 * var(--cert-u));
  background: var(--navy-900);
  transform: var(--slant);
}

.cert-doc-bar-open {
  border: calc(1 * var(--cert-u)) solid var(--ink-400);
  background: transparent;
}

/* The Full Program: all three filled, inside a navy hairline frame. */
.cert-doc-bars-full {
  padding: calc(5 * var(--cert-u)) calc(9 * var(--cert-u));
  border: calc(1 * var(--cert-u)) solid var(--navy-900);
}

.cert-doc-bars-full .cert-doc-bar {
  width: calc(10 * var(--cert-u));
  height: calc(26 * var(--cert-u));
}

.cert-doc-program {
  font-family: var(--font-serif);
  font-size: calc(34 * var(--cert-u));
  line-height: calc(40 * var(--cert-u));
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--navy-800);
}

.cert-doc-line {
  margin-top: calc(10 * var(--cert-u));
  font-size: calc(15 * var(--cert-u));
  line-height: calc(24 * var(--cert-u));
  color: var(--ink-700);
}

.cert-doc-foot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(20 * var(--cert-u));
  width: 100%;
}

.cert-doc-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) calc(120 * var(--cert-u)) minmax(0, 1fr);
  column-gap: calc(32 * var(--cert-u));
  align-items: end;
  width: 100%;
}

.cert-doc-sign {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: calc(6 * var(--cert-u));
  text-align: left;
}

/* Carlos's handwritten signature (2026-10-23, owner decision), 56 units tall, its bottom 4 units past the hairline
   (the column's 6 unit gap less 10): the lowest strokes cross the line as a pen signs and stop clear of the line of
   words under it. The image's ground is transparent, and it lies over the hairline. */
.cert-doc-signature {
  position: relative;
  z-index: 1;
  display: block;
  width: auto;
  height: calc(56 * var(--cert-u));
  margin-bottom: calc(-10 * var(--cert-u));
}

.cert-doc-sign-rule {
  display: block;
  width: calc(240 * var(--cert-u));
  max-width: 100%;
  height: calc(1 * var(--cert-u));
  background: var(--ink-400);
}

.cert-doc-signer {
  font-size: calc(12 * var(--cert-u));
  line-height: calc(18 * var(--cert-u));
  color: var(--ink-500);
}

/* The seal: the canvas's 120 x 120 drawing; its rings, words, isotipo and code take currentColor. */
.cert-doc-seal {
  display: block;
  width: calc(120 * var(--cert-u));
  height: calc(120 * var(--cert-u));
  color: var(--navy-900);
}

.cert-doc-seal text {
  font-family: var(--font-mono);
}

.cert-doc-facts {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: calc(2 * var(--cert-u));
  text-align: right;
}

.cert-doc-label {
  font-family: var(--font-mono);
  font-size: calc(11 * var(--cert-u));
  line-height: calc(16 * var(--cert-u));
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-500);
}

.cert-doc-date + .cert-doc-label {
  margin-top: calc(8 * var(--cert-u));
}

.cert-doc-date {
  font-family: var(--font-serif);
  font-size: calc(18 * var(--cert-u));
  line-height: calc(24 * var(--cert-u));
  color: var(--navy-800);
}

.cert-doc-id {
  font-family: var(--font-mono);
  font-size: calc(14 * var(--cert-u));
  line-height: calc(20 * var(--cert-u));
  color: var(--ink-900);
}

/* The coaching disclaimer, byte for byte, in the certificate's language. */
.cert-doc-legal {
  max-width: calc(820 * var(--cert-u));
  font-size: calc(12 * var(--cert-u));
  line-height: calc(18 * var(--cert-u));
  font-style: italic;
  color: var(--ink-500);
}

/* Forced colors (Windows High Contrast, review of 2026-10-22): the browser replaces backgrounds with Canvas and
   borders with CanvasText, so the filled rungs, the rule under the name and the signature rule (drawn as
   backgrounds) would vanish while the open rungs (borders) stayed, and the level would read backwards. These
   marks keep their own drawing in the system's text color; the open rungs stay outlines on Canvas. */
@media (forced-colors: active) {
  .cert-doc-bar,
  .cert-doc-rule,
  .cert-doc-sign-rule {
    forced-color-adjust: none;
    background: CanvasText;
  }

  .cert-doc-bar-open {
    border-color: CanvasText;
    background: Canvas;
  }
}

/* 8. Figures, numerals, stats, chips */

/* Serif numerals: counts and the next session time. */
.numeral {
  font-family: var(--font-serif);
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--navy-800);
  font-variant-numeric: tabular-nums;
}

.numeral-xl {
  font-size: 88px;
  line-height: 72px;
}

.numeral-l {
  font-size: 60px;
  line-height: 60px;
}

.numeral-m {
  font-size: 40px;
  line-height: 40px;
}

.numeral-s {
  font-size: 28px;
  line-height: 32px;
}

[data-ground="dark"] .numeral {
  color: var(--white);
}

/* Mono figures: money, codes, ages, table figures. Money never wraps. */
.figure {
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 22px;
  font-weight: 400;
  color: var(--ink-900);
  white-space: nowrap;
}

.figure-xl {
  font-size: 40px;
  line-height: 44px;
  letter-spacing: -0.02em;
}

.figure-l {
  font-size: 28px;
  line-height: 34px;
  letter-spacing: -0.02em;
}

.figure-m {
  font-size: 17px;
  line-height: 24px;
}

.figure-s {
  font-size: 15px;
  line-height: 22px;
}

.figure-xs {
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-700);
}

[data-ground="dark"] .figure {
  color: var(--white);
}

.stat {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.stat-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
}

.stat-unit {
  font-size: 15px;
  line-height: 24px;
  color: var(--ink-700);
}

.stat-figure {
  gap: 6px;
}

.stat-context {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-500);
}

[data-ground="dark"] .stat-unit {
  color: var(--ink-300);
}

/* Chips: 24 tall, never interactive. States are words plus an icon or shape. */
.chip {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 8px;
  border: 1px solid var(--ink-100);
  border-radius: var(--radius-control);
  background: var(--ink-100);
  color: var(--ink-700);
  font-family: var(--font-sans);
  font-size: 12px;
  line-height: 16px;
  font-weight: 500;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.chip-outline {
  border-color: var(--navy-800);
  background: var(--white);
  color: var(--navy-800);
}

.chip-hairline {
  border-color: var(--ink-200);
  background: var(--white);
  color: var(--ink-700);
}

.chip-hairline .icon {
  color: var(--navy-800);
}

.chip-danger {
  border-color: var(--danger);
  background: var(--white);
  color: var(--danger);
}

/* The level mark (LevelMark, src/ui/level-mark.tsx; 2026-10-23, owner decision, the canvas's ForumBadges.dc.html): a
   client's highest completed level beside their name. A chip 20 tall, never interactive: three mini tier bars of
   3 x 10 at the logo's angle (the level's rungs filled navy-900, the others a 1px ink-400 outline), then the level's
   name at 11/16 600. The Full Program's three filled bars of 3 x 8 sit in a navy-900 frame 14 tall. White chip on
   light grounds (the forum); the dark one (.level-mark-dark) only in the client top bar, the one place its bars are
   gold. The staff badge (.fm-staff) stays the only filled chip. */
.level-mark {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: 20px;
  padding: 0 6px;
  border: 1px solid var(--navy-900);
  border-radius: var(--radius-control);
  background: var(--white);
  color: var(--navy-800);
  font-family: var(--font-sans);
  font-size: 11px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.level-mark-full {
  padding-left: 3px;
}

.level-mark-bars {
  display: flex;
  flex: none;
  align-items: center;
  gap: 2px;
}

.level-mark-bar {
  display: block;
  width: 3px;
  height: 10px;
  border: 1px solid var(--ink-400);
  transform: var(--slant);
}

.level-mark-bar-done {
  border-color: var(--navy-900);
  background: var(--navy-900);
}

.level-mark-full .level-mark-bars {
  height: 14px;
  padding: 0 3px;
  border: 1px solid var(--navy-900);
}

.level-mark-full .level-mark-bar {
  height: 8px;
}

/* On the ink-900 top bar: a white hairline at 24%, the word in white, the rungs gold-500 filled or a white 40%
   outline, the Full Program's frame gold-500. */
.level-mark-dark {
  border-color: var(--white-24);
  background: transparent;
  color: var(--white);
}

.level-mark-dark .level-mark-bar {
  border-color: var(--white-40);
}

.level-mark-dark .level-mark-bar-done {
  border-color: var(--gold-500);
  background: var(--gold-500);
}

.level-mark-dark.level-mark-full .level-mark-bars {
  border-color: var(--gold-500);
}

/* The compact form, the bars alone: no hairline, no padding, the word kept for screen readers only (the title and
   the hidden words still name it). The top bar uses it under 900 px and in Spanish from 1200 to 1219 px (section 13,
   2026-10-23, owner decision: P123 into Tools) and every mark under 480 px (section 15). */
.topbar-level .level-mark {
  gap: 0;
  padding: 0;
  border-width: 0;
}

.topbar-level .level-mark-word {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
}

/* Forced colors (as the certificate's tier bars, 2026-10-22): the filled rungs are backgrounds, which the browser
   would drop while the open rungs' borders stayed, so the level would read backwards. The rungs keep their own
   drawing in the system's text color; the open ones stay outlines on Canvas. The chip and the frame are borders,
   which the system colors already. The dark variant's selectors are listed too, so its gold and white-40 rungs (two
   classes) cannot outrank this block on the top bar's forced Canvas. */
@media (forced-colors: active) {
  .level-mark-bar,
  .level-mark-dark .level-mark-bar {
    forced-color-adjust: none;
    border-color: CanvasText;
    background: Canvas;
  }

  .level-mark-bar-done,
  .level-mark-dark .level-mark-bar-done {
    background: CanvasText;
  }
}

/* Tags for unfinished content: Placeholder, Working title, Sample figures. */
.tag {
  display: inline-flex;
  flex: none;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 8px;
  border: 1px dashed var(--ink-400);
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink-500);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  white-space: nowrap;
}

[data-ground="dark"] .tag {
  border: 1px solid var(--white-24);
  color: var(--ink-300);
}

/* Choice chips: 44 tall filters and toggles (links, buttons or labelled inputs). */
.choices {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.choice {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: var(--target);
  padding: 0 14px;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-control);
  background: var(--white);
  color: var(--ink-700);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.choice:hover {
  border-color: var(--navy-800);
  color: var(--ink-700);
}

.choice:active {
  transform: scale(0.98);
}

.choice[aria-pressed="true"],
.choice[aria-current="true"],
.choice[aria-current="page"],
.choice-input:checked + .choice {
  border-color: var(--navy-800);
  background: var(--ink-100);
  color: var(--navy-800);
  font-weight: 600;
}

.choice-input:focus-visible + .choice {
  outline: 2px solid var(--navy-800);
  outline-offset: 2px;
}

.choice-count {
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 20px;
  font-weight: 400;
  color: var(--ink-500);
}

/* Tables: th scope="col" in mono micro caps, 64 tall rows, hover ink-50. */
.table-wrap {
  width: 100%;
  overflow-x: auto;
}

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

.table caption {
  text-align: left;
}

.table thead th {
  height: 44px;
  padding: 0 16px 0 0;
  border-bottom: 1px solid var(--ink-200);
  color: var(--ink-500);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  font-weight: 400;
  letter-spacing: 0.18em;
  text-align: left;
  text-transform: uppercase;
  vertical-align: middle;
  white-space: nowrap;
}

.table tbody :is(td, th) {
  height: 64px;
  padding: 0 16px 0 0;
  border-bottom: 1px solid var(--ink-200);
  color: var(--ink-900);
  font-size: 15px;
  line-height: 22px;
  font-weight: 400;
  text-align: left;
  vertical-align: middle;
}

.table :is(td, th):last-child {
  padding-right: 0;
}

.table tbody tr:hover {
  background: var(--ink-50);
}

.table .cell-num {
  font-family: var(--font-mono);
  text-align: right;
  white-space: nowrap;
}

.table thead th.cell-num {
  text-align: right;
}

.table-compact tbody :is(td, th) {
  height: 44px;
}

.cell-stack {
  display: flex;
  flex-direction: column;
}

.cell-sub {
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-500);
}

/* Avatar tile: initials inside a 44 px button. */
.avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-control);
  background: var(--navy-700);
  color: var(--white);
  font-size: 12px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/* 9. Progress marks: they lean like the mark and never show a percent. */

/* Session tick bar: held solid, booked outline, to book faint. */
.pips {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
}

.pip {
  display: block;
  flex: none;
  width: 28px;
  height: 8px;
  background: var(--ink-200);
  transform: var(--slant);
}

.pip-held {
  background: var(--navy-900);
}

.pip-booked {
  border: 1px solid var(--navy-900);
  background: var(--white);
}

.pips-lessons .pip {
  width: 24px;
}

[data-ground="dark"] .pip {
  background: var(--white-16);
}

[data-ground="dark"] .pip-held {
  background: var(--white);
}

[data-ground="dark"] .pip-booked {
  border-color: var(--white);
  background: transparent;
}

/* Forced colors drop backgrounds (2026-10-27): held keeps its fill, booked its outline, the rest a grey outline, so the
   bar never reads empty or backwards. */
@media (forced-colors: active) {
  .pip,
  [data-ground="dark"] .pip {
    forced-color-adjust: none;
    border: 1px solid GrayText;
    background: Canvas;
  }

  .pip-held,
  [data-ground="dark"] .pip-held {
    border-color: CanvasText;
    background: CanvasText;
  }

  .pip-booked,
  [data-ground="dark"] .pip-booked {
    border-color: CanvasText;
  }
}

/* Lessons: the same bar with a count beside it. */
.progress {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

/* Skill steps: 28 (tiles), 20 (legend), 10 (mini map). Navy only. */
.step {
  position: relative;
  display: inline-block;
  flex: none;
  width: 28px;
  height: 28px;
  vertical-align: middle;
}

.step::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--ink-300);
  background: var(--white);
  transform: var(--slant);
}

/* Studied: the navy outline and its bottom quarter filled, the first rung of the fill applied and confirmed
   continue (2026-10-19: an outline alone read as not started). */
.step-studied::before {
  border: 1.5px solid var(--navy-900);
  background: linear-gradient(to top, var(--navy-900) 25%, var(--white) 25%);
}

.step-applied::before {
  border: 1.5px solid var(--navy-900);
  background: linear-gradient(to top, var(--navy-900) 50%, var(--white) 50%);
}

.step-confirmed::before {
  border: 1.5px solid var(--navy-900);
  background: var(--navy-900);
}

/* Review due: a small open ring. It never removes a level. */
.step-review::after {
  content: "";
  position: absolute;
  top: -5px;
  right: -8px;
  width: 10px;
  height: 10px;
  border: 1.5px solid var(--navy-900);
  border-radius: 50%;
  background: var(--white);
}

.step-md {
  width: 20px;
  height: 20px;
}

.step-sm {
  width: 10px;
  height: 10px;
}

.step-sm::before {
  border-width: 1px;
}

.step-sm.step-none::before {
  border: 0;
  background: var(--ink-200);
}

[data-ground="dark"] .step-confirmed::before {
  border-color: var(--white);
  background: var(--white);
}

.step-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 24px;
}

.step-key {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  min-height: 28px;
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-700);
}

/* Track tile: 170 tall, level in serif. Mastered turns navy with the gold rule. */
.track {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 16px;
  min-width: 0;
  min-height: 170px;
  padding: 20px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  background: var(--white);
}

.track-head {
  display: flex;
  flex-direction: column;
}

.track-name {
  font-size: 15px;
  line-height: 22px;
  font-weight: 600;
  color: var(--ink-900);
}

.level {
  font-family: var(--font-serif);
  font-size: 20px;
  line-height: 26px;
  font-weight: 500;
  color: var(--ink-900);
}

.level-none {
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 26px;
  font-weight: 400;
  color: var(--ink-500);
}

.track-steps {
  display: flex;
  gap: 12px;
}

.track-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 28px;
}

.track-code {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.04em;
  color: var(--ink-500);
  white-space: nowrap;
}

.track-mastered {
  border-color: var(--navy-800);
  background: var(--navy-800);
  color: var(--white);
}

.track-mastered .gold-rule {
  margin-bottom: 12px;
}

.track-mastered .track-name,
.track-mastered .level {
  color: var(--white);
}

.track-mastered .track-code {
  color: var(--ink-300);
}

/* Skill map in miniature: 3 x 3 tracks of 4 steps at 10 px. */
.skillmap {
  display: grid;
  grid-template-columns: repeat(3, max-content);
  gap: 10px 16px;
}

.skillmap-track {
  display: flex;
  gap: 3px;
}

/* Admin skills strip: one mark per track, fill rises a quarter per confirmed step. */
.skillstrip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

.skillstrip-marks {
  display: flex;
  gap: 3px;
}

.skillstrip-mark {
  display: block;
  flex: none;
  width: 12px;
  height: 12px;
  border: 1px solid var(--navy-900);
  background: var(--white);
  transform: var(--slant);
}

.skillstrip-mark.fill-0 {
  border-color: var(--ink-300);
}

.skillstrip-mark.fill-1 {
  background: linear-gradient(to top, var(--navy-900) 25%, var(--white) 25%);
}

.skillstrip-mark.fill-2 {
  background: linear-gradient(to top, var(--navy-900) 50%, var(--white) 50%);
}

.skillstrip-mark.fill-3 {
  background: linear-gradient(to top, var(--navy-900) 75%, var(--white) 75%);
}

.skillstrip-mark.fill-4 {
  background: var(--navy-900);
}

/* Study weeks: 13 marks, oldest first. Weeks, never days. */
.weeks {
  display: flex;
  gap: 4px;
}

.week {
  display: block;
  flex: none;
  width: 12px;
  height: 12px;
  background: var(--ink-200);
  transform: var(--slant);
}

.week-on {
  background: var(--navy-900);
}

.week-now {
  border: 1px solid var(--navy-900);
  background: var(--white);
}

.study-weeks {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.study-weeks-count {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-700);
}

/* Week ring (phone): three static arcs, Learn, Apply, Review. */
.week-ring-row {
  display: flex;
  align-items: center;
  gap: 16px;
}

.week-ring {
  display: block;
  flex: none;
  width: 64px;
  height: 64px;
}

.week-ring .arc {
  fill: none;
  stroke: var(--ink-200);
  stroke-width: 5;
  stroke-linecap: butt;
}

.week-ring .arc-closed {
  stroke: var(--navy-900);
}

.ring-legend {
  display: flex;
  flex: none;
  flex-direction: column;
  gap: 4px;
}

.ring-key {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-700);
}

a.ring-key {
  align-self: flex-start;
  min-height: var(--target);
  margin: -12px 0;
  font-weight: 500;
}

.ring-key-bar {
  display: block;
  flex: none;
  width: 12px;
  height: 4px;
  background: var(--ink-200);
}

.ring-key-bar.is-closed {
  background: var(--navy-900);
}

/* Milestones: reached in navy with a date; the next three as outlines. */
.milestones {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.milestone {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 24px;
}

.milestone-mark {
  display: block;
  flex: none;
  width: 10px;
  height: 10px;
  background: var(--navy-900);
  transform: var(--slant);
}

.milestone-name {
  flex: 1;
  font-size: 15px;
  line-height: 22px;
  color: var(--ink-900);
}

.milestone-next .milestone-mark {
  border: 1px solid var(--ink-400);
  background: transparent;
}

.milestone-next .milestone-name {
  color: var(--ink-500);
}

/* Checklist rings: pending, current, done. */
.ring-mark {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: 1.5px solid var(--ink-400);
  border-radius: 50%;
  color: var(--ink-500);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 16px;
}

.ring-mark-current {
  border-color: var(--navy-900);
  color: var(--navy-900);
  font-weight: 500;
}

.ring-mark-done {
  border-color: var(--navy-900);
  background: var(--navy-900);
  color: var(--white);
}

/* 10. Forms: label above, hint or error below, 48 tall, borders 3:1. */

.form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.form-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px 24px;
}

.form-grid > .field-wide {
  grid-column: 1 / -1;
}

.field {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

.field-label {
  font-size: 13px;
  line-height: 20px;
  font-weight: 500;
  color: var(--ink-700);
}

.field-optional {
  font-weight: 400;
  color: var(--ink-500);
}

.field-hint {
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-500);
}

.field-error {
  font-size: 13px;
  line-height: 20px;
  color: var(--danger);
}

.input {
  display: block;
  width: 100%;
  height: var(--control-h);
  padding: 0 14px;
  border: 1px solid var(--ink-400);
  border-radius: var(--radius-control);
  background: var(--white);
  color: var(--ink-900);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 22px;
}

.input[aria-invalid="true"] {
  border-color: var(--danger);
}

.input:disabled {
  border-color: var(--ink-200);
  background: var(--ink-50);
  color: var(--ink-500);
  cursor: not-allowed;
}

.input[readonly] {
  background: var(--ink-50);
}

textarea.input {
  height: auto;
  min-height: 120px;
  padding: 12px 14px;
  line-height: 24px;
  resize: vertical;
}

select.input {
  padding-right: 44px;
  appearance: none;
  -webkit-appearance: none;
}

.input-wrap {
  position: relative;
}

.input-wrap > .input {
  padding-right: 52px;
}

.input-wrap > .icon-btn {
  position: absolute;
  top: 2px;
  right: 2px;
}

.select {
  position: relative;
}

.select-icon {
  position: absolute;
  top: 14px;
  right: 14px;
  color: var(--ink-700);
  pointer-events: none;
}

.search {
  position: relative;
  width: 280px;
  max-width: 100%;
}

.search > .input {
  height: var(--control-h-compact);
  padding-left: 40px;
}

.search-icon {
  position: absolute;
  top: 12px;
  left: 12px;
  color: var(--ink-500);
  pointer-events: none;
}

/* Checkbox rows: native box, navy accent, at least 44 tall, never ticked by default. */
.check {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-height: var(--target);
  padding: 10px 0;
  cursor: pointer;
}

.check-input {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 2px 0 0;
  accent-color: var(--navy-800);
  cursor: pointer;
}

.check-text {
  font-size: 15px;
  line-height: 24px;
  color: var(--ink-900);
}

/* Segmented control: radio inputs or links, 44 tall, selected is navy. */
.segmented {
  display: inline-flex;
  align-self: flex-start;
  overflow: hidden;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-control);
  background: var(--white);
}

.segmented-item {
  position: relative;
  display: flex;
}

.segmented-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.segmented-label,
.segmented > a {
  display: flex;
  flex: 1;
  align-items: center;
  justify-content: center;
  height: var(--target);
  padding: 0 16px;
  background: var(--white);
  color: var(--ink-700);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.segmented-item + .segmented-item .segmented-label,
.segmented > a + a {
  border-left: 1px solid var(--ink-300);
}

.segmented-label:hover,
.segmented > a:hover {
  background: var(--ink-100);
  color: var(--ink-700);
}

.segmented-input:checked + .segmented-label,
.segmented > a[aria-current="page"] {
  background: var(--navy-800);
  color: var(--white);
  font-weight: 600;
}

.segmented-input:focus-visible + .segmented-label {
  outline: 2px solid var(--navy-800);
  outline-offset: -4px;
}

.segmented > a:focus-visible {
  outline-offset: -4px;
}

.segmented-fill {
  display: grid;
  grid-auto-columns: minmax(0, 1fr);
  grid-auto-flow: column;
  align-self: stretch;
}

/* Switch: a checkbox with role="switch"; the track is its second label. */
.switch-row {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 56px;
}

.switch-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.switch-label {
  font-size: 15px;
  line-height: 22px;
  font-weight: 500;
  color: var(--ink-900);
}

.switch-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.switch {
  position: relative;
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--target);
  height: var(--target);
  cursor: pointer;
}

.switch::before {
  content: "";
  display: block;
  width: 40px;
  height: 24px;
  border: 1px solid var(--ink-400);
  border-radius: var(--radius-control);
  background: var(--white);
}

.switch::after {
  content: "";
  position: absolute;
  top: 14px;
  left: 6px;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-control);
  background: var(--ink-500);
}

.switch-input:checked + .switch::before {
  border-color: var(--navy-800);
  background: var(--navy-800);
}

.switch-input:checked + .switch::after {
  left: 22px;
  background: var(--white);
}

.switch-input:focus-visible + .switch {
  outline: 2px solid var(--navy-800);
  outline-offset: 2px;
  border-radius: var(--radius-control);
}

/* File drop: the native input stays focusable; base.js shows the chosen name. */
.file-drop {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 120px;
  padding: 16px;
  border: 1px dashed var(--ink-400);
  border-radius: var(--radius-card);
  background: var(--white);
  text-align: center;
  cursor: pointer;
}

.file-drop:hover {
  background: var(--ink-50);
}

.file-drop:focus-within {
  outline: 2px solid var(--navy-800);
  outline-offset: 2px;
}

.file-drop-icon {
  color: var(--navy-900);
}

.file-drop-title {
  font-size: 15px;
  line-height: 20px;
  font-weight: 500;
  color: var(--navy-800);
}

.file-drop-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.file-drop-name {
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-900);
  overflow-wrap: anywhere;
}

.divider-or {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 13px;
  line-height: 20px;
  color: var(--ink-500);
}

.divider-or::before,
.divider-or::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--ink-200);
}

/* Continue with Google: the outline button with Google's own colored mark. */
.btn-google {
  border-color: var(--ink-400);
  background: var(--white);
  color: var(--ink-900);
}

.btn-google:hover {
  background: var(--ink-50);
  color: var(--ink-900);
}

/* 11. Booking: day cells, day chips, time slots. Client time first, Carlos's second. */

.calendar {
  display: grid;
  grid-template-columns: repeat(7, 48px);
  gap: 6px;
}

.calendar-wd {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 24px;
}

.day {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink-400);
  font-family: var(--font-sans);
  font-size: 15px;
  line-height: 20px;
  font-weight: 400;
  text-decoration: none;
}

.day-open {
  border-color: var(--ink-300);
  background: var(--white);
  color: var(--navy-800);
  font-weight: 500;
  cursor: pointer;
}

.day-open:hover {
  border-color: var(--navy-800);
  color: var(--navy-800);
}

.day-open:active {
  transform: scale(0.98);
}

.day-selected,
.day[aria-current="date"],
.day[aria-pressed="true"] {
  border-color: var(--navy-800);
  background: var(--navy-800);
  color: var(--white);
  font-weight: 600;
}

.day-selected:hover,
.day[aria-current="date"]:hover {
  color: var(--white);
}

.day-booked {
  color: var(--navy-800);
  font-weight: 500;
}

.day-dot {
  display: block;
  width: 4px;
  height: 4px;
  background: var(--navy-800);
}

.day-closed {
  color: var(--ink-400);
  cursor: default;
}

/* Phone week strip: weekday above the number, 56 tall. */
.day-strip {
  display: grid;
  grid-auto-columns: minmax(0, 1fr);
  grid-auto-flow: column;
  gap: 6px;
}

.day-chip {
  position: relative;
  gap: 2px;
  width: auto;
  min-width: 0;
  height: 56px;
  font-size: 17px;
  line-height: 22px;
}

.day-chip .day-wd {
  margin-right: -0.18em;
}

.day-chip .day-dot {
  position: absolute;
  bottom: 5px;
  left: 50%;
  margin-left: -2px;
}

.day-selected .micro,
.day[aria-current="date"] .micro {
  color: var(--ink-300);
}

.slots {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.slot {
  position: relative;
  display: block;
  cursor: pointer;
}

.slot-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.slot-body {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  height: 56px;
  padding: 0 16px;
  border: 1px solid var(--ink-300);
  border-radius: var(--radius-control);
  background: var(--white);
  text-align: left;
  text-decoration: none;
}

.slot:hover .slot-body,
a.slot-body:hover {
  border-color: var(--navy-800);
}

.slot:active .slot-body {
  transform: scale(0.98);
}

.slot-main {
  display: flex;
  flex-direction: column;
}

.slot-time {
  font-size: 17px;
  line-height: 22px;
  font-weight: 500;
  color: var(--navy-800);
}

.slot-alt {
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 16px;
  color: var(--ink-500);
  white-space: nowrap;
}

.slot-input:checked + .slot-body,
.slot-body.is-selected {
  border-color: var(--navy-800);
  background: var(--navy-800);
}

.slot-input:checked + .slot-body .slot-time,
.slot-body.is-selected .slot-time {
  color: var(--white);
}

.slot-input:checked + .slot-body :is(.slot-alt, .micro),
.slot-body.is-selected :is(.slot-alt, .micro) {
  color: var(--ink-300);
}

.slot-input:focus-visible + .slot-body {
  outline: 2px solid var(--navy-800);
  outline-offset: 2px;
}

.slot-input:disabled + .slot-body {
  border-color: var(--ink-200);
  background: var(--ink-50);
  cursor: default;
}

.slot-input:disabled + .slot-body :is(.slot-time, .slot-alt, .micro) {
  color: var(--ink-400);
}

/* The client's own booking: shown in navy outline, not choosable. */
.slot-booked .slot-input:disabled + .slot-body {
  border-color: var(--navy-800);
  background: var(--white);
  cursor: default;
}

.slot-booked .slot-input:disabled + .slot-body .slot-time {
  color: var(--navy-800);
}

.slot-booked .slot-input:disabled + .slot-body :is(.slot-alt, .micro) {
  color: var(--ink-500);
}

/* A day with its times, for lists of days without a month grid. */
.day-list {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.day-list-item {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* A panel that docks to the bottom of the screen on phones (booking confirm). */
.dock {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* 12. Feedback: empty states, toast, notices */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 40px 24px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  background: var(--white);
  text-align: center;
}

.empty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  color: var(--navy-900);
}

.empty-title {
  font-family: var(--font-serif);
  font-size: 22px;
  line-height: 29px;
  font-weight: 500;
  color: var(--navy-800);
}

/* Toast: the flash message after a redirect, bottom left, role status. */
.toast {
  position: fixed;
  bottom: 24px;
  left: 24px;
  z-index: 50;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  max-width: calc(100vw - 48px);
  min-height: 48px;
  padding: 0 4px 0 16px;
  border: 1px solid var(--ink-900);
  border-radius: var(--radius-card);
  background: var(--ink-900);
  color: var(--white);
}

.toast-text {
  padding: 12px 0;
  font-size: 14px;
  line-height: 20px;
}

/* The page a flash line names ('View'), in a new tab: the toast's one link. */
.toast-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--target);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  white-space: nowrap;
}

.toast-close {
  margin-left: auto;
}

.toast-error {
  border-color: var(--danger);
  background: var(--white);
  color: var(--danger);
}

.toast-error .toast-text {
  font-weight: 500;
}

.toast-error .icon-btn {
  color: var(--ink-700);
}

.toast-error .icon-btn:hover {
  background: var(--ink-100);
  color: var(--ink-900);
}

.toast:not(:has(.toast-close:not([hidden]))) {
  padding-right: 16px;
}

/* Notice: a failure or warning inside the page, never a color scale. */
.notice {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 56px;
  padding: 8px 8px 8px 16px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  background: var(--white);
}

.notice-mark {
  display: block;
  flex: none;
  width: 8px;
  height: 8px;
  background: var(--navy-900);
  transform: var(--slant);
}

.notice-text {
  font-size: 15px;
  line-height: 22px;
  font-weight: 500;
  color: var(--ink-900);
}

.notice-action {
  margin-left: auto;
}

.notice-error {
  border-color: var(--danger);
}

.notice-error .notice-mark {
  background: var(--danger);
}

.notice-error .notice-text {
  color: var(--danger);
}

/* 13. Shells: top bars, account menu, phone tab bar, footer. */

.topbar {
  position: relative;
  z-index: 20;
  flex: none;
  background: var(--ink-900);
  color: var(--white);
}

.topbar-inner {
  display: flex;
  align-items: center;
  height: var(--bar-h);
}

.brand {
  display: flex;
  flex: none;
  align-items: center;
  height: var(--target);
  margin-right: 48px;
  text-decoration: none;
}

.brand img {
  display: block;
  width: auto;
  height: 24px;
}

.brand-group {
  display: flex;
  flex: none;
  align-items: center;
  gap: 16px;
  margin-right: 48px;
}

.brand-group .brand {
  margin-right: 0;
}

.admin-tag {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 8px;
  border: 1px solid var(--white-24);
  border-radius: var(--radius-control);
  color: var(--ink-300);
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.topbar-nav {
  display: flex;
  flex: 1;
  align-items: center;
  min-width: 0;
  height: var(--bar-h);
}

.tabs {
  display: flex;
  align-items: center;
  gap: 32px;
  height: 100%;
}

.tabs-end {
  margin-left: auto;
}

/* The admin bar's two groups keep at least one tab gap between them when the row is full: with Research
   in it, the English row needs about 1060 px at 32 px gaps, 1003 px at 24 px with the Forum dot, so from 1024
   to 1199 px the gaps narrow to 24 px. The Spanish row (Investigación, Invitaciones) needs about 1046 px at
   24 px with the dot and 990 px at 16 px, so up to 1099 px its gaps narrow to 16 px; a classic scrollbar's
   17 px still fits in both. Under 1024 px the tabs take their own row (below). */
@media (min-width: 1024px) {
  .shell-admin .topbar-nav {
    column-gap: 32px;
  }
}

@media (min-width: 1024px) and (max-width: 1199px) {
  .shell-admin .topbar-nav,
  .shell-admin .tabs {
    column-gap: 24px;
  }
}

@media (min-width: 1024px) and (max-width: 1099px) {
  :lang(es) .shell-admin .topbar-nav,
  :lang(es) .shell-admin .tabs {
    column-gap: 16px;
  }
}

/* The client bar since 2026-10-24 (owner decision): Home, Room, Course, Research and Skills after the logo; on the
   right Programs (.tabs-end), then the last group, Forum, the Tools menu and Substack (.tabs-more). P123 (the owner's
   Portfolio123 referral link, 2026-10-22) is the Tools menu's last item since 2026-10-23 (owner decision), so the
   level mark can show its word. Under 1200 px the avatar menu lists the last group instead (.menu-item-compact),
   P123 the last item of its Tools group; Programs stays, in Spanish down to 1024 px (below). The same tabs as before
   the new order, so the same widths: measured in IBM Plex Sans Medium 14 px with its 0.02em, both dots, the icons and
   one gap before Programs, against the container's room with a classic 17 px scrollbar (1240 px from 1305 px up, so
   at 1366 and 1440; 1215 px at 1280; 1135 px at 1200): the English row needs about 1073 px at 32 px gaps and 1009 px
   at 24 px, and with the level mark's full chip (the note beside .topbar-level) 1172 px and 1108 px, so from 1200 to
   1279 px its gaps narrow to 24 px (1108 of 1135 at 1200; 1172 of 1215 at 1280 and of 1240 at 1366 and 1440). At
   1199 px the row without the last group needs 779 px of 1134, at 1024 px the same of 959 (the chip's 877). */
.tabs-more {
  margin-left: 32px;
}

@media (min-width: 1200px) and (max-width: 1279px) {
  .shell-client .tabs {
    gap: 24px;
  }

  .shell-client .tabs-more {
    margin-left: 24px;
  }
}

/* The client bar in Spanish (Inicio, Sala, Curso, Investigación, Habilidades · Programas · Foro, Herramientas with
   P123 in it since 2026-10-23, Substack, that order since 2026-10-24; measured the same way): the whole row needs
   about 1176 px at 32 px gaps, 1112 px at 24 px and 1048 px at 16 px; with the full chip 1274 px at 32 px gaps, more
   than the 1240 px it ever has, 1210 px at 24 px and 1146 px at 16 px. So its gaps are 24 px from 1280 px up (the
   chip's 1210 of 1240 at 1366 and 1440, of 1215 at 1280) and 16 px from 1200 to 1279 px, where the chip shows from
   1220 px and the mark is the bars alone below (1061 of 1135 at 1200; the note beside .topbar-level). At 1199 px the
   Spanish row without the last group needs 839 px of 1134, at 1024 px the same of 959 (the chip's 937). Under 1024 px
   Programas leaves for the avatar menu too (.menu-item-narrow-es): with it the row and the chip would need 881 px at
   24 px gaps, of 835 at 900, and with the bars alone at 16 px 756 px, of 703 at 768; without it the chip's 785 of 835
   at 900 and the bars' 668 of 703 at 768. Programas keeps one gap from Habilidades whenever the row is full. */
:lang(es) .shell-client .tabs-end {
  padding-left: 32px;
}

@media (min-width: 1200px) {
  :lang(es) .shell-client .tabs {
    gap: 24px;
  }

  :lang(es) .shell-client .tabs-end {
    padding-left: 24px;
  }

  :lang(es) .shell-client .tabs-more {
    margin-left: 24px;
  }
}

@media (min-width: 1200px) and (max-width: 1279px) {
  :lang(es) .shell-client .tabs {
    gap: 16px;
  }

  :lang(es) .shell-client .tabs-end {
    padding-left: 16px;
  }

  :lang(es) .shell-client .tabs-more {
    margin-left: 16px;
  }
}

.tab {
  display: flex;
  align-items: center;
  gap: 6px;
  height: var(--bar-h);
  padding-top: 2px;
  border-bottom: 2px solid transparent;
  color: var(--ink-300);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  letter-spacing: 0.02em;
  text-decoration: none;
  white-space: nowrap;
}

.tab:hover {
  color: var(--white);
}

.tab[aria-current="page"] {
  border-bottom-color: var(--gold-500);
  color: var(--white);
}

.tab:focus-visible {
  outline-offset: -2px;
}

/* A small dot beside an item with news (Forum: a newer post in a topic the member wrote in). A dot,
   never a count: gold on the dark bar, navy in the white menu, and on phones also on the avatar,
   since Forum moves into its menu there. */
.nav-dot {
  display: inline-block;
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--gold-500);
}

.menu-item .nav-dot {
  background: var(--navy-800);
}

.nav-dot-avatar {
  position: absolute;
  top: 2px;
  right: 2px;
  display: none;
  width: 12px;
  height: 12px;
  border: 2px solid var(--ink-900);
}

/* The avatar menu's hidden words for a compact item's dot (Forum since 2026-10-24, owner decision; Research before): only where the item lives in the menu. */
.nav-dot-words-compact {
  display: none;
}

/* Tools in the client bar: a details disclosure styled as a tab, opening the account menu's panel. */
.nav-menu {
  position: relative;
}

.nav-menu-toggle {
  list-style: none;
  cursor: pointer;
}

.nav-menu-toggle::-webkit-details-marker {
  display: none;
}

.nav-menu[open] > .nav-menu-toggle {
  color: var(--white);
}

.nav-menu[open] > .nav-menu-toggle .icon {
  transform: rotate(180deg);
}

/* Under the bar, lined up with the label; two classes, so it wins over .menu-panel further down. */
.nav-menu > .nav-menu-panel {
  top: calc(100% + 4px);
  right: auto;
  left: -16px;
}

/* Account menu: a details disclosure, so it opens without JavaScript. */
.menu {
  position: relative;
  flex: none;
  margin-left: 24px;
}

/* The client's level mark immediately left of the avatar (2026-10-23, owner decision): 16 px after the last tab, and
   none between it and the avatar button, whose 44 px target already leaves 6 px around the 32 px tile. Measured as
   the row above (src/ui/test/client-bar.test.tsx): the full chip, up to 106 px for 'Full Program' (103 for
   'Intermediate'), fits from 900 px where the last group lives in the avatar menu (since the order of 2026-10-24 the
   English row with Programs then needs at most 821 px, the Spanish without it 785 px, of 835 at 900), and since P123
   moved into Tools (2026-10-23, owner decision)
   on the wide bar too: the English row needs at most 1108 px of 1135 at 1200 and 1172 of 1215 at 1280, the Spanish
   1210 of 1215 at 1280 and 1146 of 1155 at 1220. So it shows from 900 px up, the bar's own step, except in Spanish
   from 1200 to 1219 px, whose gaps are at their 16 px floor and where the row with the chip would need 1146 px of
   1135 at 1200 (it holds from 1212 px; 1220 keeps a margin for the browser's rounding, review of 2026-10-23).
   Elsewhere the bars alone, 13 px or the Full Program's framed 21 px, which take 13 px more than the menu's own
   margin at most and fit the Spanish row at 1200 (1061 of 1135) and at 768 (668 of 703), the English one with
   Programs at 768 (696 of 703). */
.topbar-level {
  display: flex;
  flex: none;
  align-items: center;
  margin-left: 16px;
}

.topbar-level + .menu {
  margin-left: 0;
}

@media (min-width: 900px) {
  .topbar-level .level-mark {
    gap: 6px;
    padding: 0 6px;
    border-width: 1px;
  }

  .topbar-level .level-mark-full {
    padding-left: 3px;
  }

  .topbar-level .level-mark-word {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
  }
}

/* The Spanish row from 1200 to 1219 px keeps the bars alone (the note above; 1279 px until the review of 2026-10-23):
   three classes, so they win over the full chip's two. */
@media (min-width: 1200px) and (max-width: 1219px) {
  :lang(es) .topbar-level .level-mark {
    gap: 0;
    padding: 0;
    border-width: 0;
  }

  :lang(es) .topbar-level .level-mark-word {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }
}

.menu-toggle {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--target);
  height: var(--target);
  border-radius: var(--radius-control);
  list-style: none;
}

.menu-toggle::-webkit-details-marker {
  display: none;
}

.menu-toggle:hover,
.menu[open] > .menu-toggle {
  background: var(--white-8);
}

.menu-panel {
  position: absolute;
  top: 58px;
  right: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  width: 200px;
  padding: 4px;
  border: 1px solid var(--ink-200);
  border-radius: var(--radius-card);
  background: var(--white);
  color: var(--ink-900);
}

.menu-form {
  display: flex;
  flex-direction: column;
}

.menu-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  height: var(--target);
  padding: 0 12px;
  border: 0;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink-900);
  font-size: 15px;
  line-height: 20px;
  font-weight: 400;
  text-align: left;
  text-decoration: none;
}

.menu-item:hover,
.menu-item:focus-visible {
  background: var(--ink-100);
  color: var(--ink-900);
}

.menu-item:focus-visible {
  outline-offset: -2px;
}

.menu-item[aria-current="page"] {
  font-weight: 600;
}

.menu-item-phone {
  display: none;
}

/* An item with a note under its label ('menu-item-note'). */
.menu-item-tall {
  height: auto;
  min-height: var(--target);
  padding-top: 8px;
  padding-bottom: 8px;
}

.menu-item-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.menu-item-note {
  font-size: 13px;
  line-height: 18px;
  color: var(--ink-500);
}

/* Items listed together under a small label (Tools in the avatar menu). */
.menu-group {
  display: flex;
  flex-direction: column;
}

.menu-label {
  padding: 8px 12px 4px;
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-500);
}

/* Listed in the avatar menu under 1200 px only, where the client bar leaves them out (Forum, Tools, Substack since
   2026-10-24); and on a Spanish page under 1024 px (Programas, section 15). */
.menu-item-compact,
.menu-item-narrow-es {
  display: none;
}

.page {
  flex: 1 0 auto;
  padding-top: 48px;
}

.page:focus {
  outline: none;
}

.shell-admin .page {
  padding-bottom: 80px;
}

/* Signed-out pages: no bar, the page decides its own frame. */
.bare {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
}

.bare:focus {
  outline: none;
}

.site-footer {
  flex: none;
  margin-top: 80px;
}

.site-footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 8px 24px;
  min-height: 88px;
  border-top: 1px solid var(--ink-200);
}

.legal-nav {
  display: flex;
  align-items: center;
  gap: 24px;
}

.legal-nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--target);
  font-size: 13px;
  line-height: 20px;
  font-weight: 500;
}

/* The footer's language switch ('English · Español', owner decision 2026-10-20), beside Privacy and Terms once
   clients choose their language: the language read now as plain ink, the other a button that reads like the legal
   links beside it, with their 44 px target. In the auth panel it sits under the footer line. */
.site-footer-end {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 24px;
}

.lang-switch {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  line-height: 20px;
  font-weight: 500;
}

.lang-switch-current {
  color: var(--ink-900);
}

.lang-switch-sep {
  color: var(--ink-500);
}

.lang-switch-option {
  display: inline-flex;
  align-items: center;
  min-height: var(--target);
  padding: 0;
  border: 0;
  background: none;
  color: var(--navy-800);
  text-decoration-line: underline;
  text-decoration-color: var(--ink-300);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.lang-switch-option:hover {
  color: var(--navy-700);
  text-decoration-color: currentColor;
}

/* The order page's 'Español' (Checkout.dc.html, TRLGDCU art. 60.4) at the end of its slim bar: the other
   language as a text link on the dark ground, 14/20 weight 500, with the 44 px target. */
.topbar-lang {
  display: flex;
  margin-left: auto;
}

.topbar-lang-option {
  display: inline-flex;
  align-items: center;
  min-height: var(--target);
  padding: 0;
  border: 0;
  background: none;
  color: var(--white);
  font-size: 14px;
  line-height: 20px;
  font-weight: 500;
  text-decoration-line: underline;
  text-decoration-color: var(--white-40);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.topbar-lang-option:hover {
  text-decoration-color: currentColor;
}

/* The switch on a dark ground (the level moment's footer): white as the legal links there. */
[data-ground="dark"] .lang-switch-current,
[data-ground="dark"] .lang-switch-option,
[data-ground="dark"] .lang-switch-option:hover {
  color: var(--white);
}

[data-ground="dark"] .lang-switch-sep {
  color: var(--ink-300);
}

[data-ground="dark"] .lang-switch-option {
  text-decoration-color: var(--white-40);
}

[data-ground="dark"] .lang-switch-option:hover {
  text-decoration-color: currentColor;
}

/* Phone tab bar: shown under 768 px only. */
.tabbar {
  display: none;
}

.tabbar-item {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  color: var(--ink-500);
  font-size: 11px;
  line-height: 14px;
  font-weight: 500;
  text-decoration: none;
}

.tabbar-item:hover {
  color: var(--navy-800);
}

.tabbar-item[aria-current="page"] {
  color: var(--navy-800);
  font-weight: 600;
}

.tabbar-item[aria-current="page"]::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 50%;
  width: 24px;
  height: 2px;
  margin-left: -12px;
  background: var(--navy-800);
}

.tabbar-item:focus-visible {
  outline-offset: -4px;
}

/* 14. Auth and error pages */

.auth {
  display: grid;
  flex: 1 0 auto;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  min-height: 100vh;
}

.auth-brand {
  display: flex;
  flex-direction: column;
  padding: 0 40px 24px 100px;
  background: var(--ink-900);
  color: var(--white);
}

.auth-bar {
  display: flex;
  align-items: center;
  height: var(--bar-h);
}

.auth-bar .brand {
  margin-right: 0;
}

.auth-moment {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin: auto 0;
  padding: 48px 0;
}

.auth-moment .display {
  margin-top: 24px;
}

.auth-line {
  margin-top: 16px;
  font-size: 17px;
  line-height: 24px;
  color: var(--ink-300);
}

/* The 9 x 4 step grid in one state only: decorative, it carries no data. */
.auth-motif {
  display: grid;
  grid-template-columns: repeat(9, 28px);
  grid-auto-rows: 28px;
  gap: 12px;
  align-self: flex-start;
}

.auth-motif > span {
  display: block;
  background: var(--navy-700);
  transform: var(--slant);
}

.auth-panel {
  display: flex;
  flex-direction: column;
  padding: clamp(48px, 18vh, 176px) 24px 24px;
  background: var(--white);
}

.auth-column {
  display: flex;
  flex-direction: column;
  gap: 24px;
  width: 100%;
  max-width: 360px;
  margin: 0 auto;
}

.auth-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.auth-form .btn-primary {
  margin-top: 16px;
}

.auth-forgot {
  align-self: center;
  margin-top: -16px;
}

.auth-note {
  align-self: center;
  text-align: center;
}

.auth-footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-top: auto;
  padding-top: 48px;
  text-align: center;
}

/* The page footer is inside the auth panel there. */
body:has(.auth) > .site-footer {
  display: none;
}

body:has(.auth) .toast {
  top: 24px;
  right: 24px;
  bottom: auto;
  left: auto;
}

.error-page {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
  max-width: 560px;
}

.error-brand {
  display: none;
}

.shell-none .error-page {
  width: 100%;
  margin: 0 auto;
  padding: 96px var(--gutter) 0;
}

.shell-none .error-brand {
  display: block;
  margin-bottom: 32px;
}

/* 15. Responsive: desktop first; phones get the MobileHome and MobileBook layouts. */

@media (max-width: 1199px) {
  /* The client bar keeps Forum, Tools (P123 in it) and Substack off (2026-10-24, owner decision; Research, a left
     tab now, stays); the avatar menu lists them, P123 the last item of its Tools group. */
  .shell-client .tabs-more {
    display: none;
  }

  .menu-item-compact {
    display: flex;
  }

  /* Forum moved into the avatar menu: its dot shows on the avatar, as Research's does on phones, and the
     menu's name says so. */
  .nav-dot-avatar-compact {
    display: block;
  }

  .nav-dot-words-compact {
    display: inline;
  }
}

@media (max-width: 1023px) {
  .grid > [class*="span-"] {
    grid-column: 1 / -1;
  }

  .grid > .md-span-6 {
    grid-column: span 6;
  }

  .brand,
  .brand-group {
    margin-right: 32px;
  }

  .tabs {
    gap: 24px;
  }

  /* The Spanish client bar leaves Programas to the avatar menu too (2026-10-24, owner decision): with Investigación
     a left tab, the row and Programas no longer fit at 900 px with the chip nor at 768 px with the bars (the note
     in section 13). */
  :lang(es) .shell-client .tabs-end {
    display: none;
  }

  :lang(es) .menu-item-narrow-es {
    display: flex;
  }

  /* Admin tabs drop to a second row that scrolls sideways. */
  .shell-admin .topbar-inner {
    flex-wrap: wrap;
    height: auto;
    min-height: var(--bar-h);
  }

  .shell-admin .topbar-inner > .brand-group {
    height: var(--bar-h);
  }

  .shell-admin .topbar-nav {
    order: 3;
    flex-basis: 100%;
    height: 48px;
    overflow-x: auto;
    scrollbar-width: none;
  }

  .shell-admin .topbar-nav .tab {
    height: 48px;
  }

  .shell-admin .tabs-end {
    margin-left: 24px;
  }

  .shell-admin .menu {
    margin-left: auto;
  }

  .auth {
    grid-template-columns: minmax(0, 1fr);
  }

  .auth-brand {
    padding: 0 var(--gutter) 32px;
  }

  .auth-moment {
    margin: 0;
    padding: 32px 0 0;
  }

  .auth-motif {
    display: none;
  }

  .auth-panel {
    padding-top: 40px;
  }

  .hero {
    grid-template-columns: minmax(0, 1fr) 1px minmax(0, 240px);
    column-gap: 32px;
    padding: 32px;
  }
}

/* The client bar from 768 to 899 px (its note is beside .tabs-more): 16 px gaps. The Spanish row needed them first;
   the English row takes them too since the level mark (2026-10-23), with which its 24 px gaps no longer fit at 768
   (the note beside .topbar-level). Programas is in the Spanish avatar menu here since 2026-10-24, so its padding
   went. */
@media (min-width: 768px) and (max-width: 899px) {
  .shell-client .tabs {
    gap: 16px;
  }

  :lang(es) .shell-client .tabs {
    gap: 16px;
  }
}

@media (max-width: 767px) {
  :root {
    --gutter: 16px;
    --bar-h: 56px;
  }

  body.shell-client {
    padding-bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  }

  :where(h1),
  .h1 {
    font-size: 28px;
    line-height: 32px;
  }

  .display {
    font-size: 40px;
    line-height: 44px;
  }

  .grid {
    row-gap: 16px;
  }

  .grid > .md-span-6 {
    grid-column: 1 / -1;
  }

  .form-grid {
    grid-template-columns: minmax(0, 1fr);
  }

  .page {
    padding-top: 24px;
  }

  .site-footer {
    margin-top: 48px;
  }

  .site-footer-inner {
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    padding: 16px 0;
  }

  .brand,
  .brand-group {
    margin-right: 16px;
  }

  .topbar-inner {
    padding-right: 6px;
  }

  .shell-client .topbar-nav {
    display: none;
  }

  .shell-client .menu {
    margin-left: auto;
  }

  /* With a level mark, the mark takes the room on the left and the avatar follows it (the bars alone here). */
  .shell-client .topbar-level {
    margin-left: auto;
  }

  .shell-client .topbar-level + .menu {
    margin-left: 0;
  }

  .menu-panel {
    top: 50px;
  }

  /* The avatar menu stops above the tab bar and scrolls inside (a phone held sideways is 375 px tall);
     the second line is for browsers that know dvh, the height left by the browser's own toolbars. */
  .shell-client .menu > .menu-panel {
    max-height: calc(100vh - var(--bar-h) - var(--tabbar-h) - env(safe-area-inset-bottom) - 8px);
    max-height: calc(100dvh - var(--bar-h) - var(--tabbar-h) - env(safe-area-inset-bottom) - 8px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }

  /* Its items keep their height and scroll rather than squeeze into the room. */
  .shell-client .menu > .menu-panel > * {
    flex-shrink: 0;
  }

  .menu-item-phone {
    display: flex;
  }

  .nav-dot-avatar {
    display: block;
  }

  .tabbar {
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    z-index: 30;
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    height: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
    padding-bottom: env(safe-area-inset-bottom);
    border-top: 1px solid var(--ink-200);
    background: var(--white);
  }

  .toast {
    bottom: 16px;
    left: 16px;
    max-width: calc(100vw - 32px);
  }

  .shell-client .toast {
    bottom: calc(var(--tabbar-h) + 16px + env(safe-area-inset-bottom));
  }

  body:has(.auth) .toast {
    top: auto;
    right: 16px;
    bottom: 16px;
  }

  .dock {
    position: sticky;
    bottom: 0;
    z-index: 5;
    margin: 0 calc(-1 * var(--gutter));
    padding: 16px var(--gutter);
    border-top: 1px solid var(--ink-200);
    background: var(--white);
  }

  .shell-client .dock {
    bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom));
  }

  /* MobileHome hero: one column, a hairline between the two halves. */
  .hero {
    grid-template-columns: minmax(0, 1fr);
    min-height: 0;
    padding: 24px;
  }

  .hero-start,
  .hero-end {
    gap: 16px;
  }

  .hero-divider {
    height: 1px;
    margin: 16px 0;
  }

  .hero .numeral-xl {
    font-size: 64px;
    line-height: 52px;
  }

  .hero .numeral-l {
    font-size: 40px;
    line-height: 40px;
  }

  .card-roomy,
  .card-dark {
    padding: 24px;
  }

  .search {
    width: 100%;
  }

  .calendar {
    grid-template-columns: repeat(7, minmax(0, 1fr));
  }

  .calendar .day {
    width: 100%;
  }

  .auth-panel {
    padding: 32px var(--gutter) 24px;
  }

  .auth-line {
    font-size: 15px;
  }

  .shell-none .error-page {
    padding-top: 48px;
  }

  .facts {
    grid-template-columns: minmax(0, 1fr);
    row-gap: 4px;
  }

  .facts dd + dt {
    margin-top: 8px;
  }
}

/* Under 480 px every level mark keeps its bars and drops the word (the canvas's rule; the word stays for screen
   readers, as in the top bar's compact form, section 8). */
@media (max-width: 479px) {
  .level-mark {
    gap: 0;
    padding: 0;
    border-width: 0;
    background: transparent;
  }

  .level-mark-word {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }
}

/* 16. Motion: press 0.98 in 80 ms, hover 200 ms, crossfade 160 ms, sheets
   280 ms, the gold hairline (dark grounds) and the certificate's navy rule
   drawn once in 1100 ms. No loops or count-ups. */

.xfade {
  transition: opacity var(--t-xfade) var(--ease-standard);
}

@media (prefers-reduced-motion: no-preference) {
  .gold-rule-draw {
    animation: rule-draw var(--t-line) var(--ease-out) both;
  }

  dialog.sheet[open] {
    animation: sheet-in var(--t-sheet) var(--ease-out);
  }

  /* The end of a Research post (2026-10-29, research-gamify canvas): the shelf's new segment fills after the gold
     hairline, then the series step it opened pops in. Once each, never looped. */
  .bar-fill-draw {
    transform-origin: left center;
    animation: rule-draw var(--t-fill) var(--ease-out) var(--t-fill-delay) both;
  }

  .mark-pop {
    animation: mark-pop var(--t-sheet) var(--ease-out) var(--t-pop-delay) both;
  }
}

/* The certificate's navy rule under the name draws the same way on the owner's first view (2026-10-22, owner
   decision: direction A), on screens only: a printed certificate always shows the rule whole. */
@media screen and (prefers-reduced-motion: no-preference) {
  .cert-doc-rule-draw {
    animation: rule-draw var(--t-line) var(--ease-out) both;
  }
}

@keyframes rule-draw {
  from {
    transform: scaleX(0);
  }

  to {
    transform: scaleX(1);
  }
}

@keyframes mark-pop {
  from {
    transform: scale(0.6);
    opacity: 0;
  }

  to {
    transform: none;
    opacity: 1;
  }
}

@keyframes sheet-in {
  from {
    transform: translateX(100%);
  }

  to {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition: none !important;
    animation: none !important;
    scroll-behavior: auto !important;
  }
}
