/* Yojobook tokens and base components, from the Design Brief (docs/design-briefs/2026-10-23_1345_yojobook.md).
   The look's values reach a page through data-look on <body> and the provider's colour through a
   style attribute written by the Worker; no hex value appears in a component. */

/* ---- Fonts: self-hosted, Latin subset, OFL (U2) ------------------------------------------------- */

@font-face {
  font-family: "Figtree";
  src: url("/f/figtree-latin-var.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329,
    U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Bricolage Grotesque";
  src: url("/f/bricolage-latin-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Fraunces";
  src: url("/f/fraunces-latin-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Lora";
  src: url("/f/lora-latin-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}

/* ---- The platform's neutral look ------------------------------------------------------------------ */

:root {
  --color-primary: #1B1B1F;
  --color-primary-hover: #2E2E35;
  --color-primary-active: #000000;
  --color-on-primary: #FFFFFF;
  --color-secondary: #FFFFFF;
  --color-accent: var(--look-accent-ws, #1B1B1F);
  --color-accent-hover: color-mix(in srgb, var(--color-accent) 88%, #000);
  --color-on-accent: #FFFFFF;
  --color-surface: #F6F5F2;
  --color-surface-elevated: #FFFFFF;
  --color-surface-overlay: rgba(27, 27, 31, 0.48);
  --color-text-primary: #1B1B1F;
  --color-text-secondary: #5B5B66;
  --color-text-muted: #5B5B66;
  --color-success: #1F5A2E;
  --color-success-tint: #E3EFE6;
  --color-warning: #7A4F00;
  --color-warning-tint: #FBF0D9;
  --color-error: #8A2E1C;
  --color-error-tint: #FBE7E2;
  --color-info: #1E4E8C;
  --color-info-tint: #E4ECF7;
  --color-border: #E3E1DB;
  --color-border-strong: #85817A;

  --font-display: var(--look-heading, "Bricolage Grotesque"), "Figtree", ui-sans-serif, system-ui, sans-serif;
  --font-body: "Figtree", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-size-xs: 0.75rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.25rem;
  --font-size-xl: 1.5rem;
  --font-size-2xl: 2rem;
  --font-size-3xl: clamp(2.25rem, 8vw, 3rem);
  --font-weight-normal: 400;
  --font-weight-medium: 500;
  --font-weight-semibold: 600;
  --font-weight-bold: 700;
  --line-height-tight: 1.15;
  --line-height-normal: 1.45;
  --line-height-relaxed: 1.6;

  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;
  --space-16: 64px;
  --page-gutter: 16px;
  --tap-min: 44px;
  /* Her workspace's sticky header (U4), on the root so the scroll rule below can read it (F267). */
  --ws-header-height: 56px;

  --radius-sm: 6px;
  --radius-md: var(--look-radius, 12px);
  --radius-lg: 20px;
  --radius-full: 9999px;
  --shadow-sm: 0 1px 2px rgba(27, 27, 31, 0.06);
  --shadow-md: 0 4px 12px rgba(27, 27, 31, 0.08);
  --shadow-lg: 0 -8px 24px rgba(27, 27, 31, 0.12);
}

/* ---- The four looks (her page, her booking flow, her statement) ----------------------------------- */

[data-look="clear"] {
  --look-ground: #FFFFFF;
  --look-surface: #F3F4F6;
  --look-ink: #111827;
  --look-muted: #4B5563;
  --look-border: #D1D5DB;
  --look-border-strong: #7C818B;
  --look-accent: #1D4ED8;
  --look-on-accent: #FFFFFF;
  --look-heading: "Bricolage Grotesque";
  --look-radius: 10px;
}
[data-look="soft"] {
  --look-ground: #FBF7F2;
  --look-surface: #FFFFFF;
  --look-ink: #2B2A33;
  --look-muted: #5F5B66;
  --look-border: #E8DFD6;
  --look-border-strong: #857A73;
  --look-accent: #A54A6C;
  --look-on-accent: #FFFFFF;
  --look-heading: "Fraunces";
  --look-radius: 18px;
}
[data-look="chalkboard"] {
  --look-ground: #1F3A34;
  --look-surface: #27463F;
  --look-ink: #F4F1E8;
  --look-muted: #C9D3CC;
  --look-border: #3B5A52;
  --look-border-strong: #88A69C;
  --look-accent: #F2C14E;
  --look-on-accent: #1F3A34;
  --look-heading: "Bricolage Grotesque";
  --look-radius: 8px;
}
[data-look="meadow"] {
  --look-ground: #F1F5EE;
  --look-surface: #FFFFFF;
  --look-ink: #1F2A22;
  --look-muted: #4F5E53;
  --look-border: #D6DFD2;
  --look-border-strong: #718075;
  --look-accent: #2F6B3A;
  --look-on-accent: #FFFFFF;
  --look-heading: "Lora";
  --look-radius: 14px;
}

/* Her pages wear her look. A custom property is resolved where it is declared, so the two that
   read the look are declared again here, where her heading font and radius are known. */
body[data-look] {
  --font-display: var(--look-heading), "Figtree", ui-sans-serif, system-ui, sans-serif;
  --radius-md: var(--look-radius);
  background: var(--look-ground);
  color: var(--look-ink);
}

/* U5: a Chalkboard provider's workspace uses Chalkboard's ground as its accent. */
.workspace[data-look="chalkboard"] {
  --look-accent-ws: #1F3A34;
}

/* ---- Base ------------------------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-padding-bottom: 96px;
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--color-surface);
  color: var(--color-text-primary);
  font-family: var(--font-body);
  font-size: var(--font-size-base);
  line-height: var(--line-height-normal);
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

h1,
h2,
h3 {
  margin: 0;
  line-height: var(--line-height-tight);
  font-weight: var(--font-weight-bold);
}

h1 {
  font-size: var(--font-size-xl);
}

p {
  margin: 0;
}

a {
  color: inherit;
  text-underline-offset: 3px;
}

/* A 2px ring offset by 2px, in ink (Accessibility: Focus). */
:focus-visible {
  outline: 2px solid var(--color-text-primary);
  outline-offset: 2px;
}
body[data-look] :focus-visible {
  outline-color: var(--look-ink);
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -100px;
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-elevated);
  border-radius: var(--radius-sm);
  z-index: 10;
}
.skip-link:focus {
  top: var(--space-4);
}

/* A phrase kept on one line, such as a class's grades ("Grade 4–7"), so it never breaks after its
   word or its dash (F170). */
.nowrap {
  white-space: nowrap;
}

/* ---- Platform chrome ---------------------------------------------------------------------------------- */

.platform-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 56px;
  padding: 0 var(--page-gutter);
}

.wordmark {
  margin-right: auto;
  font-weight: var(--font-weight-semibold);
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
}

/* "Sign out" in the platform header during onboarding (F92): a text button with the full 44px
   target, like the language switch. */
.header-out {
  margin: 0;
}
.header-out button {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: 0 var(--space-3);
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  text-decoration: underline;
  text-underline-offset: 3px;
  white-space: nowrap;
  cursor: pointer;
}

/* A text link that is a main way on: the full 44px target (WCAG 2.5.8; the brief's tap size). */
.tap-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  min-width: var(--tap-min);
}
/* The same link as a form's button, where what it carries must not go in a query string (F150). */
button.tap-link {
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.lang-switch {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: 0 var(--space-3);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
}

.lang-switch-form {
  margin: 0;
}
button.lang-switch {
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.page {
  max-width: 480px;
  margin: 0 auto;
  padding: var(--space-4) var(--page-gutter) var(--space-12);
}
.page:focus {
  outline: none;
}

.card {
  background: var(--color-surface-elevated);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  padding: var(--space-6) var(--space-4);
}

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

.secondary {
  color: var(--color-text-secondary);
}

/* ---- P1 landing and P2 line choice ---------------------------------------------------------------------- */

/* The landing page's headline only: Bricolage Grotesque on the neutral look. */
.display {
  font-family: var(--font-display);
  font-size: var(--font-size-3xl);
  letter-spacing: -0.01em;
}

.landing {
  padding-top: var(--space-8);
}
.landing .lead {
  font-size: var(--font-size-lg);
  line-height: var(--line-height-relaxed);
}

.line-cards {
  list-style: none;
  margin: 0;
  padding: 0;
}
.line-cards > li + li {
  margin-top: var(--space-3);
}

.line-card {
  display: block;
  min-height: 112px;
  padding: var(--space-6) var(--space-4);
  background: var(--color-surface-elevated);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  text-decoration: none;
  transition: border-color 150ms ease-out;
}
.line-card > .secondary {
  display: block;
}
.line-card[href]:hover {
  border-color: var(--color-primary);
}
.line-card[aria-disabled="true"] {
  border-color: var(--color-border);
  background: transparent;
}

.line-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
}
.line-card-name {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
}

/* A word in a pill, never colour alone. */
.badge {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
}
.badge.live {
  background: var(--color-success-tint);
  border-color: var(--color-success);
  color: var(--color-success);
}

/* ---- Forms -------------------------------------------------------------------------------------------- */

.field label {
  display: block;
  font-weight: var(--font-weight-medium);
  margin-bottom: var(--space-2);
}

.field input,
.field select,
.field textarea {
  display: block;
  width: 100%;
  min-height: 48px;
  padding: var(--space-3);
  font: inherit;
  font-size: var(--font-size-base);
  color: var(--color-text-primary);
  background: var(--color-surface-elevated);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  transition: border-color 150ms ease-out;
}
body[data-look] .field input {
  border-color: var(--look-border-strong);
}
/* Date and time boxes keep to their column on an iPhone too (F259). Safari's native look for them
   on iOS sets a minimum width of its own and measures the box without its padding and border, so
   a full-width box ran 26px past its column, and past the card on the right; without that look
   they take the field's own width and edges, as in Chrome. */
.field input[type="date"],
.field input[type="time"] {
  -webkit-appearance: none;
  appearance: none;
  min-width: 0;
}
.field input::-webkit-date-and-time-value {
  text-align: left;
}
.field textarea {
  resize: vertical;
}

.field input[aria-invalid="true"],
.field select[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: var(--color-error);
  border-width: 2px;
}

.code-input {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.3em;
  font-size: var(--font-size-lg) !important;
}

.hint,
.note {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
}
.field .hint {
  margin-bottom: var(--space-2);
}
.field .note {
  margin-top: var(--space-2);
}

/* Her page address after the site's own, as one field. */
.address-input {
  display: flex;
}
.address-host {
  display: flex;
  align-items: center;
  padding: 0 var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-right: 0;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text-secondary);
  font-size: var(--font-size-sm);
  white-space: nowrap;
}
.address-input input {
  min-width: 0;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}

.field-error {
  display: flex;
  gap: var(--space-2);
  align-items: flex-start;
  margin-top: var(--space-2);
  color: var(--color-error);
  font-size: var(--font-size-sm);
}
.field-error .icon {
  flex: none;
  width: 20px;
  height: 20px;
}

/* ---- Buttons ------------------------------------------------------------------------------------------ */

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: var(--space-3) var(--space-6);
  font: inherit;
  font-weight: var(--font-weight-semibold);
  text-align: center;
  text-decoration: none;
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background-color 150ms ease-out, border-color 150ms ease-out;
}
.button.primary {
  width: 100%;
  background: var(--color-primary);
  color: var(--color-on-primary);
  border: 1px solid var(--color-primary);
}
.button.primary:hover {
  background: var(--color-primary-hover);
}
.button.primary:active {
  background: var(--color-primary-active);
}
.button.secondary {
  background: var(--color-secondary);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-strong);
}

/* The one main action, pinned in the thumb zone above the home indicator. */
.action-bar {
  position: sticky;
  bottom: 0;
  padding: var(--space-3) 0 calc(var(--space-3) + env(safe-area-inset-bottom));
  background: var(--color-surface-elevated);
}

/* "Send a new code" after 30 seconds, without script. */
.reveal-after-30s {
  visibility: hidden;
  animation: reveal 0s linear 30s forwards;
}
@keyframes reveal {
  to {
    visibility: visible;
  }
}

/* ---- B1 her page and B6 her house rules ------------------------------------------------------------- */

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

body[data-look] .skip-link {
  background: var(--look-surface);
}
body[data-look] .note {
  color: var(--look-muted);
}

/* Her band scrolls away with the page; its text lines up with the 480px column below. */
.her-band {
  background: var(--look-accent);
  color: var(--look-on-accent);
}
.her-band-inner,
.her-foot {
  max-width: 480px;
  margin: 0 auto;
  padding: var(--space-6) var(--page-gutter);
}
.her-band-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.her-band .lang-switch {
  flex: none;
  color: inherit;
}
/* On her accent the ring takes the band's text colour, which keeps 3:1 against it. */
body[data-look] .her-band :focus-visible {
  outline-color: var(--look-on-accent);
}
.her-name {
  font-family: var(--font-display);
  font-size: var(--font-size-2xl);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
  overflow-wrap: anywhere;
}
.her-foot {
  text-align: center;
  font-size: var(--font-size-sm);
  color: var(--look-muted);
}

/* The credit line (ruling of 28 Oct, G), last on every page: small, in the muted text colour, 6.15:1
   on the neutral ground. On her pages it is the second line of her foot, in her look's muted on its
   ground (6.20 to 7.98:1). */
.credit-foot {
  padding: 0 var(--page-gutter) var(--space-6);
  text-align: center;
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

.welcome {
  font-size: var(--font-size-lg);
  line-height: var(--line-height-relaxed);
}
.her-section {
  margin-top: var(--space-8);
}
.her-section h1,
.her-section h2,
.her-section h3 {
  font-family: var(--font-display);
}
.her-section h1,
.her-section h2 {
  font-size: var(--font-size-lg);
  margin-bottom: var(--space-3);
}
.her-section h3 {
  font-size: var(--font-size-base);
}

.plain-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
/* A list inside a stack keeps the stack's gap above it (F4 runtime check, cosmetic 2). */
.stack > * + .plain-list {
  margin-top: var(--space-4);
}
.her-card,
.session-row {
  padding: var(--space-4);
  background: var(--look-surface);
  border-radius: var(--radius-md);
}
.plain-list > li + li {
  margin-top: var(--space-2);
}
.facts {
  font-size: var(--font-size-sm);
  color: var(--look-muted);
}
.her-card .facts {
  margin-top: var(--space-1);
}

.month-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.month-nav a,
.month-nav-gap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
}
.month-name {
  font-weight: var(--font-weight-semibold);
}

/* Seven columns; each day at least 44px tall, and at least 40px wide at 360px (12px gutter). */
.month-grid {
  width: calc(100% + 8px);
  margin: 0 -4px;
  table-layout: fixed;
  border-spacing: 4px;
}
.month-grid th {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--look-muted);
}
.month-grid td {
  padding: 0;
}
.day {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap-min);
  border: 1px solid var(--look-border);
  border-radius: var(--radius-sm);
  color: var(--look-muted);
  font-variant-numeric: tabular-nums;
}
a.day {
  background: var(--look-accent);
  border-color: var(--look-accent);
  color: var(--look-on-accent);
  font-weight: var(--font-weight-bold);
  text-decoration: none;
}
.day[aria-current] {
  border-width: 2px;
  border-color: var(--look-ink);
}
.month-grid + .note,
.none {
  margin-top: var(--space-2);
}

