/*
 * Vesper UI layer: base reset + reusable components (ADR-0005).
 * Consumes tokens.css only. Add a new pattern HERE (and to /styleguide), never
 * inline in a view. Every value is a var(--token) or a color-mix() over one.
 */

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

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

/* The hidden attribute must win over a component's display (e.g. .tarot-card). */
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

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

h1, h2, h3 {
  font-family: var(--font-serif);
  font-weight: var(--weight-semibold);
  color: var(--color-heading);
  line-height: var(--leading-snug);
  margin: 0;
}

/* Visible keyboard focus for every interactive element. */
:where(a, button, input, textarea, select, [tabindex]):focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* -------------------------------------------------------------------- Layout */
.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--space-6);
}
.container--narrow { max-width: var(--container-narrow); }

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

/* --------------------------------------------------------------- Typography */
.display {
  font-family: var(--font-serif);
  font-weight: var(--weight-semibold);
  font-size: var(--text-display);
  line-height: var(--leading-tight);
  color: var(--color-heading);
  letter-spacing: -0.01em;
  text-wrap: balance;
  margin: 0;
}
.heading { font-size: var(--text-xl); }
.heading--lg { font-size: var(--text-2xl); }

.eyebrow {
  text-transform: uppercase;
  letter-spacing: var(--tracking-eyebrow);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-eyebrow);
  margin: 0;
}

.lede {
  font-size: var(--text-md);
  line-height: var(--leading-normal);
  color: var(--color-text-muted);
  margin: 0;
}
.muted { color: var(--color-text-muted); }
.micro { font-size: var(--text-sm); color: var(--color-text-muted); }

/* ----------------------------------------------------------------- Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-sans);
  font-weight: var(--weight-semibold);
  font-size: var(--text-md);
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  border: 0;
  border-radius: var(--radius-pill);
  padding: var(--space-4) var(--space-8);
  background: var(--color-accent);
  color: var(--color-accent-ink);
  transition: transform var(--dur-fast) var(--ease-out),
              background var(--dur-fast) var(--ease-out);
}
.btn:hover { background: color-mix(in srgb, var(--color-accent) 86%, var(--tint-light)); transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn--ghost {
  background: transparent;
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
}
.btn--ghost:hover { background: color-mix(in srgb, var(--star) 8%, transparent); border-color: var(--color-text-muted); }

.btn--sm { font-size: var(--text-sm); padding: var(--space-3) var(--space-5); }
.btn--lg { font-size: var(--text-lg); padding: var(--space-4) var(--space-10); }

/* Full-width within its container: keeps a long label (notably the longer es-MX
   CTAs, e.g. "Guardar hora de nacimiento") from spilling a narrow form card at
   360px. Pair with single-column forms. */
.btn--block { width: 100%; }

/* ----------------------------------------------------------- Surfaces / cards */
.surface {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-xl);
  padding: var(--space-8);
}

.card {
  background: var(--color-surface-raised);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: var(--shadow-lg);
}

.rule { height: 1px; border: 0; background: var(--color-border); margin-block: var(--space-12); }

/* The recurring star glyph (wordmark, accents). Decorative. Mark aria-hidden. */
.star {
  display: inline-block;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: var(--glow-amber);
}

/* ------------------------------------------------------------------- Fields */
.field { display: grid; gap: var(--space-3); text-align: left; }

.field__label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--color-eyebrow);
}
.field__hint { font-size: var(--text-sm); color: var(--color-text-muted); }

.input, .textarea {
  font: inherit;
  font-size: var(--text-base);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid var(--color-border-strong);
  background: var(--color-surface-raised);
  color: var(--color-text);
  color-scheme: dark;
}
.textarea { min-height: 8rem; resize: vertical; line-height: var(--leading-normal); }
.input::placeholder, .textarea::placeholder { color: color-mix(in srgb, var(--mist) 70%, transparent); }

/* Select: the native control with our own chevron, given room to breathe from
   the edge (feedback: the platform arrow crowded the border). The chevron is a
   token-coloured caret (same border trick as the disclosure marker, so no raw
   hex), drawn by the wrapper; the select reserves inline-end space for it. */
.select { position: relative; display: grid; }

.select > select.input {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: var(--space-10);
}