.day-group {
  margin-top: var(--space-6);
}
/* On her page a day's anchor lands with a little room above it; in her workspace the one scroll
   rule gives that room already (F267). */
body:not(.workspace) .day-group {
  scroll-margin-top: var(--space-4);
}
.day-group > h3 {
  margin-bottom: var(--space-2);
}
.session-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.session-time {
  font-weight: var(--font-weight-semibold);
  font-variant-numeric: tabular-nums;
}

/* A word in a pill: her accent while seats are open, the divider colour with ink when full. */
.pill {
  flex: none;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-full);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  white-space: nowrap;
}
.pill.open {
  background: var(--look-accent);
  color: var(--look-on-accent);
}
.pill.full {
  background: var(--look-border);
  color: var(--look-ink);
}

.rules-summary {
  margin: 0;
  padding-left: var(--space-6);
}
.rules-summary li + li {
  margin-top: var(--space-2);
}
.her-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--tap-min);
  margin-top: var(--space-2);
  font-weight: var(--font-weight-semibold);
}
.her-link.back {
  margin: 0 0 0 calc(-1 * var(--space-1));
}
/* Two ways on in one row, the first on the left and the second on the right, each its full 44px
   target; at 360px a longer pair wraps to two lines (B4's links, /me's Sign out; F201, F202). */