.select::after {
  content: "";
  position: absolute;
  inset-inline-end: var(--space-4);
  top: 50%;
  width: 0.5rem;
  height: 0.5rem;
  border-right: 2px solid var(--color-text-muted);
  border-bottom: 2px solid var(--color-text-muted);
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}

/* ----------------------------------------------------------- Numbered steps */

/* The Draw -> Read the sky -> Reflect ritual pattern. */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-12); }
.steps__item { max-width: 30rem; }

.steps__num {
  font-family: var(--font-serif);
  font-size: var(--text-sm);
  letter-spacing: 0.1em;
  color: var(--color-accent);
}
.steps__title { font-size: var(--text-xl); margin: var(--space-2) 0; }
.steps__body { margin: 0; color: var(--color-text-muted); }

/* --------------------------------------------------------------------- Chip */
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-pill);
  border: 1px solid var(--color-border-strong);
  color: var(--color-text-muted);
}

/* ===================================================== Product components ===
   Patterns the MVP screens need (issues 01-09). Compose these; don't re-create
   them inline. Showcased in /styleguide. */

/* App bar: the authenticated shell header (issue 01). */
.appbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--color-border);
}

.appbar__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-serif);
  font-size: var(--text-lg);
  color: var(--color-heading);
}

/* The Vesper mark, sized to the wordmark it sits beside (scales with the brand
   font). Decorative -- the wordmark names the brand -- so it carries empty alt. */
.appbar__logo { width: 1.5em; height: 1.5em; }

/* Wrap, so the longer es-MX chrome ("Diario / Carta / Ajustes" + "Cerrar
   sesión") drops the sign-out pill to its own line whole at 360px rather than
   overflowing or breaking the label mid-word. */
.appbar__nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-5); }
.appbar__nav .btn { white-space: nowrap; }

.appbar__nav a {
  padding-block: var(--space-2);
  color: var(--color-text-muted);
  text-decoration: none;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}
.appbar__nav a:hover { color: var(--color-text); }

/* Burger: the mobile menu trigger (issue 02). Hidden by default -- it is both the
   no-JS state (the controller reveals it) and the wide-screen state; the media
   query below shows it only on narrow, enhanced headers. */
.appbar__burger {
  display: none;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  background: transparent;
  color: var(--color-text);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

/* Three stacked bars: the element is the middle bar, its pseudo-elements the
   outer two. currentColor so it inherits the button's colour (no raw hex). */
.appbar__burger-bars,
.appbar__burger-bars::before,
.appbar__burger-bars::after {
  content: "";
  display: block;
  width: 1.15rem;
  height: 2px;
  border-radius: 1px;
  background: currentColor;
}
.appbar__burger-bars { position: relative; }
.appbar__burger-bars::before { position: absolute; top: -6px; }
.appbar__burger-bars::after { position: absolute; top: 6px; }

/* Drawer: the mobile nav in a native <dialog>, anchored full-height to the inline
   end. showModal() supplies the focus trap, Esc-to-close and inert background;
   this only styles it. No open/close animation -- a calm, instant panel that is
   trivially reduced-motion-safe (a subtle slide can be added later once it can be
   visually QA'd with @starting-style). */
.drawer {
  position: fixed;
  inset-block: 0;
  inset-inline-end: 0;
  height: 100dvh;
  width: min(20rem, 82vw);
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  border-inline-start: 1px solid var(--color-border);
  background: var(--color-surface);
  color: var(--color-text);
  box-shadow: var(--shadow-lg);
}
.drawer::backdrop { background: color-mix(in srgb, var(--night-900) 68%, transparent); }

.drawer__panel {
  display: grid;
  gap: var(--space-2);
  align-content: start;
  height: 100%;
  padding: var(--space-6);
}

.drawer__close {
  justify-self: end;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  background: transparent;
  color: var(--color-text-muted);
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.drawer__close:hover { color: var(--color-text); }
.drawer__close-glyph { font-size: var(--text-2xl); line-height: 1; }

.drawer__nav { display: grid; gap: var(--space-1); }

.drawer__nav a {
  padding: var(--space-3) var(--space-2);
  color: var(--color-text);
  text-decoration: none;
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}
.drawer__nav a:hover { color: var(--color-heading); }

/* Sign-out is a button_to, so the <form> is the grid item -- align and space that,
   not the inner .btn (which would be inert). */
.drawer__nav form { justify-self: start; margin-top: var(--space-4); }

/* Below the breakpoint, and only once JS has enhanced the header: the inline nav
   gives way to the burger + drawer. Above it (and with JS off) the inline nav
   stays, so every destination is always reachable. */
@media (max-width: 40rem) {
  .appbar--enhanced .appbar__nav { display: none; }
  .appbar--enhanced .appbar__burger { display: inline-flex; }
}

/* While the drawer is open, hold the page still behind it. */
.is-scroll-locked { overflow: hidden; }

/* Notice: an inline message, one of info (default), error, or success (issues 01, 03). */
.notice {
  border: 1px solid var(--color-border-strong);
  border-left-width: 3px;
  border-radius: var(--radius);
  padding: var(--space-4) var(--space-5);
  background: var(--color-surface);
  color: var(--color-text);
}
.notice--error { border-left-color: var(--color-danger); }
.notice--success { border-left-color: var(--color-accent); }

/* Flash region: wraps the global flash notice(s) at the top of a screen and
   gives them room to breathe (issue 01). */
.flash { padding-block: var(--space-4); }

/* Auth shell: the calm, narrow panel layout shared by the sign-in and
   confirm-sign-in screens (issue 01). Pair with .container--narrow. */
.auth { padding-block: var(--space-16) var(--space-20); }

/* Empty state (issue 04, the empty "today"). Roomy, unhurried spacing so the
   invitation reads calm rather than cluttered (feedback). */
.empty {
  display: grid;
  justify-items: center;
  gap: var(--space-5);
  padding: var(--space-16) var(--space-6);
  text-align: center;
}

.empty__glyph {
  width: 14px;
  height: 14px;
  margin-bottom: var(--space-2);
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: var(--glow-amber);
}

.empty__title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-xl);
  color: var(--color-heading);
}
.empty__body { margin: 0; max-width: 28rem; color: var(--color-text-muted); line-height: var(--leading-normal); }