.link-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0 var(--space-4);
}
.link-row > .her-link,
.link-row > form {
  margin: 0;
}
/* A line of words in the row ("Signed in as {email}") takes the room left and wraps there, even
   inside a long address, so the way on stays beside it. */
.link-row > p {
  flex: 1 1 0;
  min-width: 0;
  overflow-wrap: anywhere;
}
.link-row button {
  white-space: nowrap;
}
.rules-text {
  max-width: 65ch;
  margin-top: var(--space-4);
  line-height: var(--line-height-relaxed);
}
.rules-text > p + p {
  margin-top: var(--space-3);
}
.own-lines {
  white-space: pre-line;
}

/* ---- Her booking steps (B2 to B4) ----------------------------------------------------------------- */

/* The booking steps wear her look: the platform's cards, lines, buttons and notes take its tokens,
   so each pair keeps the contrast the look was checked for. Chalkboard is dark, so there the error
   lines are in her ink, still with their icon and words (never colour alone). */
body[data-look] .card {
  background: var(--look-surface);
  box-shadow: none;
}
body[data-look] .action-bar {
  background: var(--look-ground);
}
body[data-look] .card .action-bar {
  background: var(--look-surface);
}
body[data-look] .secondary,
body[data-look] .hint {
  color: var(--look-muted);
}
body[data-look] .button.primary,
body[data-look] .button.primary:hover,
body[data-look] .button.primary:active {
  background: var(--look-accent);
  border-color: var(--look-accent);
  color: var(--look-on-accent);
}
body[data-look] .button.secondary {
  background: var(--look-surface);
  color: var(--look-ink);
  border-color: var(--look-border-strong);
}
body[data-look] .lead-note {
  background: var(--look-surface);
  border-left: 4px solid var(--look-accent);
}
body[data-look="chalkboard"] .field-error,
body[data-look="chalkboard"] .error-summary a {
  color: var(--look-ink);
}
body[data-look="chalkboard"] .alert,
body[data-look="chalkboard"] .error-summary {
  border-color: var(--look-ink);
}

/* A session row that books is one tap target (her page, B1). */
a.session-row {
  color: inherit;
  text-decoration: none;
}
a.session-row .session-time {
  text-decoration: underline;
  text-underline-offset: 3px;
}
.classmates {
  margin-top: var(--space-1);
}
body[data-look] .field select {
  border-color: var(--look-border-strong);
}
body[data-look] .choice input {
  accent-color: var(--look-accent);
}
.consent-row {
  align-items: flex-start;
  padding: var(--space-2) 0;
}
.consent-row input {
  margin-top: 2px;
}
.consent-text {
  max-width: 65ch;
  line-height: var(--line-height-relaxed);
}
.optional {
  margin-left: var(--space-1);
  font-size: var(--font-size-sm);
  color: var(--look-muted);
}
.consent > .hint,
.consent > .field-error {
  margin-left: 34px;
}
.tick {
  display: block;
  color: var(--look-accent);
}
@media (prefers-reduced-motion: no-preference) {
  .tick,
  .tick + h1 {
    animation: rise 200ms ease-out;
  }
}
@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
}

/* ---- Onboarding and settings (O1 to O5, O8, W8) ------------------------------------------------- */

/* A longer way back (to where she came from, F157) puts the step count on its own line at 360px. */
.step-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0 var(--space-3);
}
.step-count {
  margin-left: auto;
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  white-space: nowrap;
}
.back-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: var(--tap-min);
  font-size: var(--font-size-sm);
}
.lead-note {
  padding: var(--space-3) var(--space-4);
  background: var(--color-info-tint);
  border-radius: var(--radius-sm);
}
.status-line {
  padding: var(--space-2) var(--space-3);
  background: var(--color-success-tint);
  color: var(--color-success);
  border-radius: var(--radius-sm);
  font-weight: var(--font-weight-medium);
}
.error-summary {
  padding: var(--space-4);
  border: 2px solid var(--color-error);
  border-radius: var(--radius-sm);
}
.error-summary h2 {
  font-size: var(--font-size-base);
  margin-bottom: var(--space-2);
}
.error-summary a {
  color: var(--color-error);
}