/* A clear beat before the call to action. */
.empty .btn { margin-top: var(--space-3); }

/* Badge: orientation / pass / status label (issues 02, 09). */
.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

.badge--accent {
  color: var(--color-accent);
  border-color: color-mix(in srgb, var(--color-accent) 50%, transparent);
}

.badge--reversed {
  color: var(--ember);
  border-color: color-mix(in srgb, var(--ember) 50%, transparent);
}

/* Tarot card: the Draw (issue 02). Face-up (art slot, name, meaning) or
   face-down (--facedown). */
.tarot-card {
  display: grid;
  gap: var(--space-4);
  width: 100%;
  max-width: 20rem;
  padding: var(--space-6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: linear-gradient(165deg, var(--night-700), var(--night-900));
  box-shadow: var(--shadow-lg);
}

.tarot-card__art {
  display: grid;
  place-items: center;
  aspect-ratio: 3 / 5;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  background:
    radial-gradient(circle at 50% 38%, color-mix(in srgb, var(--color-accent) 70%, transparent), transparent 60%),
    var(--night-800);
}

/* Real card art fills the slot; the night base matches any cover-crop letterbox
   and keeps the engraving dissolving into the dark card. */
.tarot-card__art--photo {
  padding: 0;
  overflow: hidden;
  background: var(--night-900);
}

.tarot-card__art--photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

/* Face-down card back: the art slot as a calm panel cradling the seal. */
.tarot-card__art--back {
  background:
    radial-gradient(circle at 50% 42%, color-mix(in srgb, var(--color-accent) 16%, transparent), transparent 58%),
    var(--night-800);
}

/* The orientation badge, pinned to the top of the card on its own row (feedback):
   a grid item stretches by default, so hold it to its content at the start edge. */
.tarot-card__badge { justify-self: start; }

.tarot-card__name {
  margin: 0;
  font-family: var(--font-serif);
  font-size: var(--text-xl);
  color: var(--color-heading);
}
.tarot-card__meaning { margin: 0; color: var(--color-text-muted); }

/* Face-down card: the art slot becomes the calm panel (--back) cradling the
   seal, so it keeps the same 3:5 card shape as the face-up side instead of a
   squat box. */
.tarot-card--facedown {
  text-align: center;
}

.tarot-card__seal {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, var(--color-accent), color-mix(in srgb, var(--color-accent) 40%, var(--tint-dark)));
  box-shadow: var(--glow-amber);
}