/* Radios and checkboxes: the whole label row is the 44px target. */
.choices {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}
.choices > legend {
  padding: 0;
  margin-bottom: var(--space-2);
  font-weight: var(--font-weight-medium);
}
/* A fieldset inside a stack keeps the stack's gap above it (F158 item 4). */
.stack > * + .choices {
  margin-top: var(--space-4);
}
/* A fieldset that is a section of its form (B2's "About you", "Your child" and "Your consent", and
   /me's "Your consent"): its legend reads as the section's heading, sized as a section head
   (F158 item 4), in her heading font on her pages, as her h2s are. */
.choices > legend.section-legend {
  margin-bottom: var(--space-3);
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
}
.her-section .section-legend {
  font-family: var(--font-display);
}
.choice {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap-min);
  cursor: pointer;
}
.choice input {
  flex: none;
  width: 22px;
  height: 22px;
  margin: 0;
  accent-color: var(--color-primary);
}
.check .hint {
  margin-left: 34px;
}
.pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-3);
}
.pair + .hint {
  margin-top: var(--space-2);
}

.item {
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.item-title {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-semibold);
}
.item .facts {
  color: var(--color-text-secondary);
}
.item-actions {
  display: flex;
  gap: var(--space-4);
}
.item-actions a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}
.button.destructive {
  width: 100%;
  background: var(--color-surface-elevated);
  color: var(--color-error);
  border: 1px solid var(--color-error);
}