/* Flip card: the two faces are stacked in one grid cell, so the card keeps a
   constant size; .is-flipped turns it with a calm 3D rotation (motion zeroed
   under prefers-reduced-motion). The /today draw flips in place via a Turbo
   Stream instead of reloading the page. */
.card-flip {
  display: grid;
  width: 100%;
  max-width: 20rem;
  perspective: 1400px;
}

.card-flip > [data-card-flip-target] {
  grid-area: 1 / 1;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  transition: transform var(--dur-slow) var(--ease-out);
}
.card-flip > [data-card-flip-target="back"] { transform: rotateY(180deg); }
.card-flip.is-flipped > [data-card-flip-target="front"] { transform: rotateY(-180deg); }
.card-flip.is-flipped > [data-card-flip-target="back"] { transform: rotateY(0deg); }
.card-flip .tarot-card { max-width: none; }
.card-flip__back { display: grid; }

/* Mood: a 1..5 scale, a radio group (issue 03). Visually-hidden inputs. The
   endpoint anchors name where the scale runs from and to, and the readout (in the
   hint) echoes the selected marker's meaning, so the bare circles are no longer
   unlabelled (feedback). */
.mood { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.mood__scale { display: inline-flex; gap: var(--space-2); }
.mood__anchor { font-size: var(--text-sm); color: var(--color-text-muted); }
.mood__readout { color: var(--color-accent); font-weight: var(--weight-semibold); }

.mood__readout:not(:empty)::after {
  content: " · ";
  color: var(--color-text-muted);
  font-weight: var(--weight-normal);
}

.mood input {
  position: absolute;
  width: 0;
  height: 0;
  opacity: 0;
}

.mood label {
  width: 24px;
  height: 24px;
  border: 1px solid var(--color-border-strong);
  border-radius: 50%;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out), transform var(--dur-fast) var(--ease-out);
}
.mood label:hover { transform: scale(1.08); }

.mood input:checked + label {
  background: var(--color-accent);
  border-color: var(--color-accent);
}

.mood input:focus-visible + label {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* Transit: an aspect line plus a plain-language explainer (issue 06). */
.transit { padding: var(--space-4) 0; border-bottom: 1px solid var(--color-border); }
.transit__line { font-size: var(--text-md); color: var(--color-text); }
.transit__line b { font-weight: var(--weight-semibold); color: var(--color-heading); }
.transit__aspect { color: var(--color-accent); }
.transit__why { margin: var(--space-2) 0 0; font-size: var(--text-sm); color: var(--color-text-muted); }

/* Placement: a natal chart row of planet, sign, (house) (issue 05). */
.placement {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
}
.placement__planet { font-family: var(--font-serif); font-size: var(--text-md); color: var(--color-heading); }
.placement__sign { color: var(--color-text); }
.placement__house { font-size: var(--text-sm); color: var(--color-text-muted); }

/* Unlock: a locked-feature prompt, e.g. add birth time (issue 05, ADR-0002). */
.unlock {
  display: grid;
  justify-items: start;
  gap: var(--space-3);
  padding: var(--space-5);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius);
  background: var(--color-surface);
}
.unlock__title { font-family: var(--font-serif); font-size: var(--text-md); color: var(--color-heading); }
.unlock__body { margin: 0; font-size: var(--text-sm); color: var(--color-text-muted); }

/* Streak: consecutive-day count (issue 07). A quiet marker of continuity, not a
   score: a serif count in the heading ink (not the amber accent, which would read
   as a hero metric beside the date) at large-body size, with a muted label. */
.streak { display: inline-flex; align-items: baseline; gap: var(--space-2); }
.streak__count { font-family: var(--font-serif); font-size: var(--text-lg); color: var(--color-heading); }
.streak__label { font-size: var(--text-sm); color: var(--color-text-muted); }

/* Switch: a settings toggle (issue 08). The vertical padding gives a
   comfortable one-handed hit area around the 24px track. */
.switch {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding-block: var(--space-2);
  cursor: pointer;
}

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