/* O3: a day's hours show once the day is ticked (all of them where :has is not supported). */
.day-hours {
  padding: var(--space-2) var(--space-3) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.day-hours + .day-hours {
  margin-top: var(--space-2);
}
.day-switch {
  font-weight: var(--font-weight-semibold);
}
.day-hours:has(.day-switch input:not(:checked)) .day-detail {
  display: none;
}
.day-detail > * + * {
  margin-top: var(--space-3);
}
/* A day's start times, one to a row, each box with its "Remove" beside it once filled (F257,
   F259). A fieldset is as wide as its content by default, so it is let shrink to its card. */
.times {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}
.times label {
  font-size: var(--font-size-sm);
}
.time-row {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.time-row input {
  flex: 0 1 10rem;
}
.time-row .button {
  flex: none;
}
.copy summary {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  cursor: pointer;
  text-decoration: underline;
  text-underline-offset: 3px;
}
.copy-days {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin-bottom: var(--space-2);
}
.rules-preview,
.preview-text {
  padding: var(--space-4);
  background: var(--color-surface);
  border-radius: var(--radius-sm);
}
.rules-preview h2 {
  font-size: var(--font-size-lg);
}
.preview-text {
  background: var(--color-surface-elevated);
}
.preview-text h3 {
  font-size: var(--font-size-sm);
  color: var(--color-text-secondary);
  margin-bottom: var(--space-2);
}
.preview-text p + p {
  margin-top: var(--space-2);
}

/* O4: named swatches, and her page as parents will see it, in her look. */
.swatch {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: var(--radius-full);
  border: 1px solid var(--color-border-strong);
}
.jump-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}
.look-layout > * + * {
  margin-top: var(--space-6);
}
.look-preview h2 {
  font-size: var(--font-size-lg);
}
.preview {
  --font-display: var(--look-heading), "Figtree", ui-sans-serif, system-ui, sans-serif;
  --radius-md: var(--look-radius);
  background: var(--look-ground);
  color: var(--look-ink);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.preview-body {
  padding: 0 var(--page-gutter) var(--space-6);
}
.preview .note {
  color: var(--look-muted);
}
@media (min-width: 900px) {
  .page:has(.look-layout) {
    max-width: 1040px;
  }
  .look-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-6);
    align-items: start;
  }
  .look-layout > * + * {
    margin-top: 0;
  }
  .look-preview {
    position: sticky;
    top: var(--space-4);
  }
  .jump-link {
    display: none;
  }
}