.switch__track {
  position: relative;
  flex: none;
  width: 42px;
  height: 24px;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-pill);
  background: var(--color-surface-raised);
  transition: background var(--dur-fast) var(--ease-out);
}

/* Unsupported / disabled: the toggle reads as unavailable, not merely off. */
.switch:has(input:disabled) { cursor: not-allowed; color: var(--color-text-muted); }
.switch input:disabled + .switch__track { opacity: 0.5; }

.switch__track::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--color-text-muted);
  transition: transform var(--dur-fast) var(--ease-out), background var(--dur-fast) var(--ease-out);
}

.switch input:checked + .switch__track {
  border-color: var(--color-accent);
  background: color-mix(in srgb, var(--color-accent) 35%, transparent);
}

.switch input:checked + .switch__track::after {
  transform: translateX(18px);
  background: var(--color-accent);
}

.switch input:focus-visible + .switch__track {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

/* Entry list: the Journal stream as an ordered list (issue 04). Wrap in a
   .surface; the list itself just strips the default list chrome. */
.entry-list { list-style: none; margin: 0; padding: 0; }
.entry-list > li:last-child .entry-summary { border-bottom: 0; }

/* Entry summary: a Journal list row (issue 04). */
.entry-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--color-border);
  color: inherit;
  text-decoration: none;
}
.entry-summary:hover .entry-summary__date { color: var(--color-heading); }
.entry-summary__date { font-family: var(--font-serif); font-size: var(--text-md); color: var(--color-text); }

.entry-summary__glance {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-align: right;
}

/* Below the narrowest target, stack the date over its glance so neither wraps
   mid-phrase. */
@media (max-width: 28rem) {
  .entry-summary { flex-direction: column; align-items: flex-start; gap: var(--space-1); }
  .entry-summary__glance { text-align: left; }
}

/* A small dot marking that a Mood was recorded for the day. The exact level is
   on the Entry itself; here it is a quiet presence cue, labelled for assistive
   tech. */
.entry-summary__mood {
  flex: none;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--color-accent);
  box-shadow: var(--glow-amber);
}

/* Skeleton: a loading placeholder for async screens (issues 02, 03, 05, 06).
   Block by default so callers only set a width, not display. */
.skeleton {
  display: block;
  border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--star) 9%, transparent);
  animation: skeleton-pulse 1.4s var(--ease-out) infinite;
}
.skeleton--line { height: 0.9em; }
.skeleton--block { height: 8rem; }

@keyframes skeleton-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.45; }
}

@media (prefers-reduced-motion: reduce) {
  .skeleton { animation: none; }
}

/* Visually-hidden text: present for screen readers, removed from the visual
   layout. Pair with an aria-hidden decorative element (e.g. the Mood dot). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --------------------------------------------------------------- Disclosure */

/* A calm, optional disclosure (native <details>/<summary>): a muted summary that
   expands to reveal more, for content that is available but never demanded -- the
   optional retrospective Pass (issue 09). Collapsed by default; the summary keeps
   a comfortable hit area in both states, and the only motion is the chevron,
   which rests under prefers-reduced-motion (--dur-fast is zeroed there). Pair the
   .disclosure__hint with the [open] rule to show the invitation only while closed. */
.disclosure { border-top: 1px solid var(--color-border); padding-top: var(--space-8); }

.disclosure__summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  padding-block: var(--space-2);
  color: var(--color-text-muted);
}
.disclosure__summary::-webkit-details-marker { display: none; }

.disclosure__summary::before {
  content: "";
  flex: none;
  width: 0.5rem;
  height: 0.5rem;
  margin-top: 0.45em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-fast) var(--ease-out);
}
.disclosure[open] .disclosure__summary::before { transform: rotate(45deg); }
.disclosure__summary:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.disclosure__label { display: grid; gap: var(--space-2); }
.disclosure__hint { max-width: 34rem; }
.disclosure[open] .disclosure__hint { display: none; }
.disclosure__body { margin-top: var(--space-8); }

/* Layout helpers. */
.cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); }
.cluster--between { justify-content: space-between; }
.passes { display: grid; gap: var(--space-6); }

@media (min-width: 720px) {
  .passes { grid-template-columns: 1fr 1fr; }
}