/* O8 and O5. */
.button-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}
.skip-link-inline {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}
.finish-card {
  margin-bottom: var(--space-4);
  border-left: 4px solid var(--color-info);
}
.finish-card h2 {
  font-size: var(--font-size-lg);
}

/* ---- Her workspace (U4): a header of 56px, tabs at the foot, a left rail from 900px ------------------ */

.workspace {
  --color-accent: var(--look-accent-ws, #1B1B1F);
  --tabs-height: 64px;
}
/* Every in-page anchor of her workspace lands clear of its sticky header, with a little room
   (F262, F267): a Timetable day (#d-), a Register row (#b-), a request (#r-), Notices' undelivered
   group (#failed), O6's entries (#entries), a day's weekly hours (#day-), and focus moved by Tab
   (WCAG 2.4.11). The page scrolls in the viewport, whose padding is the root's. */
html:has(> body.workspace) {
  scroll-padding-top: calc(var(--ws-header-height) + var(--space-4));
}
.sprite {
  position: absolute;
  overflow: hidden;
}
.ws-header {
  position: sticky;
  top: 0;
  z-index: 5;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  height: var(--ws-header-height);
  padding: 0 var(--page-gutter);
  background: var(--color-surface-elevated);
  border-bottom: 1px solid var(--color-border);
}
.ws-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: var(--font-weight-semibold);
}
.avatar {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--tap-min);
  height: var(--tap-min);
  border-radius: var(--radius-full);
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-weight: var(--font-weight-bold);
  text-decoration: none;
}
.avatar[aria-current] {
  box-shadow: 0 0 0 2px var(--color-surface-elevated), 0 0 0 4px var(--color-accent);
}
.ws-tabs {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  display: flex;
  padding: 0 env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background: var(--color-surface-elevated);
  border-top: 1px solid var(--color-border);
}
.ws-tabs a {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--tabs-height);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-secondary);
  text-decoration: none;
}
.ws-tabs a[aria-current] {
  color: var(--color-accent);
  font-weight: var(--font-weight-bold);
  box-shadow: inset 0 3px 0 var(--color-accent);
}
.workspace .page {
  max-width: 720px;
  padding-bottom: var(--space-8);
}
/* The credit line comes after the page, so it is what clears the tabs pinned at the foot. */
.workspace .credit-foot {
  padding-bottom: calc(var(--tabs-height) + var(--space-6) + env(safe-area-inset-bottom));
}
.workspace .page > * + * {
  margin-top: var(--space-4);
}
/* The pinned action stays above the tabs. */
.workspace .action-bar {
  bottom: calc(var(--tabs-height) + env(safe-area-inset-bottom));
}
@media (min-width: 900px) {
  .ws-shell {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    align-items: start;
  }
  .ws-tabs {
    position: sticky;
    top: 56px;
    flex-direction: column;
    gap: var(--space-1);
    height: calc(100vh - 56px);
    padding: var(--space-4) var(--space-3);
    border-top: 0;
    border-right: 1px solid var(--color-border);
  }
  .ws-tabs a {
    flex: none;
    flex-direction: row;
    justify-content: flex-start;
    gap: var(--space-3);
    min-height: 48px;
    padding: 0 var(--space-3);
    font-size: var(--font-size-base);
    border-radius: var(--radius-sm);
  }
  .ws-tabs a[aria-current] {
    background: var(--color-surface);
    box-shadow: inset 3px 0 0 var(--color-accent);
  }
  .workspace .page {
    padding-bottom: var(--space-12);
  }
  /* Centred under the page, beside the rail. */
  .workspace .credit-foot {
    padding: 0 var(--page-gutter) var(--space-6) calc(220px + var(--page-gutter));
  }
  .workspace .page:has(.look-layout) {
    max-width: 1040px;
  }
  .workspace .action-bar {
    bottom: 0;
  }
}

/* Sessions, seats and status in the workspace: ink on white, her accent on open seats only. */
.workspace .session-row {
  background: var(--color-surface-elevated);
  border: 1px solid var(--color-border);
}
.workspace .facts {
  color: var(--color-text-secondary);
}
.workspace .pill.open {
  background: var(--color-accent);
  color: var(--color-on-accent);
}
.workspace .pill.full {
  background: var(--color-border);
  color: var(--color-text-primary);
}
/* A session's status (Open, Closed, Cancelled) is a label beside its time, never read as a
   button (F255): a dot before the word, which carries the meaning, kept on one line with it. */
.status {
  margin-left: var(--space-2);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--color-text-secondary);
  white-space: nowrap;
  cursor: default;
}
.status::before {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 0.5em;
  margin-right: var(--space-1);
  border-radius: var(--radius-full);
  background: currentColor;
  vertical-align: 0.1em;
}
.status.cancelled {
  color: var(--color-error);
}
.ws-kicker {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-semibold);
  color: var(--color-text-secondary);
}
.empty > * + * {
  margin-top: var(--space-3);
}
.menu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  min-height: 56px;
  padding: 0 var(--space-4);
  background: var(--color-surface-elevated);
  border-radius: var(--radius-sm);
  font-weight: var(--font-weight-medium);
  text-decoration: none;
}
.menu-out {
  gap: var(--space-2);
}

/* W6. */
.button.small {
  min-height: var(--tap-min);
  padding: var(--space-2) var(--space-4);
  font-size: var(--font-size-sm);
}
.day-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.day-actions form,
.holiday form {
  margin: 0;
}
.week-nav {
  display: flex;
  justify-content: space-between;
}
.week-nav a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}
.hours-list .facts {
  margin-top: var(--space-1);
}
.result-group h3 {
  font-size: var(--font-size-base);
  margin-bottom: var(--space-2);
}
.result-list,
.family-list {
  margin: 0;
  padding-left: var(--space-6);
}
.result-list li + li,
.family-list li + li {
  margin-top: var(--space-1);
}
.result-reason {
  font-weight: var(--font-weight-semibold);
}
.holiday {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
}
.alert {
  padding: var(--space-3) var(--space-4);
  border: 2px solid var(--color-error);
  border-radius: var(--radius-sm);
}
.alert > * + * {
  margin-top: var(--space-2);
}

/* W1 rosters, W2 Requests, W3 Register, W7 Families, O6 (F3). A status is a word in a pill:
   outlined, so colour is never the only signal. */
.roster {
  margin: var(--space-2) 0 0;
  padding: 0;
  list-style: none;
}
.roster li {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  min-height: 32px;
}
.roster-name {
  font-weight: var(--font-weight-medium);
}
.pill[class*="status-"] {
  background: var(--color-surface-elevated);
  color: var(--color-text-primary);
  border: 1px solid var(--color-border-strong);
}
.pill.status-confirmed,
.pill.status-attended,
.pill.status-notice-sent {
  background: var(--color-success-tint);
  color: var(--color-success);
  border-color: var(--color-success);
}
/* Notices (F4-10): Not delivered in the error colour, its reason in words below it. */
.pill.status-notice-failed {
  background: var(--color-error-tint);
  color: var(--color-error);
  border-color: var(--color-error);
}
.notice-item > * + * {
  margin-top: var(--space-2);
}
.fit.outside {
  font-weight: var(--font-weight-semibold);
}
.register-list > li + li {
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}
.register-row > * + * {
  margin-top: var(--space-2);
}
.reference {
  font-variant-numeric: tabular-nums;
  font-weight: var(--font-weight-medium);
  color: var(--color-text-secondary);
  white-space: nowrap;
}
/* O6: the class and grade, prominent before a save (F3-7 as ruled). */
.prominent {
  padding: var(--space-4);
  border: 2px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}
.prominent h2 {
  font-size: var(--font-size-lg);
}
.recorded {
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
}
.change-summary {
  margin: 0;
}
.change-summary dt {
  font-weight: var(--font-weight-semibold);
}
.change-summary dd {
  margin: 0 0 var(--space-3);
}
.change-summary dd.prominent {
  padding: var(--space-2) var(--space-3);
  font-weight: var(--font-weight-semibold);
}
details.names summary {
  display: flex;
  align-items: center;
  min-height: var(--tap-min);
  cursor: pointer;
}

/* ---- Small screens and motion ------------------------------------------------------------------------ */

@media (max-width: 379px) {
  :root {
    --page-gutter: 12px;
  }
}

@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
